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('is android : ' + Roo.isAndroid);
7198 alert('is ios : ' + Roo.isIOS);
7201 alert('Is Android');
7202 return Roo.get(document.documentElement);
7206 alert('not android');
7209 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7213 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7214 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7215 * @param {String} selector The simple selector to test
7216 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7217 search as a number or element (defaults to 10 || document.body)
7218 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7220 up : function(simpleSelector, maxDepth){
7221 return this.findParentNode(simpleSelector, maxDepth, true);
7227 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7228 * @param {String} selector The simple selector to test
7229 * @return {Boolean} True if this element matches the selector, else false
7231 is : function(simpleSelector){
7232 return Roo.DomQuery.is(this.dom, simpleSelector);
7236 * Perform animation on this element.
7237 * @param {Object} args The YUI animation control args
7238 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7239 * @param {Function} onComplete (optional) Function to call when animation completes
7240 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7241 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7242 * @return {Roo.Element} this
7244 animate : function(args, duration, onComplete, easing, animType){
7245 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7250 * @private Internal animation call
7252 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7253 animType = animType || 'run';
7255 var anim = Roo.lib.Anim[animType](
7257 (opt.duration || defaultDur) || .35,
7258 (opt.easing || defaultEase) || 'easeOut',
7260 Roo.callback(cb, this);
7261 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7269 // private legacy anim prep
7270 preanim : function(a, i){
7271 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7275 * Removes worthless text nodes
7276 * @param {Boolean} forceReclean (optional) By default the element
7277 * keeps track if it has been cleaned already so
7278 * you can call this over and over. However, if you update the element and
7279 * need to force a reclean, you can pass true.
7281 clean : function(forceReclean){
7282 if(this.isCleaned && forceReclean !== true){
7286 var d = this.dom, n = d.firstChild, ni = -1;
7288 var nx = n.nextSibling;
7289 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7296 this.isCleaned = true;
7301 calcOffsetsTo : function(el){
7304 var restorePos = false;
7305 if(el.getStyle('position') == 'static'){
7306 el.position('relative');
7311 while(op && op != d && op.tagName != 'HTML'){
7314 op = op.offsetParent;
7317 el.position('static');
7323 * Scrolls this element into view within the passed container.
7324 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7325 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7326 * @return {Roo.Element} this
7328 scrollIntoView : function(container, hscroll){
7329 var c = Roo.getDom(container) || document.body;
7332 var o = this.calcOffsetsTo(c),
7335 b = t+el.offsetHeight,
7336 r = l+el.offsetWidth;
7338 var ch = c.clientHeight;
7339 var ct = parseInt(c.scrollTop, 10);
7340 var cl = parseInt(c.scrollLeft, 10);
7342 var cr = cl + c.clientWidth;
7350 if(hscroll !== false){
7354 c.scrollLeft = r-c.clientWidth;
7361 scrollChildIntoView : function(child, hscroll){
7362 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7366 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7367 * the new height may not be available immediately.
7368 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7369 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7370 * @param {Function} onComplete (optional) Function to call when animation completes
7371 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7372 * @return {Roo.Element} this
7374 autoHeight : function(animate, duration, onComplete, easing){
7375 var oldHeight = this.getHeight();
7377 this.setHeight(1); // force clipping
7378 setTimeout(function(){
7379 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7381 this.setHeight(height);
7383 if(typeof onComplete == "function"){
7387 this.setHeight(oldHeight); // restore original height
7388 this.setHeight(height, animate, duration, function(){
7390 if(typeof onComplete == "function") { onComplete(); }
7391 }.createDelegate(this), easing);
7393 }.createDelegate(this), 0);
7398 * Returns true if this element is an ancestor of the passed element
7399 * @param {HTMLElement/String} el The element to check
7400 * @return {Boolean} True if this element is an ancestor of el, else false
7402 contains : function(el){
7403 if(!el){return false;}
7404 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7408 * Checks whether the element is currently visible using both visibility and display properties.
7409 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7410 * @return {Boolean} True if the element is currently visible, else false
7412 isVisible : function(deep) {
7413 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7414 if(deep !== true || !vis){
7417 var p = this.dom.parentNode;
7418 while(p && p.tagName.toLowerCase() != "body"){
7419 if(!Roo.fly(p, '_isVisible').isVisible()){
7428 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7429 * @param {String} selector The CSS selector
7430 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7431 * @return {CompositeElement/CompositeElementLite} The composite element
7433 select : function(selector, unique){
7434 return El.select(selector, unique, this.dom);
7438 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7439 * @param {String} selector The CSS selector
7440 * @return {Array} An array of the matched nodes
7442 query : function(selector, unique){
7443 return Roo.DomQuery.select(selector, this.dom);
7447 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7448 * @param {String} selector The CSS selector
7449 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7450 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7452 child : function(selector, returnDom){
7453 var n = Roo.DomQuery.selectNode(selector, this.dom);
7454 return returnDom ? n : Roo.get(n);
7458 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7459 * @param {String} selector The CSS selector
7460 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7461 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7463 down : function(selector, returnDom){
7464 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7465 return returnDom ? n : Roo.get(n);
7469 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7470 * @param {String} group The group the DD object is member of
7471 * @param {Object} config The DD config object
7472 * @param {Object} overrides An object containing methods to override/implement on the DD object
7473 * @return {Roo.dd.DD} The DD object
7475 initDD : function(group, config, overrides){
7476 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7477 return Roo.apply(dd, overrides);
7481 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7482 * @param {String} group The group the DDProxy object is member of
7483 * @param {Object} config The DDProxy config object
7484 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7485 * @return {Roo.dd.DDProxy} The DDProxy object
7487 initDDProxy : function(group, config, overrides){
7488 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7489 return Roo.apply(dd, overrides);
7493 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7494 * @param {String} group The group the DDTarget object is member of
7495 * @param {Object} config The DDTarget config object
7496 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7497 * @return {Roo.dd.DDTarget} The DDTarget object
7499 initDDTarget : function(group, config, overrides){
7500 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7501 return Roo.apply(dd, overrides);
7505 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7506 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7507 * @param {Boolean} visible Whether the element is visible
7508 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7509 * @return {Roo.Element} this
7511 setVisible : function(visible, animate){
7513 if(this.visibilityMode == El.DISPLAY){
7514 this.setDisplayed(visible);
7517 this.dom.style.visibility = visible ? "visible" : "hidden";
7520 // closure for composites
7522 var visMode = this.visibilityMode;
7524 this.setOpacity(.01);
7525 this.setVisible(true);
7527 this.anim({opacity: { to: (visible?1:0) }},
7528 this.preanim(arguments, 1),
7529 null, .35, 'easeIn', function(){
7531 if(visMode == El.DISPLAY){
7532 dom.style.display = "none";
7534 dom.style.visibility = "hidden";
7536 Roo.get(dom).setOpacity(1);
7544 * Returns true if display is not "none"
7547 isDisplayed : function() {
7548 return this.getStyle("display") != "none";
7552 * Toggles the element's visibility or display, depending on visibility mode.
7553 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7554 * @return {Roo.Element} this
7556 toggle : function(animate){
7557 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7562 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7563 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7564 * @return {Roo.Element} this
7566 setDisplayed : function(value) {
7567 if(typeof value == "boolean"){
7568 value = value ? this.originalDisplay : "none";
7570 this.setStyle("display", value);
7575 * Tries to focus the element. Any exceptions are caught and ignored.
7576 * @return {Roo.Element} this
7578 focus : function() {
7586 * Tries to blur the element. Any exceptions are caught and ignored.
7587 * @return {Roo.Element} this
7597 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7598 * @param {String/Array} className The CSS class to add, or an array of classes
7599 * @return {Roo.Element} this
7601 addClass : function(className){
7602 if(className instanceof Array){
7603 for(var i = 0, len = className.length; i < len; i++) {
7604 this.addClass(className[i]);
7607 if(className && !this.hasClass(className)){
7608 this.dom.className = this.dom.className + " " + className;
7615 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7616 * @param {String/Array} className The CSS class to add, or an array of classes
7617 * @return {Roo.Element} this
7619 radioClass : function(className){
7620 var siblings = this.dom.parentNode.childNodes;
7621 for(var i = 0; i < siblings.length; i++) {
7622 var s = siblings[i];
7623 if(s.nodeType == 1){
7624 Roo.get(s).removeClass(className);
7627 this.addClass(className);
7632 * Removes one or more CSS classes from the element.
7633 * @param {String/Array} className The CSS class to remove, or an array of classes
7634 * @return {Roo.Element} this
7636 removeClass : function(className){
7637 if(!className || !this.dom.className){
7640 if(className instanceof Array){
7641 for(var i = 0, len = className.length; i < len; i++) {
7642 this.removeClass(className[i]);
7645 if(this.hasClass(className)){
7646 var re = this.classReCache[className];
7648 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7649 this.classReCache[className] = re;
7651 this.dom.className =
7652 this.dom.className.replace(re, " ");
7662 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7663 * @param {String} className The CSS class to toggle
7664 * @return {Roo.Element} this
7666 toggleClass : function(className){
7667 if(this.hasClass(className)){
7668 this.removeClass(className);
7670 this.addClass(className);
7676 * Checks if the specified CSS class exists on this element's DOM node.
7677 * @param {String} className The CSS class to check for
7678 * @return {Boolean} True if the class exists, else false
7680 hasClass : function(className){
7681 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7685 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7686 * @param {String} oldClassName The CSS class to replace
7687 * @param {String} newClassName The replacement CSS class
7688 * @return {Roo.Element} this
7690 replaceClass : function(oldClassName, newClassName){
7691 this.removeClass(oldClassName);
7692 this.addClass(newClassName);
7697 * Returns an object with properties matching the styles requested.
7698 * For example, el.getStyles('color', 'font-size', 'width') might return
7699 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7700 * @param {String} style1 A style name
7701 * @param {String} style2 A style name
7702 * @param {String} etc.
7703 * @return {Object} The style object
7705 getStyles : function(){
7706 var a = arguments, len = a.length, r = {};
7707 for(var i = 0; i < len; i++){
7708 r[a[i]] = this.getStyle(a[i]);
7714 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7715 * @param {String} property The style property whose value is returned.
7716 * @return {String} The current value of the style property for this element.
7718 getStyle : function(){
7719 return view && view.getComputedStyle ?
7721 var el = this.dom, v, cs, camel;
7722 if(prop == 'float'){
7725 if(el.style && (v = el.style[prop])){
7728 if(cs = view.getComputedStyle(el, "")){
7729 if(!(camel = propCache[prop])){
7730 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7737 var el = this.dom, v, cs, camel;
7738 if(prop == 'opacity'){
7739 if(typeof el.style.filter == 'string'){
7740 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7742 var fv = parseFloat(m[1]);
7744 return fv ? fv / 100 : 0;
7749 }else if(prop == 'float'){
7750 prop = "styleFloat";
7752 if(!(camel = propCache[prop])){
7753 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7755 if(v = el.style[camel]){
7758 if(cs = el.currentStyle){
7766 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7767 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7768 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7769 * @return {Roo.Element} this
7771 setStyle : function(prop, value){
7772 if(typeof prop == "string"){
7774 if (prop == 'float') {
7775 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7780 if(!(camel = propCache[prop])){
7781 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7784 if(camel == 'opacity') {
7785 this.setOpacity(value);
7787 this.dom.style[camel] = value;
7790 for(var style in prop){
7791 if(typeof prop[style] != "function"){
7792 this.setStyle(style, prop[style]);
7800 * More flexible version of {@link #setStyle} for setting style properties.
7801 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7802 * a function which returns such a specification.
7803 * @return {Roo.Element} this
7805 applyStyles : function(style){
7806 Roo.DomHelper.applyStyles(this.dom, style);
7811 * 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).
7812 * @return {Number} The X position of the element
7815 return D.getX(this.dom);
7819 * 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).
7820 * @return {Number} The Y position of the element
7823 return D.getY(this.dom);
7827 * 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).
7828 * @return {Array} The XY position of the element
7831 return D.getXY(this.dom);
7835 * 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).
7836 * @param {Number} The X position of the element
7837 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7838 * @return {Roo.Element} this
7840 setX : function(x, animate){
7842 D.setX(this.dom, x);
7844 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7850 * 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).
7851 * @param {Number} The Y position of the element
7852 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7853 * @return {Roo.Element} this
7855 setY : function(y, animate){
7857 D.setY(this.dom, y);
7859 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7865 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7866 * @param {String} left The left CSS property value
7867 * @return {Roo.Element} this
7869 setLeft : function(left){
7870 this.setStyle("left", this.addUnits(left));
7875 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7876 * @param {String} top The top CSS property value
7877 * @return {Roo.Element} this
7879 setTop : function(top){
7880 this.setStyle("top", this.addUnits(top));
7885 * Sets the element's CSS right style.
7886 * @param {String} right The right CSS property value
7887 * @return {Roo.Element} this
7889 setRight : function(right){
7890 this.setStyle("right", this.addUnits(right));
7895 * Sets the element's CSS bottom style.
7896 * @param {String} bottom The bottom CSS property value
7897 * @return {Roo.Element} this
7899 setBottom : function(bottom){
7900 this.setStyle("bottom", this.addUnits(bottom));
7905 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7906 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7907 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7908 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7909 * @return {Roo.Element} this
7911 setXY : function(pos, animate){
7913 D.setXY(this.dom, pos);
7915 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7921 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7922 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7923 * @param {Number} x X value for new position (coordinates are page-based)
7924 * @param {Number} y Y value for new position (coordinates are page-based)
7925 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7926 * @return {Roo.Element} this
7928 setLocation : function(x, y, animate){
7929 this.setXY([x, y], this.preanim(arguments, 2));
7934 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7935 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7936 * @param {Number} x X value for new position (coordinates are page-based)
7937 * @param {Number} y Y value for new position (coordinates are page-based)
7938 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7939 * @return {Roo.Element} this
7941 moveTo : function(x, y, animate){
7942 this.setXY([x, y], this.preanim(arguments, 2));
7947 * Returns the region of the given element.
7948 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7949 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7951 getRegion : function(){
7952 return D.getRegion(this.dom);
7956 * Returns the offset height of the element
7957 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7958 * @return {Number} The element's height
7960 getHeight : function(contentHeight){
7961 var h = this.dom.offsetHeight || 0;
7962 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7966 * Returns the offset width of the element
7967 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7968 * @return {Number} The element's width
7970 getWidth : function(contentWidth){
7971 var w = this.dom.offsetWidth || 0;
7972 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7976 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7977 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7978 * if a height has not been set using CSS.
7981 getComputedHeight : function(){
7982 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7984 h = parseInt(this.getStyle('height'), 10) || 0;
7985 if(!this.isBorderBox()){
7986 h += this.getFrameWidth('tb');
7993 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7994 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7995 * if a width has not been set using CSS.
7998 getComputedWidth : function(){
7999 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8001 w = parseInt(this.getStyle('width'), 10) || 0;
8002 if(!this.isBorderBox()){
8003 w += this.getFrameWidth('lr');
8010 * Returns the size of the element.
8011 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8012 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8014 getSize : function(contentSize){
8015 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8019 * Returns the width and height of the viewport.
8020 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8022 getViewSize : function(){
8023 var d = this.dom, doc = document, aw = 0, ah = 0;
8024 if(d == doc || d == doc.body){
8025 return {width : D.getViewWidth(), height: D.getViewHeight()};
8028 width : d.clientWidth,
8029 height: d.clientHeight
8035 * Returns the value of the "value" attribute
8036 * @param {Boolean} asNumber true to parse the value as a number
8037 * @return {String/Number}
8039 getValue : function(asNumber){
8040 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8044 adjustWidth : function(width){
8045 if(typeof width == "number"){
8046 if(this.autoBoxAdjust && !this.isBorderBox()){
8047 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8057 adjustHeight : function(height){
8058 if(typeof height == "number"){
8059 if(this.autoBoxAdjust && !this.isBorderBox()){
8060 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8070 * Set the width of the element
8071 * @param {Number} width The new width
8072 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8073 * @return {Roo.Element} this
8075 setWidth : function(width, animate){
8076 width = this.adjustWidth(width);
8078 this.dom.style.width = this.addUnits(width);
8080 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8086 * Set the height of the element
8087 * @param {Number} height The new height
8088 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8089 * @return {Roo.Element} this
8091 setHeight : function(height, animate){
8092 height = this.adjustHeight(height);
8094 this.dom.style.height = this.addUnits(height);
8096 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8102 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8103 * @param {Number} width The new width
8104 * @param {Number} height The new height
8105 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8106 * @return {Roo.Element} this
8108 setSize : function(width, height, animate){
8109 if(typeof width == "object"){ // in case of object from getSize()
8110 height = width.height; width = width.width;
8112 width = this.adjustWidth(width); height = this.adjustHeight(height);
8114 this.dom.style.width = this.addUnits(width);
8115 this.dom.style.height = this.addUnits(height);
8117 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8123 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8124 * @param {Number} x X value for new position (coordinates are page-based)
8125 * @param {Number} y Y value for new position (coordinates are page-based)
8126 * @param {Number} width The new width
8127 * @param {Number} height The new height
8128 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8129 * @return {Roo.Element} this
8131 setBounds : function(x, y, width, height, animate){
8133 this.setSize(width, height);
8134 this.setLocation(x, y);
8136 width = this.adjustWidth(width); height = this.adjustHeight(height);
8137 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8138 this.preanim(arguments, 4), 'motion');
8144 * 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.
8145 * @param {Roo.lib.Region} region The region to fill
8146 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8147 * @return {Roo.Element} this
8149 setRegion : function(region, animate){
8150 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8155 * Appends an event handler
8157 * @param {String} eventName The type of event to append
8158 * @param {Function} fn The method the event invokes
8159 * @param {Object} scope (optional) The scope (this object) of the fn
8160 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8162 addListener : function(eventName, fn, scope, options){
8164 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8169 * Removes an event handler from this element
8170 * @param {String} eventName the type of event to remove
8171 * @param {Function} fn the method the event invokes
8172 * @return {Roo.Element} this
8174 removeListener : function(eventName, fn){
8175 Roo.EventManager.removeListener(this.dom, eventName, fn);
8180 * Removes all previous added listeners from this element
8181 * @return {Roo.Element} this
8183 removeAllListeners : function(){
8184 E.purgeElement(this.dom);
8188 relayEvent : function(eventName, observable){
8189 this.on(eventName, function(e){
8190 observable.fireEvent(eventName, e);
8195 * Set the opacity of the element
8196 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8197 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8198 * @return {Roo.Element} this
8200 setOpacity : function(opacity, animate){
8202 var s = this.dom.style;
8205 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8206 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8208 s.opacity = opacity;
8211 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8217 * Gets the left X coordinate
8218 * @param {Boolean} local True to get the local css position instead of page coordinate
8221 getLeft : function(local){
8225 return parseInt(this.getStyle("left"), 10) || 0;
8230 * Gets the right X coordinate of the element (element X position + element width)
8231 * @param {Boolean} local True to get the local css position instead of page coordinate
8234 getRight : function(local){
8236 return this.getX() + this.getWidth();
8238 return (this.getLeft(true) + this.getWidth()) || 0;
8243 * Gets the top Y coordinate
8244 * @param {Boolean} local True to get the local css position instead of page coordinate
8247 getTop : function(local) {
8251 return parseInt(this.getStyle("top"), 10) || 0;
8256 * Gets the bottom Y coordinate of the element (element Y position + element height)
8257 * @param {Boolean} local True to get the local css position instead of page coordinate
8260 getBottom : function(local){
8262 return this.getY() + this.getHeight();
8264 return (this.getTop(true) + this.getHeight()) || 0;
8269 * Initializes positioning on this element. If a desired position is not passed, it will make the
8270 * the element positioned relative IF it is not already positioned.
8271 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8272 * @param {Number} zIndex (optional) The zIndex to apply
8273 * @param {Number} x (optional) Set the page X position
8274 * @param {Number} y (optional) Set the page Y position
8276 position : function(pos, zIndex, x, y){
8278 if(this.getStyle('position') == 'static'){
8279 this.setStyle('position', 'relative');
8282 this.setStyle("position", pos);
8285 this.setStyle("z-index", zIndex);
8287 if(x !== undefined && y !== undefined){
8289 }else if(x !== undefined){
8291 }else if(y !== undefined){
8297 * Clear positioning back to the default when the document was loaded
8298 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8299 * @return {Roo.Element} this
8301 clearPositioning : function(value){
8309 "position" : "static"
8315 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8316 * snapshot before performing an update and then restoring the element.
8319 getPositioning : function(){
8320 var l = this.getStyle("left");
8321 var t = this.getStyle("top");
8323 "position" : this.getStyle("position"),
8325 "right" : l ? "" : this.getStyle("right"),
8327 "bottom" : t ? "" : this.getStyle("bottom"),
8328 "z-index" : this.getStyle("z-index")
8333 * Gets the width of the border(s) for the specified side(s)
8334 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8335 * passing lr would get the border (l)eft width + the border (r)ight width.
8336 * @return {Number} The width of the sides passed added together
8338 getBorderWidth : function(side){
8339 return this.addStyles(side, El.borders);
8343 * Gets the width of the padding(s) for the specified side(s)
8344 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8345 * passing lr would get the padding (l)eft + the padding (r)ight.
8346 * @return {Number} The padding of the sides passed added together
8348 getPadding : function(side){
8349 return this.addStyles(side, El.paddings);
8353 * Set positioning with an object returned by getPositioning().
8354 * @param {Object} posCfg
8355 * @return {Roo.Element} this
8357 setPositioning : function(pc){
8358 this.applyStyles(pc);
8359 if(pc.right == "auto"){
8360 this.dom.style.right = "";
8362 if(pc.bottom == "auto"){
8363 this.dom.style.bottom = "";
8369 fixDisplay : function(){
8370 if(this.getStyle("display") == "none"){
8371 this.setStyle("visibility", "hidden");
8372 this.setStyle("display", this.originalDisplay); // first try reverting to default
8373 if(this.getStyle("display") == "none"){ // if that fails, default to block
8374 this.setStyle("display", "block");
8380 * Quick set left and top adding default units
8381 * @param {String} left The left CSS property value
8382 * @param {String} top The top CSS property value
8383 * @return {Roo.Element} this
8385 setLeftTop : function(left, top){
8386 this.dom.style.left = this.addUnits(left);
8387 this.dom.style.top = this.addUnits(top);
8392 * Move this element relative to its current position.
8393 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8394 * @param {Number} distance How far to move the element in pixels
8395 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8396 * @return {Roo.Element} this
8398 move : function(direction, distance, animate){
8399 var xy = this.getXY();
8400 direction = direction.toLowerCase();
8404 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8408 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8413 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8418 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8425 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8426 * @return {Roo.Element} this
8429 if(!this.isClipped){
8430 this.isClipped = true;
8431 this.originalClip = {
8432 "o": this.getStyle("overflow"),
8433 "x": this.getStyle("overflow-x"),
8434 "y": this.getStyle("overflow-y")
8436 this.setStyle("overflow", "hidden");
8437 this.setStyle("overflow-x", "hidden");
8438 this.setStyle("overflow-y", "hidden");
8444 * Return clipping (overflow) to original clipping before clip() was called
8445 * @return {Roo.Element} this
8447 unclip : function(){
8449 this.isClipped = false;
8450 var o = this.originalClip;
8451 if(o.o){this.setStyle("overflow", o.o);}
8452 if(o.x){this.setStyle("overflow-x", o.x);}
8453 if(o.y){this.setStyle("overflow-y", o.y);}
8460 * Gets the x,y coordinates specified by the anchor position on the element.
8461 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8462 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8463 * {width: (target width), height: (target height)} (defaults to the element's current size)
8464 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8465 * @return {Array} [x, y] An array containing the element's x and y coordinates
8467 getAnchorXY : function(anchor, local, s){
8468 //Passing a different size is useful for pre-calculating anchors,
8469 //especially for anchored animations that change the el size.
8471 var w, h, vp = false;
8474 if(d == document.body || d == document){
8476 w = D.getViewWidth(); h = D.getViewHeight();
8478 w = this.getWidth(); h = this.getHeight();
8481 w = s.width; h = s.height;
8483 var x = 0, y = 0, r = Math.round;
8484 switch((anchor || "tl").toLowerCase()){
8526 var sc = this.getScroll();
8527 return [x + sc.left, y + sc.top];
8529 //Add the element's offset xy
8530 var o = this.getXY();
8531 return [x+o[0], y+o[1]];
8535 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8536 * supported position values.
8537 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8538 * @param {String} position The position to align to.
8539 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8540 * @return {Array} [x, y]
8542 getAlignToXY : function(el, p, o){
8546 throw "Element.alignTo with an element that doesn't exist";
8548 var c = false; //constrain to viewport
8549 var p1 = "", p2 = "";
8556 }else if(p.indexOf("-") == -1){
8559 p = p.toLowerCase();
8560 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8562 throw "Element.alignTo with an invalid alignment " + p;
8564 p1 = m[1]; p2 = m[2]; c = !!m[3];
8566 //Subtract the aligned el's internal xy from the target's offset xy
8567 //plus custom offset to get the aligned el's new offset xy
8568 var a1 = this.getAnchorXY(p1, true);
8569 var a2 = el.getAnchorXY(p2, false);
8570 var x = a2[0] - a1[0] + o[0];
8571 var y = a2[1] - a1[1] + o[1];
8573 //constrain the aligned el to viewport if necessary
8574 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8575 // 5px of margin for ie
8576 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8578 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8579 //perpendicular to the vp border, allow the aligned el to slide on that border,
8580 //otherwise swap the aligned el to the opposite border of the target.
8581 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8582 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8583 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8584 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8587 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8588 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8590 if((x+w) > dw + scrollX){
8591 x = swapX ? r.left-w : dw+scrollX-w;
8594 x = swapX ? r.right : scrollX;
8596 if((y+h) > dh + scrollY){
8597 y = swapY ? r.top-h : dh+scrollY-h;
8600 y = swapY ? r.bottom : scrollY;
8607 getConstrainToXY : function(){
8608 var os = {top:0, left:0, bottom:0, right: 0};
8610 return function(el, local, offsets, proposedXY){
8612 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8614 var vw, vh, vx = 0, vy = 0;
8615 if(el.dom == document.body || el.dom == document){
8616 vw = Roo.lib.Dom.getViewWidth();
8617 vh = Roo.lib.Dom.getViewHeight();
8619 vw = el.dom.clientWidth;
8620 vh = el.dom.clientHeight;
8622 var vxy = el.getXY();
8628 var s = el.getScroll();
8630 vx += offsets.left + s.left;
8631 vy += offsets.top + s.top;
8633 vw -= offsets.right;
8634 vh -= offsets.bottom;
8639 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8640 var x = xy[0], y = xy[1];
8641 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8643 // only move it if it needs it
8646 // first validate right/bottom
8655 // then make sure top/left isn't negative
8664 return moved ? [x, y] : false;
8669 adjustForConstraints : function(xy, parent, offsets){
8670 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8674 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8675 * document it aligns it to the viewport.
8676 * The position parameter is optional, and can be specified in any one of the following formats:
8678 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8679 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8680 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8681 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8682 * <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
8683 * element's anchor point, and the second value is used as the target's anchor point.</li>
8685 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8686 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8687 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8688 * that specified in order to enforce the viewport constraints.
8689 * Following are all of the supported anchor positions:
8692 ----- -----------------------------
8693 tl The top left corner (default)
8694 t The center of the top edge
8695 tr The top right corner
8696 l The center of the left edge
8697 c In the center of the element
8698 r The center of the right edge
8699 bl The bottom left corner
8700 b The center of the bottom edge
8701 br The bottom right corner
8705 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8706 el.alignTo("other-el");
8708 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8709 el.alignTo("other-el", "tr?");
8711 // align the bottom right corner of el with the center left edge of other-el
8712 el.alignTo("other-el", "br-l?");
8714 // align the center of el with the bottom left corner of other-el and
8715 // adjust the x position by -6 pixels (and the y position by 0)
8716 el.alignTo("other-el", "c-bl", [-6, 0]);
8718 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8719 * @param {String} position The position to align to.
8720 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8721 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8722 * @return {Roo.Element} this
8724 alignTo : function(element, position, offsets, animate){
8725 var xy = this.getAlignToXY(element, position, offsets);
8726 this.setXY(xy, this.preanim(arguments, 3));
8731 * Anchors an element to another element and realigns it when the window is resized.
8732 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8733 * @param {String} position The position to align to.
8734 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8735 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8736 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8737 * is a number, it is used as the buffer delay (defaults to 50ms).
8738 * @param {Function} callback The function to call after the animation finishes
8739 * @return {Roo.Element} this
8741 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8742 var action = function(){
8743 this.alignTo(el, alignment, offsets, animate);
8744 Roo.callback(callback, this);
8746 Roo.EventManager.onWindowResize(action, this);
8747 var tm = typeof monitorScroll;
8748 if(tm != 'undefined'){
8749 Roo.EventManager.on(window, 'scroll', action, this,
8750 {buffer: tm == 'number' ? monitorScroll : 50});
8752 action.call(this); // align immediately
8756 * Clears any opacity settings from this element. Required in some cases for IE.
8757 * @return {Roo.Element} this
8759 clearOpacity : function(){
8760 if (window.ActiveXObject) {
8761 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8762 this.dom.style.filter = "";
8765 this.dom.style.opacity = "";
8766 this.dom.style["-moz-opacity"] = "";
8767 this.dom.style["-khtml-opacity"] = "";
8773 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8774 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8775 * @return {Roo.Element} this
8777 hide : function(animate){
8778 this.setVisible(false, this.preanim(arguments, 0));
8783 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8784 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8785 * @return {Roo.Element} this
8787 show : function(animate){
8788 this.setVisible(true, this.preanim(arguments, 0));
8793 * @private Test if size has a unit, otherwise appends the default
8795 addUnits : function(size){
8796 return Roo.Element.addUnits(size, this.defaultUnit);
8800 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8801 * @return {Roo.Element} this
8803 beginMeasure : function(){
8805 if(el.offsetWidth || el.offsetHeight){
8806 return this; // offsets work already
8809 var p = this.dom, b = document.body; // start with this element
8810 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8811 var pe = Roo.get(p);
8812 if(pe.getStyle('display') == 'none'){
8813 changed.push({el: p, visibility: pe.getStyle("visibility")});
8814 p.style.visibility = "hidden";
8815 p.style.display = "block";
8819 this._measureChanged = changed;
8825 * Restores displays to before beginMeasure was called
8826 * @return {Roo.Element} this
8828 endMeasure : function(){
8829 var changed = this._measureChanged;
8831 for(var i = 0, len = changed.length; i < len; i++) {
8833 r.el.style.visibility = r.visibility;
8834 r.el.style.display = "none";
8836 this._measureChanged = null;
8842 * Update the innerHTML of this element, optionally searching for and processing scripts
8843 * @param {String} html The new HTML
8844 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8845 * @param {Function} callback For async script loading you can be noticed when the update completes
8846 * @return {Roo.Element} this
8848 update : function(html, loadScripts, callback){
8849 if(typeof html == "undefined"){
8852 if(loadScripts !== true){
8853 this.dom.innerHTML = html;
8854 if(typeof callback == "function"){
8862 html += '<span id="' + id + '"></span>';
8864 E.onAvailable(id, function(){
8865 var hd = document.getElementsByTagName("head")[0];
8866 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8867 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8868 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8871 while(match = re.exec(html)){
8872 var attrs = match[1];
8873 var srcMatch = attrs ? attrs.match(srcRe) : false;
8874 if(srcMatch && srcMatch[2]){
8875 var s = document.createElement("script");
8876 s.src = srcMatch[2];
8877 var typeMatch = attrs.match(typeRe);
8878 if(typeMatch && typeMatch[2]){
8879 s.type = typeMatch[2];
8882 }else if(match[2] && match[2].length > 0){
8883 if(window.execScript) {
8884 window.execScript(match[2]);
8892 window.eval(match[2]);
8896 var el = document.getElementById(id);
8897 if(el){el.parentNode.removeChild(el);}
8898 if(typeof callback == "function"){
8902 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8907 * Direct access to the UpdateManager update() method (takes the same parameters).
8908 * @param {String/Function} url The url for this request or a function to call to get the url
8909 * @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}
8910 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8911 * @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.
8912 * @return {Roo.Element} this
8915 var um = this.getUpdateManager();
8916 um.update.apply(um, arguments);
8921 * Gets this element's UpdateManager
8922 * @return {Roo.UpdateManager} The UpdateManager
8924 getUpdateManager : function(){
8925 if(!this.updateManager){
8926 this.updateManager = new Roo.UpdateManager(this);
8928 return this.updateManager;
8932 * Disables text selection for this element (normalized across browsers)
8933 * @return {Roo.Element} this
8935 unselectable : function(){
8936 this.dom.unselectable = "on";
8937 this.swallowEvent("selectstart", true);
8938 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8939 this.addClass("x-unselectable");
8944 * Calculates the x, y to center this element on the screen
8945 * @return {Array} The x, y values [x, y]
8947 getCenterXY : function(){
8948 return this.getAlignToXY(document, 'c-c');
8952 * Centers the Element in either the viewport, or another Element.
8953 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8955 center : function(centerIn){
8956 this.alignTo(centerIn || document, 'c-c');
8961 * Tests various css rules/browsers to determine if this element uses a border box
8964 isBorderBox : function(){
8965 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8969 * Return a box {x, y, width, height} that can be used to set another elements
8970 * size/location to match this element.
8971 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8972 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8973 * @return {Object} box An object in the format {x, y, width, height}
8975 getBox : function(contentBox, local){
8980 var left = parseInt(this.getStyle("left"), 10) || 0;
8981 var top = parseInt(this.getStyle("top"), 10) || 0;
8984 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8986 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8988 var l = this.getBorderWidth("l")+this.getPadding("l");
8989 var r = this.getBorderWidth("r")+this.getPadding("r");
8990 var t = this.getBorderWidth("t")+this.getPadding("t");
8991 var b = this.getBorderWidth("b")+this.getPadding("b");
8992 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)};
8994 bx.right = bx.x + bx.width;
8995 bx.bottom = bx.y + bx.height;
9000 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9001 for more information about the sides.
9002 * @param {String} sides
9005 getFrameWidth : function(sides, onlyContentBox){
9006 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9010 * 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.
9011 * @param {Object} box The box to fill {x, y, width, height}
9012 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9013 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9014 * @return {Roo.Element} this
9016 setBox : function(box, adjust, animate){
9017 var w = box.width, h = box.height;
9018 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9019 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9020 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9022 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9027 * Forces the browser to repaint this element
9028 * @return {Roo.Element} this
9030 repaint : function(){
9032 this.addClass("x-repaint");
9033 setTimeout(function(){
9034 Roo.get(dom).removeClass("x-repaint");
9040 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9041 * then it returns the calculated width of the sides (see getPadding)
9042 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9043 * @return {Object/Number}
9045 getMargins : function(side){
9048 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9049 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9050 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9051 right: parseInt(this.getStyle("margin-right"), 10) || 0
9054 return this.addStyles(side, El.margins);
9059 addStyles : function(sides, styles){
9061 for(var i = 0, len = sides.length; i < len; i++){
9062 v = this.getStyle(styles[sides.charAt(i)]);
9064 w = parseInt(v, 10);
9072 * Creates a proxy element of this element
9073 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9074 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9075 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9076 * @return {Roo.Element} The new proxy element
9078 createProxy : function(config, renderTo, matchBox){
9080 renderTo = Roo.getDom(renderTo);
9082 renderTo = document.body;
9084 config = typeof config == "object" ?
9085 config : {tag : "div", cls: config};
9086 var proxy = Roo.DomHelper.append(renderTo, config, true);
9088 proxy.setBox(this.getBox());
9094 * Puts a mask over this element to disable user interaction. Requires core.css.
9095 * This method can only be applied to elements which accept child nodes.
9096 * @param {String} msg (optional) A message to display in the mask
9097 * @param {String} msgCls (optional) A css class to apply to the msg element
9098 * @return {Element} The mask element
9100 mask : function(msg, msgCls)
9102 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9103 this.setStyle("position", "relative");
9106 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9108 this.addClass("x-masked");
9109 this._mask.setDisplayed(true);
9114 while (dom && dom.style) {
9115 if (!isNaN(parseInt(dom.style.zIndex))) {
9116 z = Math.max(z, parseInt(dom.style.zIndex));
9118 dom = dom.parentNode;
9120 // if we are masking the body - then it hides everything..
9121 if (this.dom == document.body) {
9123 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9124 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9127 if(typeof msg == 'string'){
9129 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9131 var mm = this._maskMsg;
9132 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9133 if (mm.dom.firstChild) { // weird IE issue?
9134 mm.dom.firstChild.innerHTML = msg;
9136 mm.setDisplayed(true);
9138 mm.setStyle('z-index', z + 102);
9140 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9141 this._mask.setHeight(this.getHeight());
9143 this._mask.setStyle('z-index', z + 100);
9149 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9150 * it is cached for reuse.
9152 unmask : function(removeEl){
9154 if(removeEl === true){
9155 this._mask.remove();
9158 this._maskMsg.remove();
9159 delete this._maskMsg;
9162 this._mask.setDisplayed(false);
9164 this._maskMsg.setDisplayed(false);
9168 this.removeClass("x-masked");
9172 * Returns true if this element is masked
9175 isMasked : function(){
9176 return this._mask && this._mask.isVisible();
9180 * Creates an iframe shim for this element to keep selects and other windowed objects from
9182 * @return {Roo.Element} The new shim element
9184 createShim : function(){
9185 var el = document.createElement('iframe');
9186 el.frameBorder = 'no';
9187 el.className = 'roo-shim';
9188 if(Roo.isIE && Roo.isSecure){
9189 el.src = Roo.SSL_SECURE_URL;
9191 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9192 shim.autoBoxAdjust = false;
9197 * Removes this element from the DOM and deletes it from the cache
9199 remove : function(){
9200 if(this.dom.parentNode){
9201 this.dom.parentNode.removeChild(this.dom);
9203 delete El.cache[this.dom.id];
9207 * Sets up event handlers to add and remove a css class when the mouse is over this element
9208 * @param {String} className
9209 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9210 * mouseout events for children elements
9211 * @return {Roo.Element} this
9213 addClassOnOver : function(className, preventFlicker){
9214 this.on("mouseover", function(){
9215 Roo.fly(this, '_internal').addClass(className);
9217 var removeFn = function(e){
9218 if(preventFlicker !== true || !e.within(this, true)){
9219 Roo.fly(this, '_internal').removeClass(className);
9222 this.on("mouseout", removeFn, this.dom);
9227 * Sets up event handlers to add and remove a css class when this element has the focus
9228 * @param {String} className
9229 * @return {Roo.Element} this
9231 addClassOnFocus : function(className){
9232 this.on("focus", function(){
9233 Roo.fly(this, '_internal').addClass(className);
9235 this.on("blur", function(){
9236 Roo.fly(this, '_internal').removeClass(className);
9241 * 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)
9242 * @param {String} className
9243 * @return {Roo.Element} this
9245 addClassOnClick : function(className){
9247 this.on("mousedown", function(){
9248 Roo.fly(dom, '_internal').addClass(className);
9249 var d = Roo.get(document);
9250 var fn = function(){
9251 Roo.fly(dom, '_internal').removeClass(className);
9252 d.removeListener("mouseup", fn);
9254 d.on("mouseup", fn);
9260 * Stops the specified event from bubbling and optionally prevents the default action
9261 * @param {String} eventName
9262 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9263 * @return {Roo.Element} this
9265 swallowEvent : function(eventName, preventDefault){
9266 var fn = function(e){
9267 e.stopPropagation();
9272 if(eventName instanceof Array){
9273 for(var i = 0, len = eventName.length; i < len; i++){
9274 this.on(eventName[i], fn);
9278 this.on(eventName, fn);
9285 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9288 * Sizes this element to its parent element's dimensions performing
9289 * neccessary box adjustments.
9290 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9291 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9292 * @return {Roo.Element} this
9294 fitToParent : function(monitorResize, targetParent) {
9295 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9296 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9297 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9300 var p = Roo.get(targetParent || this.dom.parentNode);
9301 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9302 if (monitorResize === true) {
9303 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9304 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9310 * Gets the next sibling, skipping text nodes
9311 * @return {HTMLElement} The next sibling or null
9313 getNextSibling : function(){
9314 var n = this.dom.nextSibling;
9315 while(n && n.nodeType != 1){
9322 * Gets the previous sibling, skipping text nodes
9323 * @return {HTMLElement} The previous sibling or null
9325 getPrevSibling : function(){
9326 var n = this.dom.previousSibling;
9327 while(n && n.nodeType != 1){
9328 n = n.previousSibling;
9335 * Appends the passed element(s) to this element
9336 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9337 * @return {Roo.Element} this
9339 appendChild: function(el){
9346 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9347 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9348 * automatically generated with the specified attributes.
9349 * @param {HTMLElement} insertBefore (optional) a child element of this element
9350 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9351 * @return {Roo.Element} The new child element
9353 createChild: function(config, insertBefore, returnDom){
9354 config = config || {tag:'div'};
9356 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9358 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9362 * Appends this element to the passed element
9363 * @param {String/HTMLElement/Element} el The new parent element
9364 * @return {Roo.Element} this
9366 appendTo: function(el){
9367 el = Roo.getDom(el);
9368 el.appendChild(this.dom);
9373 * Inserts this element before the passed element in the DOM
9374 * @param {String/HTMLElement/Element} el The element to insert before
9375 * @return {Roo.Element} this
9377 insertBefore: function(el){
9378 el = Roo.getDom(el);
9379 el.parentNode.insertBefore(this.dom, el);
9384 * Inserts this element after the passed element in the DOM
9385 * @param {String/HTMLElement/Element} el The element to insert after
9386 * @return {Roo.Element} this
9388 insertAfter: function(el){
9389 el = Roo.getDom(el);
9390 el.parentNode.insertBefore(this.dom, el.nextSibling);
9395 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9396 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9397 * @return {Roo.Element} The new child
9399 insertFirst: function(el, returnDom){
9401 if(typeof el == 'object' && !el.nodeType){ // dh config
9402 return this.createChild(el, this.dom.firstChild, returnDom);
9404 el = Roo.getDom(el);
9405 this.dom.insertBefore(el, this.dom.firstChild);
9406 return !returnDom ? Roo.get(el) : el;
9411 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9412 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9413 * @param {String} where (optional) 'before' or 'after' defaults to before
9414 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9415 * @return {Roo.Element} the inserted Element
9417 insertSibling: function(el, where, returnDom){
9418 where = where ? where.toLowerCase() : 'before';
9420 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9422 if(typeof el == 'object' && !el.nodeType){ // dh config
9423 if(where == 'after' && !this.dom.nextSibling){
9424 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9426 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9430 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9431 where == 'before' ? this.dom : this.dom.nextSibling);
9440 * Creates and wraps this element with another element
9441 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9442 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9443 * @return {HTMLElement/Element} The newly created wrapper element
9445 wrap: function(config, returnDom){
9447 config = {tag: "div"};
9449 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9450 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9455 * Replaces the passed element with this element
9456 * @param {String/HTMLElement/Element} el The element to replace
9457 * @return {Roo.Element} this
9459 replace: function(el){
9461 this.insertBefore(el);
9467 * Inserts an html fragment into this element
9468 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9469 * @param {String} html The HTML fragment
9470 * @param {Boolean} returnEl True to return an Roo.Element
9471 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9473 insertHtml : function(where, html, returnEl){
9474 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9475 return returnEl ? Roo.get(el) : el;
9479 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9480 * @param {Object} o The object with the attributes
9481 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9482 * @return {Roo.Element} this
9484 set : function(o, useSet){
9486 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9488 if(attr == "style" || typeof o[attr] == "function") { continue; }
9490 el.className = o["cls"];
9493 el.setAttribute(attr, o[attr]);
9500 Roo.DomHelper.applyStyles(el, o.style);
9506 * Convenience method for constructing a KeyMap
9507 * @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:
9508 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9509 * @param {Function} fn The function to call
9510 * @param {Object} scope (optional) The scope of the function
9511 * @return {Roo.KeyMap} The KeyMap created
9513 addKeyListener : function(key, fn, scope){
9515 if(typeof key != "object" || key instanceof Array){
9531 return new Roo.KeyMap(this, config);
9535 * Creates a KeyMap for this element
9536 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9537 * @return {Roo.KeyMap} The KeyMap created
9539 addKeyMap : function(config){
9540 return new Roo.KeyMap(this, config);
9544 * Returns true if this element is scrollable.
9547 isScrollable : function(){
9549 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9553 * 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().
9554 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9555 * @param {Number} value The new scroll value
9556 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9557 * @return {Element} this
9560 scrollTo : function(side, value, animate){
9561 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9563 this.dom[prop] = value;
9565 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9566 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9572 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9573 * within this element's scrollable range.
9574 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9575 * @param {Number} distance How far to scroll the element in pixels
9576 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9577 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9578 * was scrolled as far as it could go.
9580 scroll : function(direction, distance, animate){
9581 if(!this.isScrollable()){
9585 var l = el.scrollLeft, t = el.scrollTop;
9586 var w = el.scrollWidth, h = el.scrollHeight;
9587 var cw = el.clientWidth, ch = el.clientHeight;
9588 direction = direction.toLowerCase();
9589 var scrolled = false;
9590 var a = this.preanim(arguments, 2);
9595 var v = Math.min(l + distance, w-cw);
9596 this.scrollTo("left", v, a);
9603 var v = Math.max(l - distance, 0);
9604 this.scrollTo("left", v, a);
9612 var v = Math.max(t - distance, 0);
9613 this.scrollTo("top", v, a);
9621 var v = Math.min(t + distance, h-ch);
9622 this.scrollTo("top", v, a);
9631 * Translates the passed page coordinates into left/top css values for this element
9632 * @param {Number/Array} x The page x or an array containing [x, y]
9633 * @param {Number} y The page y
9634 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9636 translatePoints : function(x, y){
9637 if(typeof x == 'object' || x instanceof Array){
9640 var p = this.getStyle('position');
9641 var o = this.getXY();
9643 var l = parseInt(this.getStyle('left'), 10);
9644 var t = parseInt(this.getStyle('top'), 10);
9647 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9650 t = (p == "relative") ? 0 : this.dom.offsetTop;
9653 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9657 * Returns the current scroll position of the element.
9658 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9660 getScroll : function(){
9661 var d = this.dom, doc = document;
9662 if(d == doc || d == doc.body){
9663 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9664 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9665 return {left: l, top: t};
9667 return {left: d.scrollLeft, top: d.scrollTop};
9672 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9673 * are convert to standard 6 digit hex color.
9674 * @param {String} attr The css attribute
9675 * @param {String} defaultValue The default value to use when a valid color isn't found
9676 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9679 getColor : function(attr, defaultValue, prefix){
9680 var v = this.getStyle(attr);
9681 if(!v || v == "transparent" || v == "inherit") {
9682 return defaultValue;
9684 var color = typeof prefix == "undefined" ? "#" : prefix;
9685 if(v.substr(0, 4) == "rgb("){
9686 var rvs = v.slice(4, v.length -1).split(",");
9687 for(var i = 0; i < 3; i++){
9688 var h = parseInt(rvs[i]).toString(16);
9695 if(v.substr(0, 1) == "#"){
9697 for(var i = 1; i < 4; i++){
9698 var c = v.charAt(i);
9701 }else if(v.length == 7){
9702 color += v.substr(1);
9706 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9710 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9711 * gradient background, rounded corners and a 4-way shadow.
9712 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9713 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9714 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9715 * @return {Roo.Element} this
9717 boxWrap : function(cls){
9718 cls = cls || 'x-box';
9719 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9720 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9725 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9726 * @param {String} namespace The namespace in which to look for the attribute
9727 * @param {String} name The attribute name
9728 * @return {String} The attribute value
9730 getAttributeNS : Roo.isIE ? function(ns, name){
9732 var type = typeof d[ns+":"+name];
9733 if(type != 'undefined' && type != 'unknown'){
9734 return d[ns+":"+name];
9737 } : function(ns, name){
9739 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9744 * Sets or Returns the value the dom attribute value
9745 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9746 * @param {String} value (optional) The value to set the attribute to
9747 * @return {String} The attribute value
9749 attr : function(name){
9750 if (arguments.length > 1) {
9751 this.dom.setAttribute(name, arguments[1]);
9752 return arguments[1];
9754 if (typeof(name) == 'object') {
9755 for(var i in name) {
9756 this.attr(i, name[i]);
9762 if (!this.dom.hasAttribute(name)) {
9765 return this.dom.getAttribute(name);
9772 var ep = El.prototype;
9775 * Appends an event handler (Shorthand for addListener)
9776 * @param {String} eventName The type of event to append
9777 * @param {Function} fn The method the event invokes
9778 * @param {Object} scope (optional) The scope (this object) of the fn
9779 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9782 ep.on = ep.addListener;
9784 ep.mon = ep.addListener;
9787 * Removes an event handler from this element (shorthand for removeListener)
9788 * @param {String} eventName the type of event to remove
9789 * @param {Function} fn the method the event invokes
9790 * @return {Roo.Element} this
9793 ep.un = ep.removeListener;
9796 * true to automatically adjust width and height settings for box-model issues (default to true)
9798 ep.autoBoxAdjust = true;
9801 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9804 El.addUnits = function(v, defaultUnit){
9805 if(v === "" || v == "auto"){
9808 if(v === undefined){
9811 if(typeof v == "number" || !El.unitPattern.test(v)){
9812 return v + (defaultUnit || 'px');
9817 // special markup used throughout Roo when box wrapping elements
9818 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>';
9820 * Visibility mode constant - Use visibility to hide element
9826 * Visibility mode constant - Use display to hide element
9832 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9833 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9834 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9846 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9847 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9848 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9849 * @return {Element} The Element object
9852 El.get = function(el){
9854 if(!el){ return null; }
9855 if(typeof el == "string"){ // element id
9856 if(!(elm = document.getElementById(el))){
9859 if(ex = El.cache[el]){
9862 ex = El.cache[el] = new El(elm);
9865 }else if(el.tagName){ // dom element
9869 if(ex = El.cache[id]){
9872 ex = El.cache[id] = new El(el);
9875 }else if(el instanceof El){
9877 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9878 // catch case where it hasn't been appended
9879 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9882 }else if(el.isComposite){
9884 }else if(el instanceof Array){
9885 return El.select(el);
9886 }else if(el == document){
9887 // create a bogus element object representing the document object
9889 var f = function(){};
9890 f.prototype = El.prototype;
9892 docEl.dom = document;
9900 El.uncache = function(el){
9901 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9903 delete El.cache[a[i].id || a[i]];
9909 // Garbage collection - uncache elements/purge listeners on orphaned elements
9910 // so we don't hold a reference and cause the browser to retain them
9911 El.garbageCollect = function(){
9912 if(!Roo.enableGarbageCollector){
9913 clearInterval(El.collectorThread);
9916 for(var eid in El.cache){
9917 var el = El.cache[eid], d = el.dom;
9918 // -------------------------------------------------------
9919 // Determining what is garbage:
9920 // -------------------------------------------------------
9922 // dom node is null, definitely garbage
9923 // -------------------------------------------------------
9925 // no parentNode == direct orphan, definitely garbage
9926 // -------------------------------------------------------
9927 // !d.offsetParent && !document.getElementById(eid)
9928 // display none elements have no offsetParent so we will
9929 // also try to look it up by it's id. However, check
9930 // offsetParent first so we don't do unneeded lookups.
9931 // This enables collection of elements that are not orphans
9932 // directly, but somewhere up the line they have an orphan
9934 // -------------------------------------------------------
9935 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9936 delete El.cache[eid];
9937 if(d && Roo.enableListenerCollection){
9943 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9947 El.Flyweight = function(dom){
9950 El.Flyweight.prototype = El.prototype;
9952 El._flyweights = {};
9954 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9955 * the dom node can be overwritten by other code.
9956 * @param {String/HTMLElement} el The dom node or id
9957 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9958 * prevent conflicts (e.g. internally Roo uses "_internal")
9960 * @return {Element} The shared Element object
9962 El.fly = function(el, named){
9963 named = named || '_global';
9964 el = Roo.getDom(el);
9968 if(!El._flyweights[named]){
9969 El._flyweights[named] = new El.Flyweight();
9971 El._flyweights[named].dom = el;
9972 return El._flyweights[named];
9976 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9977 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9978 * Shorthand of {@link Roo.Element#get}
9979 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9980 * @return {Element} The Element object
9986 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9987 * the dom node can be overwritten by other code.
9988 * Shorthand of {@link Roo.Element#fly}
9989 * @param {String/HTMLElement} el The dom node or id
9990 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9991 * prevent conflicts (e.g. internally Roo uses "_internal")
9993 * @return {Element} The shared Element object
9999 // speedy lookup for elements never to box adjust
10000 var noBoxAdjust = Roo.isStrict ? {
10003 input:1, select:1, textarea:1
10005 if(Roo.isIE || Roo.isGecko){
10006 noBoxAdjust['button'] = 1;
10010 Roo.EventManager.on(window, 'unload', function(){
10012 delete El._flyweights;
10020 Roo.Element.selectorFunction = Roo.DomQuery.select;
10023 Roo.Element.select = function(selector, unique, root){
10025 if(typeof selector == "string"){
10026 els = Roo.Element.selectorFunction(selector, root);
10027 }else if(selector.length !== undefined){
10030 throw "Invalid selector";
10032 if(unique === true){
10033 return new Roo.CompositeElement(els);
10035 return new Roo.CompositeElementLite(els);
10039 * Selects elements based on the passed CSS selector to enable working on them as 1.
10040 * @param {String/Array} selector The CSS selector or an array of elements
10041 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10042 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10043 * @return {CompositeElementLite/CompositeElement}
10047 Roo.select = Roo.Element.select;
10064 * Ext JS Library 1.1.1
10065 * Copyright(c) 2006-2007, Ext JS, LLC.
10067 * Originally Released Under LGPL - original licence link has changed is not relivant.
10070 * <script type="text/javascript">
10075 //Notifies Element that fx methods are available
10076 Roo.enableFx = true;
10080 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10081 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10082 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10083 * Element effects to work.</p><br/>
10085 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10086 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10087 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10088 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10089 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10090 * expected results and should be done with care.</p><br/>
10092 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10093 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10096 ----- -----------------------------
10097 tl The top left corner
10098 t The center of the top edge
10099 tr The top right corner
10100 l The center of the left edge
10101 r The center of the right edge
10102 bl The bottom left corner
10103 b The center of the bottom edge
10104 br The bottom right corner
10106 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10107 * below are common options that can be passed to any Fx method.</b>
10108 * @cfg {Function} callback A function called when the effect is finished
10109 * @cfg {Object} scope The scope of the effect function
10110 * @cfg {String} easing A valid Easing value for the effect
10111 * @cfg {String} afterCls A css class to apply after the effect
10112 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10113 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10114 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10115 * effects that end with the element being visually hidden, ignored otherwise)
10116 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10117 * a function which returns such a specification that will be applied to the Element after the effect finishes
10118 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10119 * @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
10120 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10124 * Slides the element into view. An anchor point can be optionally passed to set the point of
10125 * origin for the slide effect. This function automatically handles wrapping the element with
10126 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10129 // default: slide the element in from the top
10132 // custom: slide the element in from the right with a 2-second duration
10133 el.slideIn('r', { duration: 2 });
10135 // common config options shown with default values
10141 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10142 * @param {Object} options (optional) Object literal with any of the Fx config options
10143 * @return {Roo.Element} The Element
10145 slideIn : function(anchor, o){
10146 var el = this.getFxEl();
10149 el.queueFx(o, function(){
10151 anchor = anchor || "t";
10153 // fix display to visibility
10156 // restore values after effect
10157 var r = this.getFxRestore();
10158 var b = this.getBox();
10159 // fixed size for slide
10163 var wrap = this.fxWrap(r.pos, o, "hidden");
10165 var st = this.dom.style;
10166 st.visibility = "visible";
10167 st.position = "absolute";
10169 // clear out temp styles after slide and unwrap
10170 var after = function(){
10171 el.fxUnwrap(wrap, r.pos, o);
10172 st.width = r.width;
10173 st.height = r.height;
10176 // time to calc the positions
10177 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10179 switch(anchor.toLowerCase()){
10181 wrap.setSize(b.width, 0);
10182 st.left = st.bottom = "0";
10186 wrap.setSize(0, b.height);
10187 st.right = st.top = "0";
10191 wrap.setSize(0, b.height);
10192 wrap.setX(b.right);
10193 st.left = st.top = "0";
10194 a = {width: bw, points: pt};
10197 wrap.setSize(b.width, 0);
10198 wrap.setY(b.bottom);
10199 st.left = st.top = "0";
10200 a = {height: bh, points: pt};
10203 wrap.setSize(0, 0);
10204 st.right = st.bottom = "0";
10205 a = {width: bw, height: bh};
10208 wrap.setSize(0, 0);
10209 wrap.setY(b.y+b.height);
10210 st.right = st.top = "0";
10211 a = {width: bw, height: bh, points: pt};
10214 wrap.setSize(0, 0);
10215 wrap.setXY([b.right, b.bottom]);
10216 st.left = st.top = "0";
10217 a = {width: bw, height: bh, points: pt};
10220 wrap.setSize(0, 0);
10221 wrap.setX(b.x+b.width);
10222 st.left = st.bottom = "0";
10223 a = {width: bw, height: bh, points: pt};
10226 this.dom.style.visibility = "visible";
10229 arguments.callee.anim = wrap.fxanim(a,
10239 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10240 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10241 * 'hidden') but block elements will still take up space in the document. The element must be removed
10242 * from the DOM using the 'remove' config option if desired. This function automatically handles
10243 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10246 // default: slide the element out to the top
10249 // custom: slide the element out to the right with a 2-second duration
10250 el.slideOut('r', { duration: 2 });
10252 // common config options shown with default values
10260 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10261 * @param {Object} options (optional) Object literal with any of the Fx config options
10262 * @return {Roo.Element} The Element
10264 slideOut : function(anchor, o){
10265 var el = this.getFxEl();
10268 el.queueFx(o, function(){
10270 anchor = anchor || "t";
10272 // restore values after effect
10273 var r = this.getFxRestore();
10275 var b = this.getBox();
10276 // fixed size for slide
10280 var wrap = this.fxWrap(r.pos, o, "visible");
10282 var st = this.dom.style;
10283 st.visibility = "visible";
10284 st.position = "absolute";
10288 var after = function(){
10290 el.setDisplayed(false);
10295 el.fxUnwrap(wrap, r.pos, o);
10297 st.width = r.width;
10298 st.height = r.height;
10303 var a, zero = {to: 0};
10304 switch(anchor.toLowerCase()){
10306 st.left = st.bottom = "0";
10307 a = {height: zero};
10310 st.right = st.top = "0";
10314 st.left = st.top = "0";
10315 a = {width: zero, points: {to:[b.right, b.y]}};
10318 st.left = st.top = "0";
10319 a = {height: zero, points: {to:[b.x, b.bottom]}};
10322 st.right = st.bottom = "0";
10323 a = {width: zero, height: zero};
10326 st.right = st.top = "0";
10327 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10330 st.left = st.top = "0";
10331 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10334 st.left = st.bottom = "0";
10335 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10339 arguments.callee.anim = wrap.fxanim(a,
10349 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10350 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10351 * The element must be removed from the DOM using the 'remove' config option if desired.
10357 // common config options shown with default values
10365 * @param {Object} options (optional) Object literal with any of the Fx config options
10366 * @return {Roo.Element} The Element
10368 puff : function(o){
10369 var el = this.getFxEl();
10372 el.queueFx(o, function(){
10373 this.clearOpacity();
10376 // restore values after effect
10377 var r = this.getFxRestore();
10378 var st = this.dom.style;
10380 var after = function(){
10382 el.setDisplayed(false);
10389 el.setPositioning(r.pos);
10390 st.width = r.width;
10391 st.height = r.height;
10396 var width = this.getWidth();
10397 var height = this.getHeight();
10399 arguments.callee.anim = this.fxanim({
10400 width : {to: this.adjustWidth(width * 2)},
10401 height : {to: this.adjustHeight(height * 2)},
10402 points : {by: [-(width * .5), -(height * .5)]},
10404 fontSize: {to:200, unit: "%"}
10415 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10416 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10417 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10423 // all config options shown with default values
10431 * @param {Object} options (optional) Object literal with any of the Fx config options
10432 * @return {Roo.Element} The Element
10434 switchOff : function(o){
10435 var el = this.getFxEl();
10438 el.queueFx(o, function(){
10439 this.clearOpacity();
10442 // restore values after effect
10443 var r = this.getFxRestore();
10444 var st = this.dom.style;
10446 var after = function(){
10448 el.setDisplayed(false);
10454 el.setPositioning(r.pos);
10455 st.width = r.width;
10456 st.height = r.height;
10461 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10462 this.clearOpacity();
10466 points:{by:[0, this.getHeight() * .5]}
10467 }, o, 'motion', 0.3, 'easeIn', after);
10468 }).defer(100, this);
10475 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10476 * changed using the "attr" config option) and then fading back to the original color. If no original
10477 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10480 // default: highlight background to yellow
10483 // custom: highlight foreground text to blue for 2 seconds
10484 el.highlight("0000ff", { attr: 'color', duration: 2 });
10486 // common config options shown with default values
10487 el.highlight("ffff9c", {
10488 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10489 endColor: (current color) or "ffffff",
10494 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10495 * @param {Object} options (optional) Object literal with any of the Fx config options
10496 * @return {Roo.Element} The Element
10498 highlight : function(color, o){
10499 var el = this.getFxEl();
10502 el.queueFx(o, function(){
10503 color = color || "ffff9c";
10504 attr = o.attr || "backgroundColor";
10506 this.clearOpacity();
10509 var origColor = this.getColor(attr);
10510 var restoreColor = this.dom.style[attr];
10511 endColor = (o.endColor || origColor) || "ffffff";
10513 var after = function(){
10514 el.dom.style[attr] = restoreColor;
10519 a[attr] = {from: color, to: endColor};
10520 arguments.callee.anim = this.fxanim(a,
10530 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10533 // default: a single light blue ripple
10536 // custom: 3 red ripples lasting 3 seconds total
10537 el.frame("ff0000", 3, { duration: 3 });
10539 // common config options shown with default values
10540 el.frame("C3DAF9", 1, {
10541 duration: 1 //duration of entire animation (not each individual ripple)
10542 // Note: Easing is not configurable and will be ignored if included
10545 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10546 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10547 * @param {Object} options (optional) Object literal with any of the Fx config options
10548 * @return {Roo.Element} The Element
10550 frame : function(color, count, o){
10551 var el = this.getFxEl();
10554 el.queueFx(o, function(){
10555 color = color || "#C3DAF9";
10556 if(color.length == 6){
10557 color = "#" + color;
10559 count = count || 1;
10560 duration = o.duration || 1;
10563 var b = this.getBox();
10564 var animFn = function(){
10565 var proxy = this.createProxy({
10568 visbility:"hidden",
10569 position:"absolute",
10570 "z-index":"35000", // yee haw
10571 border:"0px solid " + color
10574 var scale = Roo.isBorderBox ? 2 : 1;
10576 top:{from:b.y, to:b.y - 20},
10577 left:{from:b.x, to:b.x - 20},
10578 borderWidth:{from:0, to:10},
10579 opacity:{from:1, to:0},
10580 height:{from:b.height, to:(b.height + (20*scale))},
10581 width:{from:b.width, to:(b.width + (20*scale))}
10582 }, duration, function(){
10586 animFn.defer((duration/2)*1000, this);
10597 * Creates a pause before any subsequent queued effects begin. If there are
10598 * no effects queued after the pause it will have no effect.
10603 * @param {Number} seconds The length of time to pause (in seconds)
10604 * @return {Roo.Element} The Element
10606 pause : function(seconds){
10607 var el = this.getFxEl();
10610 el.queueFx(o, function(){
10611 setTimeout(function(){
10613 }, seconds * 1000);
10619 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10620 * using the "endOpacity" config option.
10623 // default: fade in from opacity 0 to 100%
10626 // custom: fade in from opacity 0 to 75% over 2 seconds
10627 el.fadeIn({ endOpacity: .75, duration: 2});
10629 // common config options shown with default values
10631 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10636 * @param {Object} options (optional) Object literal with any of the Fx config options
10637 * @return {Roo.Element} The Element
10639 fadeIn : function(o){
10640 var el = this.getFxEl();
10642 el.queueFx(o, function(){
10643 this.setOpacity(0);
10645 this.dom.style.visibility = 'visible';
10646 var to = o.endOpacity || 1;
10647 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10648 o, null, .5, "easeOut", function(){
10650 this.clearOpacity();
10659 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10660 * using the "endOpacity" config option.
10663 // default: fade out from the element's current opacity to 0
10666 // custom: fade out from the element's current opacity to 25% over 2 seconds
10667 el.fadeOut({ endOpacity: .25, duration: 2});
10669 // common config options shown with default values
10671 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10678 * @param {Object} options (optional) Object literal with any of the Fx config options
10679 * @return {Roo.Element} The Element
10681 fadeOut : function(o){
10682 var el = this.getFxEl();
10684 el.queueFx(o, function(){
10685 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10686 o, null, .5, "easeOut", function(){
10687 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10688 this.dom.style.display = "none";
10690 this.dom.style.visibility = "hidden";
10692 this.clearOpacity();
10700 * Animates the transition of an element's dimensions from a starting height/width
10701 * to an ending height/width.
10704 // change height and width to 100x100 pixels
10705 el.scale(100, 100);
10707 // common config options shown with default values. The height and width will default to
10708 // the element's existing values if passed as null.
10711 [element's height], {
10716 * @param {Number} width The new width (pass undefined to keep the original width)
10717 * @param {Number} height The new height (pass undefined to keep the original height)
10718 * @param {Object} options (optional) Object literal with any of the Fx config options
10719 * @return {Roo.Element} The Element
10721 scale : function(w, h, o){
10722 this.shift(Roo.apply({}, o, {
10730 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10731 * Any of these properties not specified in the config object will not be changed. This effect
10732 * requires that at least one new dimension, position or opacity setting must be passed in on
10733 * the config object in order for the function to have any effect.
10736 // slide the element horizontally to x position 200 while changing the height and opacity
10737 el.shift({ x: 200, height: 50, opacity: .8 });
10739 // common config options shown with default values.
10741 width: [element's width],
10742 height: [element's height],
10743 x: [element's x position],
10744 y: [element's y position],
10745 opacity: [element's opacity],
10750 * @param {Object} options Object literal with any of the Fx config options
10751 * @return {Roo.Element} The Element
10753 shift : function(o){
10754 var el = this.getFxEl();
10756 el.queueFx(o, function(){
10757 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10758 if(w !== undefined){
10759 a.width = {to: this.adjustWidth(w)};
10761 if(h !== undefined){
10762 a.height = {to: this.adjustHeight(h)};
10764 if(x !== undefined || y !== undefined){
10766 x !== undefined ? x : this.getX(),
10767 y !== undefined ? y : this.getY()
10770 if(op !== undefined){
10771 a.opacity = {to: op};
10773 if(o.xy !== undefined){
10774 a.points = {to: o.xy};
10776 arguments.callee.anim = this.fxanim(a,
10777 o, 'motion', .35, "easeOut", function(){
10785 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10786 * ending point of the effect.
10789 // default: slide the element downward while fading out
10792 // custom: slide the element out to the right with a 2-second duration
10793 el.ghost('r', { duration: 2 });
10795 // common config options shown with default values
10803 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10804 * @param {Object} options (optional) Object literal with any of the Fx config options
10805 * @return {Roo.Element} The Element
10807 ghost : function(anchor, o){
10808 var el = this.getFxEl();
10811 el.queueFx(o, function(){
10812 anchor = anchor || "b";
10814 // restore values after effect
10815 var r = this.getFxRestore();
10816 var w = this.getWidth(),
10817 h = this.getHeight();
10819 var st = this.dom.style;
10821 var after = function(){
10823 el.setDisplayed(false);
10829 el.setPositioning(r.pos);
10830 st.width = r.width;
10831 st.height = r.height;
10836 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10837 switch(anchor.toLowerCase()){
10864 arguments.callee.anim = this.fxanim(a,
10874 * Ensures that all effects queued after syncFx is called on the element are
10875 * run concurrently. This is the opposite of {@link #sequenceFx}.
10876 * @return {Roo.Element} The Element
10878 syncFx : function(){
10879 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10888 * Ensures that all effects queued after sequenceFx is called on the element are
10889 * run in sequence. This is the opposite of {@link #syncFx}.
10890 * @return {Roo.Element} The Element
10892 sequenceFx : function(){
10893 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10895 concurrent : false,
10902 nextFx : function(){
10903 var ef = this.fxQueue[0];
10910 * Returns true if the element has any effects actively running or queued, else returns false.
10911 * @return {Boolean} True if element has active effects, else false
10913 hasActiveFx : function(){
10914 return this.fxQueue && this.fxQueue[0];
10918 * Stops any running effects and clears the element's internal effects queue if it contains
10919 * any additional effects that haven't started yet.
10920 * @return {Roo.Element} The Element
10922 stopFx : function(){
10923 if(this.hasActiveFx()){
10924 var cur = this.fxQueue[0];
10925 if(cur && cur.anim && cur.anim.isAnimated()){
10926 this.fxQueue = [cur]; // clear out others
10927 cur.anim.stop(true);
10934 beforeFx : function(o){
10935 if(this.hasActiveFx() && !o.concurrent){
10946 * Returns true if the element is currently blocking so that no other effect can be queued
10947 * until this effect is finished, else returns false if blocking is not set. This is commonly
10948 * used to ensure that an effect initiated by a user action runs to completion prior to the
10949 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10950 * @return {Boolean} True if blocking, else false
10952 hasFxBlock : function(){
10953 var q = this.fxQueue;
10954 return q && q[0] && q[0].block;
10958 queueFx : function(o, fn){
10962 if(!this.hasFxBlock()){
10963 Roo.applyIf(o, this.fxDefaults);
10965 var run = this.beforeFx(o);
10966 fn.block = o.block;
10967 this.fxQueue.push(fn);
10979 fxWrap : function(pos, o, vis){
10981 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10984 wrapXY = this.getXY();
10986 var div = document.createElement("div");
10987 div.style.visibility = vis;
10988 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10989 wrap.setPositioning(pos);
10990 if(wrap.getStyle("position") == "static"){
10991 wrap.position("relative");
10993 this.clearPositioning('auto');
10995 wrap.dom.appendChild(this.dom);
10997 wrap.setXY(wrapXY);
11004 fxUnwrap : function(wrap, pos, o){
11005 this.clearPositioning();
11006 this.setPositioning(pos);
11008 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11014 getFxRestore : function(){
11015 var st = this.dom.style;
11016 return {pos: this.getPositioning(), width: st.width, height : st.height};
11020 afterFx : function(o){
11022 this.applyStyles(o.afterStyle);
11025 this.addClass(o.afterCls);
11027 if(o.remove === true){
11030 Roo.callback(o.callback, o.scope, [this]);
11032 this.fxQueue.shift();
11038 getFxEl : function(){ // support for composite element fx
11039 return Roo.get(this.dom);
11043 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11044 animType = animType || 'run';
11046 var anim = Roo.lib.Anim[animType](
11048 (opt.duration || defaultDur) || .35,
11049 (opt.easing || defaultEase) || 'easeOut',
11051 Roo.callback(cb, this);
11060 // backwords compat
11061 Roo.Fx.resize = Roo.Fx.scale;
11063 //When included, Roo.Fx is automatically applied to Element so that all basic
11064 //effects are available directly via the Element API
11065 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11067 * Ext JS Library 1.1.1
11068 * Copyright(c) 2006-2007, Ext JS, LLC.
11070 * Originally Released Under LGPL - original licence link has changed is not relivant.
11073 * <script type="text/javascript">
11078 * @class Roo.CompositeElement
11079 * Standard composite class. Creates a Roo.Element for every element in the collection.
11081 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11082 * actions will be performed on all the elements in this collection.</b>
11084 * All methods return <i>this</i> and can be chained.
11086 var els = Roo.select("#some-el div.some-class", true);
11087 // or select directly from an existing element
11088 var el = Roo.get('some-el');
11089 el.select('div.some-class', true);
11091 els.setWidth(100); // all elements become 100 width
11092 els.hide(true); // all elements fade out and hide
11094 els.setWidth(100).hide(true);
11097 Roo.CompositeElement = function(els){
11098 this.elements = [];
11099 this.addElements(els);
11101 Roo.CompositeElement.prototype = {
11103 addElements : function(els){
11107 if(typeof els == "string"){
11108 els = Roo.Element.selectorFunction(els);
11110 var yels = this.elements;
11111 var index = yels.length-1;
11112 for(var i = 0, len = els.length; i < len; i++) {
11113 yels[++index] = Roo.get(els[i]);
11119 * Clears this composite and adds the elements returned by the passed selector.
11120 * @param {String/Array} els A string CSS selector, an array of elements or an element
11121 * @return {CompositeElement} this
11123 fill : function(els){
11124 this.elements = [];
11130 * Filters this composite to only elements that match the passed selector.
11131 * @param {String} selector A string CSS selector
11132 * @param {Boolean} inverse return inverse filter (not matches)
11133 * @return {CompositeElement} this
11135 filter : function(selector, inverse){
11137 inverse = inverse || false;
11138 this.each(function(el){
11139 var match = inverse ? !el.is(selector) : el.is(selector);
11141 els[els.length] = el.dom;
11148 invoke : function(fn, args){
11149 var els = this.elements;
11150 for(var i = 0, len = els.length; i < len; i++) {
11151 Roo.Element.prototype[fn].apply(els[i], args);
11156 * Adds elements to this composite.
11157 * @param {String/Array} els A string CSS selector, an array of elements or an element
11158 * @return {CompositeElement} this
11160 add : function(els){
11161 if(typeof els == "string"){
11162 this.addElements(Roo.Element.selectorFunction(els));
11163 }else if(els.length !== undefined){
11164 this.addElements(els);
11166 this.addElements([els]);
11171 * Calls the passed function passing (el, this, index) for each element in this composite.
11172 * @param {Function} fn The function to call
11173 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11174 * @return {CompositeElement} this
11176 each : function(fn, scope){
11177 var els = this.elements;
11178 for(var i = 0, len = els.length; i < len; i++){
11179 if(fn.call(scope || els[i], els[i], this, i) === false) {
11187 * Returns the Element object at the specified index
11188 * @param {Number} index
11189 * @return {Roo.Element}
11191 item : function(index){
11192 return this.elements[index] || null;
11196 * Returns the first Element
11197 * @return {Roo.Element}
11199 first : function(){
11200 return this.item(0);
11204 * Returns the last Element
11205 * @return {Roo.Element}
11208 return this.item(this.elements.length-1);
11212 * Returns the number of elements in this composite
11215 getCount : function(){
11216 return this.elements.length;
11220 * Returns true if this composite contains the passed element
11223 contains : function(el){
11224 return this.indexOf(el) !== -1;
11228 * Returns true if this composite contains the passed element
11231 indexOf : function(el){
11232 return this.elements.indexOf(Roo.get(el));
11237 * Removes the specified element(s).
11238 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11239 * or an array of any of those.
11240 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11241 * @return {CompositeElement} this
11243 removeElement : function(el, removeDom){
11244 if(el instanceof Array){
11245 for(var i = 0, len = el.length; i < len; i++){
11246 this.removeElement(el[i]);
11250 var index = typeof el == 'number' ? el : this.indexOf(el);
11253 var d = this.elements[index];
11257 d.parentNode.removeChild(d);
11260 this.elements.splice(index, 1);
11266 * Replaces the specified element with the passed element.
11267 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11269 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11270 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11271 * @return {CompositeElement} this
11273 replaceElement : function(el, replacement, domReplace){
11274 var index = typeof el == 'number' ? el : this.indexOf(el);
11277 this.elements[index].replaceWith(replacement);
11279 this.elements.splice(index, 1, Roo.get(replacement))
11286 * Removes all elements.
11288 clear : function(){
11289 this.elements = [];
11293 Roo.CompositeElement.createCall = function(proto, fnName){
11294 if(!proto[fnName]){
11295 proto[fnName] = function(){
11296 return this.invoke(fnName, arguments);
11300 for(var fnName in Roo.Element.prototype){
11301 if(typeof Roo.Element.prototype[fnName] == "function"){
11302 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11308 * Ext JS Library 1.1.1
11309 * Copyright(c) 2006-2007, Ext JS, LLC.
11311 * Originally Released Under LGPL - original licence link has changed is not relivant.
11314 * <script type="text/javascript">
11318 * @class Roo.CompositeElementLite
11319 * @extends Roo.CompositeElement
11320 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11322 var els = Roo.select("#some-el div.some-class");
11323 // or select directly from an existing element
11324 var el = Roo.get('some-el');
11325 el.select('div.some-class');
11327 els.setWidth(100); // all elements become 100 width
11328 els.hide(true); // all elements fade out and hide
11330 els.setWidth(100).hide(true);
11331 </code></pre><br><br>
11332 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11333 * actions will be performed on all the elements in this collection.</b>
11335 Roo.CompositeElementLite = function(els){
11336 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11337 this.el = new Roo.Element.Flyweight();
11339 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11340 addElements : function(els){
11342 if(els instanceof Array){
11343 this.elements = this.elements.concat(els);
11345 var yels = this.elements;
11346 var index = yels.length-1;
11347 for(var i = 0, len = els.length; i < len; i++) {
11348 yels[++index] = els[i];
11354 invoke : function(fn, args){
11355 var els = this.elements;
11357 for(var i = 0, len = els.length; i < len; i++) {
11359 Roo.Element.prototype[fn].apply(el, args);
11364 * Returns a flyweight Element of the dom element object at the specified index
11365 * @param {Number} index
11366 * @return {Roo.Element}
11368 item : function(index){
11369 if(!this.elements[index]){
11372 this.el.dom = this.elements[index];
11376 // fixes scope with flyweight
11377 addListener : function(eventName, handler, scope, opt){
11378 var els = this.elements;
11379 for(var i = 0, len = els.length; i < len; i++) {
11380 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11386 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11387 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11388 * a reference to the dom node, use el.dom.</b>
11389 * @param {Function} fn The function to call
11390 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11391 * @return {CompositeElement} this
11393 each : function(fn, scope){
11394 var els = this.elements;
11396 for(var i = 0, len = els.length; i < len; i++){
11398 if(fn.call(scope || el, el, this, i) === false){
11405 indexOf : function(el){
11406 return this.elements.indexOf(Roo.getDom(el));
11409 replaceElement : function(el, replacement, domReplace){
11410 var index = typeof el == 'number' ? el : this.indexOf(el);
11412 replacement = Roo.getDom(replacement);
11414 var d = this.elements[index];
11415 d.parentNode.insertBefore(replacement, d);
11416 d.parentNode.removeChild(d);
11418 this.elements.splice(index, 1, replacement);
11423 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11427 * Ext JS Library 1.1.1
11428 * Copyright(c) 2006-2007, Ext JS, LLC.
11430 * Originally Released Under LGPL - original licence link has changed is not relivant.
11433 * <script type="text/javascript">
11439 * @class Roo.data.Connection
11440 * @extends Roo.util.Observable
11441 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11442 * either to a configured URL, or to a URL specified at request time.<br><br>
11444 * Requests made by this class are asynchronous, and will return immediately. No data from
11445 * the server will be available to the statement immediately following the {@link #request} call.
11446 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11448 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11449 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11450 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11451 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11452 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11453 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11454 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11455 * standard DOM methods.
11457 * @param {Object} config a configuration object.
11459 Roo.data.Connection = function(config){
11460 Roo.apply(this, config);
11463 * @event beforerequest
11464 * Fires before a network request is made to retrieve a data object.
11465 * @param {Connection} conn This Connection object.
11466 * @param {Object} options The options config object passed to the {@link #request} method.
11468 "beforerequest" : true,
11470 * @event requestcomplete
11471 * Fires if the request was successfully completed.
11472 * @param {Connection} conn This Connection object.
11473 * @param {Object} response The XHR object containing the response data.
11474 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11475 * @param {Object} options The options config object passed to the {@link #request} method.
11477 "requestcomplete" : true,
11479 * @event requestexception
11480 * Fires if an error HTTP status was returned from the server.
11481 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11482 * @param {Connection} conn This Connection object.
11483 * @param {Object} response The XHR object containing the response data.
11484 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11485 * @param {Object} options The options config object passed to the {@link #request} method.
11487 "requestexception" : true
11489 Roo.data.Connection.superclass.constructor.call(this);
11492 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11494 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11497 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11498 * extra parameters to each request made by this object. (defaults to undefined)
11501 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11502 * to each request made by this object. (defaults to undefined)
11505 * @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)
11508 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11512 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11518 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11521 disableCaching: true,
11524 * Sends an HTTP request to a remote server.
11525 * @param {Object} options An object which may contain the following properties:<ul>
11526 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11527 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11528 * request, a url encoded string or a function to call to get either.</li>
11529 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11530 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11531 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11532 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11533 * <li>options {Object} The parameter to the request call.</li>
11534 * <li>success {Boolean} True if the request succeeded.</li>
11535 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11537 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11538 * The callback is passed the following parameters:<ul>
11539 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11540 * <li>options {Object} The parameter to the request call.</li>
11542 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11543 * The callback is passed the following parameters:<ul>
11544 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11545 * <li>options {Object} The parameter to the request call.</li>
11547 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11548 * for the callback function. Defaults to the browser window.</li>
11549 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11550 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11551 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11552 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11553 * params for the post data. Any params will be appended to the URL.</li>
11554 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11556 * @return {Number} transactionId
11558 request : function(o){
11559 if(this.fireEvent("beforerequest", this, o) !== false){
11562 if(typeof p == "function"){
11563 p = p.call(o.scope||window, o);
11565 if(typeof p == "object"){
11566 p = Roo.urlEncode(o.params);
11568 if(this.extraParams){
11569 var extras = Roo.urlEncode(this.extraParams);
11570 p = p ? (p + '&' + extras) : extras;
11573 var url = o.url || this.url;
11574 if(typeof url == 'function'){
11575 url = url.call(o.scope||window, o);
11579 var form = Roo.getDom(o.form);
11580 url = url || form.action;
11582 var enctype = form.getAttribute("enctype");
11583 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11584 return this.doFormUpload(o, p, url);
11586 var f = Roo.lib.Ajax.serializeForm(form);
11587 p = p ? (p + '&' + f) : f;
11590 var hs = o.headers;
11591 if(this.defaultHeaders){
11592 hs = Roo.apply(hs || {}, this.defaultHeaders);
11599 success: this.handleResponse,
11600 failure: this.handleFailure,
11602 argument: {options: o},
11603 timeout : o.timeout || this.timeout
11606 var method = o.method||this.method||(p ? "POST" : "GET");
11608 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11609 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11612 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11616 }else if(this.autoAbort !== false){
11620 if((method == 'GET' && p) || o.xmlData){
11621 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11624 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11625 return this.transId;
11627 Roo.callback(o.callback, o.scope, [o, null, null]);
11633 * Determine whether this object has a request outstanding.
11634 * @param {Number} transactionId (Optional) defaults to the last transaction
11635 * @return {Boolean} True if there is an outstanding request.
11637 isLoading : function(transId){
11639 return Roo.lib.Ajax.isCallInProgress(transId);
11641 return this.transId ? true : false;
11646 * Aborts any outstanding request.
11647 * @param {Number} transactionId (Optional) defaults to the last transaction
11649 abort : function(transId){
11650 if(transId || this.isLoading()){
11651 Roo.lib.Ajax.abort(transId || this.transId);
11656 handleResponse : function(response){
11657 this.transId = false;
11658 var options = response.argument.options;
11659 response.argument = options ? options.argument : null;
11660 this.fireEvent("requestcomplete", this, response, options);
11661 Roo.callback(options.success, options.scope, [response, options]);
11662 Roo.callback(options.callback, options.scope, [options, true, response]);
11666 handleFailure : function(response, e){
11667 this.transId = false;
11668 var options = response.argument.options;
11669 response.argument = options ? options.argument : null;
11670 this.fireEvent("requestexception", this, response, options, e);
11671 Roo.callback(options.failure, options.scope, [response, options]);
11672 Roo.callback(options.callback, options.scope, [options, false, response]);
11676 doFormUpload : function(o, ps, url){
11678 var frame = document.createElement('iframe');
11681 frame.className = 'x-hidden';
11683 frame.src = Roo.SSL_SECURE_URL;
11685 document.body.appendChild(frame);
11688 document.frames[id].name = id;
11691 var form = Roo.getDom(o.form);
11693 form.method = 'POST';
11694 form.enctype = form.encoding = 'multipart/form-data';
11700 if(ps){ // add dynamic params
11702 ps = Roo.urlDecode(ps, false);
11704 if(ps.hasOwnProperty(k)){
11705 hd = document.createElement('input');
11706 hd.type = 'hidden';
11709 form.appendChild(hd);
11716 var r = { // bogus response object
11721 r.argument = o ? o.argument : null;
11726 doc = frame.contentWindow.document;
11728 doc = (frame.contentDocument || window.frames[id].document);
11730 if(doc && doc.body){
11731 r.responseText = doc.body.innerHTML;
11733 if(doc && doc.XMLDocument){
11734 r.responseXML = doc.XMLDocument;
11736 r.responseXML = doc;
11743 Roo.EventManager.removeListener(frame, 'load', cb, this);
11745 this.fireEvent("requestcomplete", this, r, o);
11746 Roo.callback(o.success, o.scope, [r, o]);
11747 Roo.callback(o.callback, o.scope, [o, true, r]);
11749 setTimeout(function(){document.body.removeChild(frame);}, 100);
11752 Roo.EventManager.on(frame, 'load', cb, this);
11755 if(hiddens){ // remove dynamic params
11756 for(var i = 0, len = hiddens.length; i < len; i++){
11757 form.removeChild(hiddens[i]);
11764 * Ext JS Library 1.1.1
11765 * Copyright(c) 2006-2007, Ext JS, LLC.
11767 * Originally Released Under LGPL - original licence link has changed is not relivant.
11770 * <script type="text/javascript">
11774 * Global Ajax request class.
11777 * @extends Roo.data.Connection
11780 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11781 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11782 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11783 * @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)
11784 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11785 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11786 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11788 Roo.Ajax = new Roo.data.Connection({
11797 * Serialize the passed form into a url encoded string
11799 * @param {String/HTMLElement} form
11802 serializeForm : function(form){
11803 return Roo.lib.Ajax.serializeForm(form);
11807 * Ext JS Library 1.1.1
11808 * Copyright(c) 2006-2007, Ext JS, LLC.
11810 * Originally Released Under LGPL - original licence link has changed is not relivant.
11813 * <script type="text/javascript">
11818 * @class Roo.UpdateManager
11819 * @extends Roo.util.Observable
11820 * Provides AJAX-style update for Element object.<br><br>
11823 * // Get it from a Roo.Element object
11824 * var el = Roo.get("foo");
11825 * var mgr = el.getUpdateManager();
11826 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11828 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11830 * // or directly (returns the same UpdateManager instance)
11831 * var mgr = new Roo.UpdateManager("myElementId");
11832 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11833 * mgr.on("update", myFcnNeedsToKnow);
11835 // short handed call directly from the element object
11836 Roo.get("foo").load({
11840 text: "Loading Foo..."
11844 * Create new UpdateManager directly.
11845 * @param {String/HTMLElement/Roo.Element} el The element to update
11846 * @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).
11848 Roo.UpdateManager = function(el, forceNew){
11850 if(!forceNew && el.updateManager){
11851 return el.updateManager;
11854 * The Element object
11855 * @type Roo.Element
11859 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11862 this.defaultUrl = null;
11866 * @event beforeupdate
11867 * Fired before an update is made, return false from your handler and the update is cancelled.
11868 * @param {Roo.Element} el
11869 * @param {String/Object/Function} url
11870 * @param {String/Object} params
11872 "beforeupdate": true,
11875 * Fired after successful update is made.
11876 * @param {Roo.Element} el
11877 * @param {Object} oResponseObject The response Object
11882 * Fired on update failure.
11883 * @param {Roo.Element} el
11884 * @param {Object} oResponseObject The response Object
11888 var d = Roo.UpdateManager.defaults;
11890 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11893 this.sslBlankUrl = d.sslBlankUrl;
11895 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11898 this.disableCaching = d.disableCaching;
11900 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11903 this.indicatorText = d.indicatorText;
11905 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11908 this.showLoadIndicator = d.showLoadIndicator;
11910 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11913 this.timeout = d.timeout;
11916 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11919 this.loadScripts = d.loadScripts;
11922 * Transaction object of current executing transaction
11924 this.transaction = null;
11929 this.autoRefreshProcId = null;
11931 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11934 this.refreshDelegate = this.refresh.createDelegate(this);
11936 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11939 this.updateDelegate = this.update.createDelegate(this);
11941 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11944 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11948 this.successDelegate = this.processSuccess.createDelegate(this);
11952 this.failureDelegate = this.processFailure.createDelegate(this);
11954 if(!this.renderer){
11956 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11958 this.renderer = new Roo.UpdateManager.BasicRenderer();
11961 Roo.UpdateManager.superclass.constructor.call(this);
11964 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11966 * Get the Element this UpdateManager is bound to
11967 * @return {Roo.Element} The element
11969 getEl : function(){
11973 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11974 * @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:
11977 url: "your-url.php",<br/>
11978 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11979 callback: yourFunction,<br/>
11980 scope: yourObject, //(optional scope) <br/>
11981 discardUrl: false, <br/>
11982 nocache: false,<br/>
11983 text: "Loading...",<br/>
11985 scripts: false<br/>
11988 * The only required property is url. The optional properties nocache, text and scripts
11989 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11990 * @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}
11991 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11992 * @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.
11994 update : function(url, params, callback, discardUrl){
11995 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11996 var method = this.method,
11998 if(typeof url == "object"){ // must be config object
12001 params = params || cfg.params;
12002 callback = callback || cfg.callback;
12003 discardUrl = discardUrl || cfg.discardUrl;
12004 if(callback && cfg.scope){
12005 callback = callback.createDelegate(cfg.scope);
12007 if(typeof cfg.method != "undefined"){method = cfg.method;};
12008 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12009 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12010 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12011 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12013 this.showLoading();
12015 this.defaultUrl = url;
12017 if(typeof url == "function"){
12018 url = url.call(this);
12021 method = method || (params ? "POST" : "GET");
12022 if(method == "GET"){
12023 url = this.prepareUrl(url);
12026 var o = Roo.apply(cfg ||{}, {
12029 success: this.successDelegate,
12030 failure: this.failureDelegate,
12031 callback: undefined,
12032 timeout: (this.timeout*1000),
12033 argument: {"url": url, "form": null, "callback": callback, "params": params}
12035 Roo.log("updated manager called with timeout of " + o.timeout);
12036 this.transaction = Roo.Ajax.request(o);
12041 * 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.
12042 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12043 * @param {String/HTMLElement} form The form Id or form element
12044 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12045 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12046 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12048 formUpdate : function(form, url, reset, callback){
12049 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12050 if(typeof url == "function"){
12051 url = url.call(this);
12053 form = Roo.getDom(form);
12054 this.transaction = Roo.Ajax.request({
12057 success: this.successDelegate,
12058 failure: this.failureDelegate,
12059 timeout: (this.timeout*1000),
12060 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12062 this.showLoading.defer(1, this);
12067 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12068 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12070 refresh : function(callback){
12071 if(this.defaultUrl == null){
12074 this.update(this.defaultUrl, null, callback, true);
12078 * Set this element to auto refresh.
12079 * @param {Number} interval How often to update (in seconds).
12080 * @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)
12081 * @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}
12082 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12083 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12085 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12087 this.update(url || this.defaultUrl, params, callback, true);
12089 if(this.autoRefreshProcId){
12090 clearInterval(this.autoRefreshProcId);
12092 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12096 * Stop auto refresh on this element.
12098 stopAutoRefresh : function(){
12099 if(this.autoRefreshProcId){
12100 clearInterval(this.autoRefreshProcId);
12101 delete this.autoRefreshProcId;
12105 isAutoRefreshing : function(){
12106 return this.autoRefreshProcId ? true : false;
12109 * Called to update the element to "Loading" state. Override to perform custom action.
12111 showLoading : function(){
12112 if(this.showLoadIndicator){
12113 this.el.update(this.indicatorText);
12118 * Adds unique parameter to query string if disableCaching = true
12121 prepareUrl : function(url){
12122 if(this.disableCaching){
12123 var append = "_dc=" + (new Date().getTime());
12124 if(url.indexOf("?") !== -1){
12125 url += "&" + append;
12127 url += "?" + append;
12136 processSuccess : function(response){
12137 this.transaction = null;
12138 if(response.argument.form && response.argument.reset){
12139 try{ // put in try/catch since some older FF releases had problems with this
12140 response.argument.form.reset();
12143 if(this.loadScripts){
12144 this.renderer.render(this.el, response, this,
12145 this.updateComplete.createDelegate(this, [response]));
12147 this.renderer.render(this.el, response, this);
12148 this.updateComplete(response);
12152 updateComplete : function(response){
12153 this.fireEvent("update", this.el, response);
12154 if(typeof response.argument.callback == "function"){
12155 response.argument.callback(this.el, true, response);
12162 processFailure : function(response){
12163 this.transaction = null;
12164 this.fireEvent("failure", this.el, response);
12165 if(typeof response.argument.callback == "function"){
12166 response.argument.callback(this.el, false, response);
12171 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12172 * @param {Object} renderer The object implementing the render() method
12174 setRenderer : function(renderer){
12175 this.renderer = renderer;
12178 getRenderer : function(){
12179 return this.renderer;
12183 * Set the defaultUrl used for updates
12184 * @param {String/Function} defaultUrl The url or a function to call to get the url
12186 setDefaultUrl : function(defaultUrl){
12187 this.defaultUrl = defaultUrl;
12191 * Aborts the executing transaction
12193 abort : function(){
12194 if(this.transaction){
12195 Roo.Ajax.abort(this.transaction);
12200 * Returns true if an update is in progress
12201 * @return {Boolean}
12203 isUpdating : function(){
12204 if(this.transaction){
12205 return Roo.Ajax.isLoading(this.transaction);
12212 * @class Roo.UpdateManager.defaults
12213 * @static (not really - but it helps the doc tool)
12214 * The defaults collection enables customizing the default properties of UpdateManager
12216 Roo.UpdateManager.defaults = {
12218 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12224 * True to process scripts by default (Defaults to false).
12227 loadScripts : false,
12230 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12233 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12235 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12238 disableCaching : false,
12240 * Whether to show indicatorText when loading (Defaults to true).
12243 showLoadIndicator : true,
12245 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12248 indicatorText : '<div class="loading-indicator">Loading...</div>'
12252 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12254 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12255 * @param {String/HTMLElement/Roo.Element} el The element to update
12256 * @param {String} url The url
12257 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12258 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12261 * @member Roo.UpdateManager
12263 Roo.UpdateManager.updateElement = function(el, url, params, options){
12264 var um = Roo.get(el, true).getUpdateManager();
12265 Roo.apply(um, options);
12266 um.update(url, params, options ? options.callback : null);
12268 // alias for backwards compat
12269 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12271 * @class Roo.UpdateManager.BasicRenderer
12272 * Default Content renderer. Updates the elements innerHTML with the responseText.
12274 Roo.UpdateManager.BasicRenderer = function(){};
12276 Roo.UpdateManager.BasicRenderer.prototype = {
12278 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12279 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12280 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12281 * @param {Roo.Element} el The element being rendered
12282 * @param {Object} response The YUI Connect response object
12283 * @param {UpdateManager} updateManager The calling update manager
12284 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12286 render : function(el, response, updateManager, callback){
12287 el.update(response.responseText, updateManager.loadScripts, callback);
12293 * (c)) Alan Knowles
12299 * @class Roo.DomTemplate
12300 * @extends Roo.Template
12301 * An effort at a dom based template engine..
12303 * Similar to XTemplate, except it uses dom parsing to create the template..
12305 * Supported features:
12310 {a_variable} - output encoded.
12311 {a_variable.format:("Y-m-d")} - call a method on the variable
12312 {a_variable:raw} - unencoded output
12313 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12314 {a_variable:this.method_on_template(...)} - call a method on the template object.
12319 <div roo-for="a_variable or condition.."></div>
12320 <div roo-if="a_variable or condition"></div>
12321 <div roo-exec="some javascript"></div>
12322 <div roo-name="named_template"></div>
12327 Roo.DomTemplate = function()
12329 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12336 Roo.extend(Roo.DomTemplate, Roo.Template, {
12338 * id counter for sub templates.
12342 * flag to indicate if dom parser is inside a pre,
12343 * it will strip whitespace if not.
12348 * The various sub templates
12356 * basic tag replacing syntax
12359 * // you can fake an object call by doing this
12363 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12364 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12366 iterChild : function (node, method) {
12368 var oldPre = this.inPre;
12369 if (node.tagName == 'PRE') {
12372 for( var i = 0; i < node.childNodes.length; i++) {
12373 method.call(this, node.childNodes[i]);
12375 this.inPre = oldPre;
12381 * compile the template
12383 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12386 compile: function()
12390 // covert the html into DOM...
12394 doc = document.implementation.createHTMLDocument("");
12395 doc.documentElement.innerHTML = this.html ;
12396 div = doc.documentElement;
12398 // old IE... - nasty -- it causes all sorts of issues.. with
12399 // images getting pulled from server..
12400 div = document.createElement('div');
12401 div.innerHTML = this.html;
12403 //doc.documentElement.innerHTML = htmlBody
12409 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12411 var tpls = this.tpls;
12413 // create a top level template from the snippet..
12415 //Roo.log(div.innerHTML);
12422 body : div.innerHTML,
12435 Roo.each(tpls, function(tp){
12436 this.compileTpl(tp);
12437 this.tpls[tp.id] = tp;
12440 this.master = tpls[0];
12446 compileNode : function(node, istop) {
12451 // skip anything not a tag..
12452 if (node.nodeType != 1) {
12453 if (node.nodeType == 3 && !this.inPre) {
12454 // reduce white space..
12455 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12478 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12479 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12480 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12481 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12487 // just itterate children..
12488 this.iterChild(node,this.compileNode);
12491 tpl.uid = this.id++;
12492 tpl.value = node.getAttribute('roo-' + tpl.attr);
12493 node.removeAttribute('roo-'+ tpl.attr);
12494 if (tpl.attr != 'name') {
12495 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12496 node.parentNode.replaceChild(placeholder, node);
12499 var placeholder = document.createElement('span');
12500 placeholder.className = 'roo-tpl-' + tpl.value;
12501 node.parentNode.replaceChild(placeholder, node);
12504 // parent now sees '{domtplXXXX}
12505 this.iterChild(node,this.compileNode);
12507 // we should now have node body...
12508 var div = document.createElement('div');
12509 div.appendChild(node);
12511 // this has the unfortunate side effect of converting tagged attributes
12512 // eg. href="{...}" into %7C...%7D
12513 // this has been fixed by searching for those combo's although it's a bit hacky..
12516 tpl.body = div.innerHTML;
12523 switch (tpl.value) {
12524 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12525 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12526 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12531 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12535 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12539 tpl.id = tpl.value; // replace non characters???
12545 this.tpls.push(tpl);
12555 * Compile a segment of the template into a 'sub-template'
12561 compileTpl : function(tpl)
12563 var fm = Roo.util.Format;
12564 var useF = this.disableFormats !== true;
12566 var sep = Roo.isGecko ? "+\n" : ",\n";
12568 var undef = function(str) {
12569 Roo.debug && Roo.log("Property not found :" + str);
12573 //Roo.log(tpl.body);
12577 var fn = function(m, lbrace, name, format, args)
12580 //Roo.log(arguments);
12581 args = args ? args.replace(/\\'/g,"'") : args;
12582 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12583 if (typeof(format) == 'undefined') {
12584 format = 'htmlEncode';
12586 if (format == 'raw' ) {
12590 if(name.substr(0, 6) == 'domtpl'){
12591 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12594 // build an array of options to determine if value is undefined..
12596 // basically get 'xxxx.yyyy' then do
12597 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12598 // (function () { Roo.log("Property not found"); return ''; })() :
12603 Roo.each(name.split('.'), function(st) {
12604 lookfor += (lookfor.length ? '.': '') + st;
12605 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12608 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12611 if(format && useF){
12613 args = args ? ',' + args : "";
12615 if(format.substr(0, 5) != "this."){
12616 format = "fm." + format + '(';
12618 format = 'this.call("'+ format.substr(5) + '", ';
12622 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12625 if (args && args.length) {
12626 // called with xxyx.yuu:(test,test)
12628 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12630 // raw.. - :raw modifier..
12631 return "'"+ sep + udef_st + name + ")"+sep+"'";
12635 // branched to use + in gecko and [].join() in others
12637 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12638 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12641 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12642 body.push(tpl.body.replace(/(\r\n|\n)/g,
12643 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12644 body.push("'].join('');};};");
12645 body = body.join('');
12648 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12650 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12657 * same as applyTemplate, except it's done to one of the subTemplates
12658 * when using named templates, you can do:
12660 * var str = pl.applySubTemplate('your-name', values);
12663 * @param {Number} id of the template
12664 * @param {Object} values to apply to template
12665 * @param {Object} parent (normaly the instance of this object)
12667 applySubTemplate : function(id, values, parent)
12671 var t = this.tpls[id];
12675 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12676 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12680 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12687 if(t.execCall && t.execCall.call(this, values, parent)){
12691 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12697 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12698 parent = t.target ? values : parent;
12699 if(t.forCall && vs instanceof Array){
12701 for(var i = 0, len = vs.length; i < len; i++){
12703 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12705 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12707 //Roo.log(t.compiled);
12711 return buf.join('');
12714 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12719 return t.compiled.call(this, vs, parent);
12721 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12723 //Roo.log(t.compiled);
12731 applyTemplate : function(values){
12732 return this.master.compiled.call(this, values, {});
12733 //var s = this.subs;
12736 apply : function(){
12737 return this.applyTemplate.apply(this, arguments);
12742 Roo.DomTemplate.from = function(el){
12743 el = Roo.getDom(el);
12744 return new Roo.Domtemplate(el.value || el.innerHTML);
12747 * Ext JS Library 1.1.1
12748 * Copyright(c) 2006-2007, Ext JS, LLC.
12750 * Originally Released Under LGPL - original licence link has changed is not relivant.
12753 * <script type="text/javascript">
12757 * @class Roo.util.DelayedTask
12758 * Provides a convenient method of performing setTimeout where a new
12759 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12760 * You can use this class to buffer
12761 * the keypress events for a certain number of milliseconds, and perform only if they stop
12762 * for that amount of time.
12763 * @constructor The parameters to this constructor serve as defaults and are not required.
12764 * @param {Function} fn (optional) The default function to timeout
12765 * @param {Object} scope (optional) The default scope of that timeout
12766 * @param {Array} args (optional) The default Array of arguments
12768 Roo.util.DelayedTask = function(fn, scope, args){
12769 var id = null, d, t;
12771 var call = function(){
12772 var now = new Date().getTime();
12776 fn.apply(scope, args || []);
12780 * Cancels any pending timeout and queues a new one
12781 * @param {Number} delay The milliseconds to delay
12782 * @param {Function} newFn (optional) Overrides function passed to constructor
12783 * @param {Object} newScope (optional) Overrides scope passed to constructor
12784 * @param {Array} newArgs (optional) Overrides args passed to constructor
12786 this.delay = function(delay, newFn, newScope, newArgs){
12787 if(id && delay != d){
12791 t = new Date().getTime();
12793 scope = newScope || scope;
12794 args = newArgs || args;
12796 id = setInterval(call, d);
12801 * Cancel the last queued timeout
12803 this.cancel = function(){
12811 * Ext JS Library 1.1.1
12812 * Copyright(c) 2006-2007, Ext JS, LLC.
12814 * Originally Released Under LGPL - original licence link has changed is not relivant.
12817 * <script type="text/javascript">
12821 Roo.util.TaskRunner = function(interval){
12822 interval = interval || 10;
12823 var tasks = [], removeQueue = [];
12825 var running = false;
12827 var stopThread = function(){
12833 var startThread = function(){
12836 id = setInterval(runTasks, interval);
12840 var removeTask = function(task){
12841 removeQueue.push(task);
12847 var runTasks = function(){
12848 if(removeQueue.length > 0){
12849 for(var i = 0, len = removeQueue.length; i < len; i++){
12850 tasks.remove(removeQueue[i]);
12853 if(tasks.length < 1){
12858 var now = new Date().getTime();
12859 for(var i = 0, len = tasks.length; i < len; ++i){
12861 var itime = now - t.taskRunTime;
12862 if(t.interval <= itime){
12863 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12864 t.taskRunTime = now;
12865 if(rt === false || t.taskRunCount === t.repeat){
12870 if(t.duration && t.duration <= (now - t.taskStartTime)){
12877 * Queues a new task.
12878 * @param {Object} task
12880 this.start = function(task){
12882 task.taskStartTime = new Date().getTime();
12883 task.taskRunTime = 0;
12884 task.taskRunCount = 0;
12889 this.stop = function(task){
12894 this.stopAll = function(){
12896 for(var i = 0, len = tasks.length; i < len; i++){
12897 if(tasks[i].onStop){
12906 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12908 * Ext JS Library 1.1.1
12909 * Copyright(c) 2006-2007, Ext JS, LLC.
12911 * Originally Released Under LGPL - original licence link has changed is not relivant.
12914 * <script type="text/javascript">
12919 * @class Roo.util.MixedCollection
12920 * @extends Roo.util.Observable
12921 * A Collection class that maintains both numeric indexes and keys and exposes events.
12923 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12924 * collection (defaults to false)
12925 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12926 * and return the key value for that item. This is used when available to look up the key on items that
12927 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12928 * equivalent to providing an implementation for the {@link #getKey} method.
12930 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12938 * Fires when the collection is cleared.
12943 * Fires when an item is added to the collection.
12944 * @param {Number} index The index at which the item was added.
12945 * @param {Object} o The item added.
12946 * @param {String} key The key associated with the added item.
12951 * Fires when an item is replaced in the collection.
12952 * @param {String} key he key associated with the new added.
12953 * @param {Object} old The item being replaced.
12954 * @param {Object} new The new item.
12959 * Fires when an item is removed from the collection.
12960 * @param {Object} o The item being removed.
12961 * @param {String} key (optional) The key associated with the removed item.
12966 this.allowFunctions = allowFunctions === true;
12968 this.getKey = keyFn;
12970 Roo.util.MixedCollection.superclass.constructor.call(this);
12973 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12974 allowFunctions : false,
12977 * Adds an item to the collection.
12978 * @param {String} key The key to associate with the item
12979 * @param {Object} o The item to add.
12980 * @return {Object} The item added.
12982 add : function(key, o){
12983 if(arguments.length == 1){
12985 key = this.getKey(o);
12987 if(typeof key == "undefined" || key === null){
12989 this.items.push(o);
12990 this.keys.push(null);
12992 var old = this.map[key];
12994 return this.replace(key, o);
12997 this.items.push(o);
12999 this.keys.push(key);
13001 this.fireEvent("add", this.length-1, o, key);
13006 * MixedCollection has a generic way to fetch keys if you implement getKey.
13009 var mc = new Roo.util.MixedCollection();
13010 mc.add(someEl.dom.id, someEl);
13011 mc.add(otherEl.dom.id, otherEl);
13015 var mc = new Roo.util.MixedCollection();
13016 mc.getKey = function(el){
13022 // or via the constructor
13023 var mc = new Roo.util.MixedCollection(false, function(el){
13029 * @param o {Object} The item for which to find the key.
13030 * @return {Object} The key for the passed item.
13032 getKey : function(o){
13037 * Replaces an item in the collection.
13038 * @param {String} key The key associated with the item to replace, or the item to replace.
13039 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13040 * @return {Object} The new item.
13042 replace : function(key, o){
13043 if(arguments.length == 1){
13045 key = this.getKey(o);
13047 var old = this.item(key);
13048 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13049 return this.add(key, o);
13051 var index = this.indexOfKey(key);
13052 this.items[index] = o;
13054 this.fireEvent("replace", key, old, o);
13059 * Adds all elements of an Array or an Object to the collection.
13060 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13061 * an Array of values, each of which are added to the collection.
13063 addAll : function(objs){
13064 if(arguments.length > 1 || objs instanceof Array){
13065 var args = arguments.length > 1 ? arguments : objs;
13066 for(var i = 0, len = args.length; i < len; i++){
13070 for(var key in objs){
13071 if(this.allowFunctions || typeof objs[key] != "function"){
13072 this.add(key, objs[key]);
13079 * Executes the specified function once for every item in the collection, passing each
13080 * item as the first and only parameter. returning false from the function will stop the iteration.
13081 * @param {Function} fn The function to execute for each item.
13082 * @param {Object} scope (optional) The scope in which to execute the function.
13084 each : function(fn, scope){
13085 var items = [].concat(this.items); // each safe for removal
13086 for(var i = 0, len = items.length; i < len; i++){
13087 if(fn.call(scope || items[i], items[i], i, len) === false){
13094 * Executes the specified function once for every key in the collection, passing each
13095 * key, and its associated item as the first two parameters.
13096 * @param {Function} fn The function to execute for each item.
13097 * @param {Object} scope (optional) The scope in which to execute the function.
13099 eachKey : function(fn, scope){
13100 for(var i = 0, len = this.keys.length; i < len; i++){
13101 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13106 * Returns the first item in the collection which elicits a true return value from the
13107 * passed selection function.
13108 * @param {Function} fn The selection function to execute for each item.
13109 * @param {Object} scope (optional) The scope in which to execute the function.
13110 * @return {Object} The first item in the collection which returned true from the selection function.
13112 find : function(fn, scope){
13113 for(var i = 0, len = this.items.length; i < len; i++){
13114 if(fn.call(scope || window, this.items[i], this.keys[i])){
13115 return this.items[i];
13122 * Inserts an item at the specified index in the collection.
13123 * @param {Number} index The index to insert the item at.
13124 * @param {String} key The key to associate with the new item, or the item itself.
13125 * @param {Object} o (optional) If the second parameter was a key, the new item.
13126 * @return {Object} The item inserted.
13128 insert : function(index, key, o){
13129 if(arguments.length == 2){
13131 key = this.getKey(o);
13133 if(index >= this.length){
13134 return this.add(key, o);
13137 this.items.splice(index, 0, o);
13138 if(typeof key != "undefined" && key != null){
13141 this.keys.splice(index, 0, key);
13142 this.fireEvent("add", index, o, key);
13147 * Removed an item from the collection.
13148 * @param {Object} o The item to remove.
13149 * @return {Object} The item removed.
13151 remove : function(o){
13152 return this.removeAt(this.indexOf(o));
13156 * Remove an item from a specified index in the collection.
13157 * @param {Number} index The index within the collection of the item to remove.
13159 removeAt : function(index){
13160 if(index < this.length && index >= 0){
13162 var o = this.items[index];
13163 this.items.splice(index, 1);
13164 var key = this.keys[index];
13165 if(typeof key != "undefined"){
13166 delete this.map[key];
13168 this.keys.splice(index, 1);
13169 this.fireEvent("remove", o, key);
13174 * Removed an item associated with the passed key fom the collection.
13175 * @param {String} key The key of the item to remove.
13177 removeKey : function(key){
13178 return this.removeAt(this.indexOfKey(key));
13182 * Returns the number of items in the collection.
13183 * @return {Number} the number of items in the collection.
13185 getCount : function(){
13186 return this.length;
13190 * Returns index within the collection of the passed Object.
13191 * @param {Object} o The item to find the index of.
13192 * @return {Number} index of the item.
13194 indexOf : function(o){
13195 if(!this.items.indexOf){
13196 for(var i = 0, len = this.items.length; i < len; i++){
13197 if(this.items[i] == o) {
13203 return this.items.indexOf(o);
13208 * Returns index within the collection of the passed key.
13209 * @param {String} key The key to find the index of.
13210 * @return {Number} index of the key.
13212 indexOfKey : function(key){
13213 if(!this.keys.indexOf){
13214 for(var i = 0, len = this.keys.length; i < len; i++){
13215 if(this.keys[i] == key) {
13221 return this.keys.indexOf(key);
13226 * Returns the item associated with the passed key OR index. Key has priority over index.
13227 * @param {String/Number} key The key or index of the item.
13228 * @return {Object} The item associated with the passed key.
13230 item : function(key){
13231 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13232 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13236 * Returns the item at the specified index.
13237 * @param {Number} index The index of the item.
13240 itemAt : function(index){
13241 return this.items[index];
13245 * Returns the item associated with the passed key.
13246 * @param {String/Number} key The key of the item.
13247 * @return {Object} The item associated with the passed key.
13249 key : function(key){
13250 return this.map[key];
13254 * Returns true if the collection contains the passed Object as an item.
13255 * @param {Object} o The Object to look for in the collection.
13256 * @return {Boolean} True if the collection contains the Object as an item.
13258 contains : function(o){
13259 return this.indexOf(o) != -1;
13263 * Returns true if the collection contains the passed Object as a key.
13264 * @param {String} key The key to look for in the collection.
13265 * @return {Boolean} True if the collection contains the Object as a key.
13267 containsKey : function(key){
13268 return typeof this.map[key] != "undefined";
13272 * Removes all items from the collection.
13274 clear : function(){
13279 this.fireEvent("clear");
13283 * Returns the first item in the collection.
13284 * @return {Object} the first item in the collection..
13286 first : function(){
13287 return this.items[0];
13291 * Returns the last item in the collection.
13292 * @return {Object} the last item in the collection..
13295 return this.items[this.length-1];
13298 _sort : function(property, dir, fn){
13299 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13300 fn = fn || function(a, b){
13303 var c = [], k = this.keys, items = this.items;
13304 for(var i = 0, len = items.length; i < len; i++){
13305 c[c.length] = {key: k[i], value: items[i], index: i};
13307 c.sort(function(a, b){
13308 var v = fn(a[property], b[property]) * dsc;
13310 v = (a.index < b.index ? -1 : 1);
13314 for(var i = 0, len = c.length; i < len; i++){
13315 items[i] = c[i].value;
13318 this.fireEvent("sort", this);
13322 * Sorts this collection with the passed comparison function
13323 * @param {String} direction (optional) "ASC" or "DESC"
13324 * @param {Function} fn (optional) comparison function
13326 sort : function(dir, fn){
13327 this._sort("value", dir, fn);
13331 * Sorts this collection by keys
13332 * @param {String} direction (optional) "ASC" or "DESC"
13333 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13335 keySort : function(dir, fn){
13336 this._sort("key", dir, fn || function(a, b){
13337 return String(a).toUpperCase()-String(b).toUpperCase();
13342 * Returns a range of items in this collection
13343 * @param {Number} startIndex (optional) defaults to 0
13344 * @param {Number} endIndex (optional) default to the last item
13345 * @return {Array} An array of items
13347 getRange : function(start, end){
13348 var items = this.items;
13349 if(items.length < 1){
13352 start = start || 0;
13353 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13356 for(var i = start; i <= end; i++) {
13357 r[r.length] = items[i];
13360 for(var i = start; i >= end; i--) {
13361 r[r.length] = items[i];
13368 * Filter the <i>objects</i> in this collection by a specific property.
13369 * Returns a new collection that has been filtered.
13370 * @param {String} property A property on your objects
13371 * @param {String/RegExp} value Either string that the property values
13372 * should start with or a RegExp to test against the property
13373 * @return {MixedCollection} The new filtered collection
13375 filter : function(property, value){
13376 if(!value.exec){ // not a regex
13377 value = String(value);
13378 if(value.length == 0){
13379 return this.clone();
13381 value = new RegExp("^" + Roo.escapeRe(value), "i");
13383 return this.filterBy(function(o){
13384 return o && value.test(o[property]);
13389 * Filter by a function. * Returns a new collection that has been filtered.
13390 * The passed function will be called with each
13391 * object in the collection. If the function returns true, the value is included
13392 * otherwise it is filtered.
13393 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13394 * @param {Object} scope (optional) The scope of the function (defaults to this)
13395 * @return {MixedCollection} The new filtered collection
13397 filterBy : function(fn, scope){
13398 var r = new Roo.util.MixedCollection();
13399 r.getKey = this.getKey;
13400 var k = this.keys, it = this.items;
13401 for(var i = 0, len = it.length; i < len; i++){
13402 if(fn.call(scope||this, it[i], k[i])){
13403 r.add(k[i], it[i]);
13410 * Creates a duplicate of this collection
13411 * @return {MixedCollection}
13413 clone : function(){
13414 var r = new Roo.util.MixedCollection();
13415 var k = this.keys, it = this.items;
13416 for(var i = 0, len = it.length; i < len; i++){
13417 r.add(k[i], it[i]);
13419 r.getKey = this.getKey;
13424 * Returns the item associated with the passed key or index.
13426 * @param {String/Number} key The key or index of the item.
13427 * @return {Object} The item associated with the passed key.
13429 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13431 * Ext JS Library 1.1.1
13432 * Copyright(c) 2006-2007, Ext JS, LLC.
13434 * Originally Released Under LGPL - original licence link has changed is not relivant.
13437 * <script type="text/javascript">
13440 * @class Roo.util.JSON
13441 * Modified version of Douglas Crockford"s json.js that doesn"t
13442 * mess with the Object prototype
13443 * http://www.json.org/js.html
13446 Roo.util.JSON = new (function(){
13447 var useHasOwn = {}.hasOwnProperty ? true : false;
13449 // crashes Safari in some instances
13450 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13452 var pad = function(n) {
13453 return n < 10 ? "0" + n : n;
13466 var encodeString = function(s){
13467 if (/["\\\x00-\x1f]/.test(s)) {
13468 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13473 c = b.charCodeAt();
13475 Math.floor(c / 16).toString(16) +
13476 (c % 16).toString(16);
13479 return '"' + s + '"';
13482 var encodeArray = function(o){
13483 var a = ["["], b, i, l = o.length, v;
13484 for (i = 0; i < l; i += 1) {
13486 switch (typeof v) {
13495 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13503 var encodeDate = function(o){
13504 return '"' + o.getFullYear() + "-" +
13505 pad(o.getMonth() + 1) + "-" +
13506 pad(o.getDate()) + "T" +
13507 pad(o.getHours()) + ":" +
13508 pad(o.getMinutes()) + ":" +
13509 pad(o.getSeconds()) + '"';
13513 * Encodes an Object, Array or other value
13514 * @param {Mixed} o The variable to encode
13515 * @return {String} The JSON string
13517 this.encode = function(o)
13519 // should this be extended to fully wrap stringify..
13521 if(typeof o == "undefined" || o === null){
13523 }else if(o instanceof Array){
13524 return encodeArray(o);
13525 }else if(o instanceof Date){
13526 return encodeDate(o);
13527 }else if(typeof o == "string"){
13528 return encodeString(o);
13529 }else if(typeof o == "number"){
13530 return isFinite(o) ? String(o) : "null";
13531 }else if(typeof o == "boolean"){
13534 var a = ["{"], b, i, v;
13536 if(!useHasOwn || o.hasOwnProperty(i)) {
13538 switch (typeof v) {
13547 a.push(this.encode(i), ":",
13548 v === null ? "null" : this.encode(v));
13559 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13560 * @param {String} json The JSON string
13561 * @return {Object} The resulting object
13563 this.decode = function(json){
13565 return /** eval:var:json */ eval("(" + json + ')');
13569 * Shorthand for {@link Roo.util.JSON#encode}
13570 * @member Roo encode
13572 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13574 * Shorthand for {@link Roo.util.JSON#decode}
13575 * @member Roo decode
13577 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13580 * Ext JS Library 1.1.1
13581 * Copyright(c) 2006-2007, Ext JS, LLC.
13583 * Originally Released Under LGPL - original licence link has changed is not relivant.
13586 * <script type="text/javascript">
13590 * @class Roo.util.Format
13591 * Reusable data formatting functions
13594 Roo.util.Format = function(){
13595 var trimRe = /^\s+|\s+$/g;
13598 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13599 * @param {String} value The string to truncate
13600 * @param {Number} length The maximum length to allow before truncating
13601 * @return {String} The converted text
13603 ellipsis : function(value, len){
13604 if(value && value.length > len){
13605 return value.substr(0, len-3)+"...";
13611 * Checks a reference and converts it to empty string if it is undefined
13612 * @param {Mixed} value Reference to check
13613 * @return {Mixed} Empty string if converted, otherwise the original value
13615 undef : function(value){
13616 return typeof value != "undefined" ? value : "";
13620 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13621 * @param {String} value The string to encode
13622 * @return {String} The encoded text
13624 htmlEncode : function(value){
13625 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13629 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13630 * @param {String} value The string to decode
13631 * @return {String} The decoded text
13633 htmlDecode : function(value){
13634 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13638 * Trims any whitespace from either side of a string
13639 * @param {String} value The text to trim
13640 * @return {String} The trimmed text
13642 trim : function(value){
13643 return String(value).replace(trimRe, "");
13647 * Returns a substring from within an original string
13648 * @param {String} value The original text
13649 * @param {Number} start The start index of the substring
13650 * @param {Number} length The length of the substring
13651 * @return {String} The substring
13653 substr : function(value, start, length){
13654 return String(value).substr(start, length);
13658 * Converts a string to all lower case letters
13659 * @param {String} value The text to convert
13660 * @return {String} The converted text
13662 lowercase : function(value){
13663 return String(value).toLowerCase();
13667 * Converts a string to all upper case letters
13668 * @param {String} value The text to convert
13669 * @return {String} The converted text
13671 uppercase : function(value){
13672 return String(value).toUpperCase();
13676 * Converts the first character only of a string to upper case
13677 * @param {String} value The text to convert
13678 * @return {String} The converted text
13680 capitalize : function(value){
13681 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13685 call : function(value, fn){
13686 if(arguments.length > 2){
13687 var args = Array.prototype.slice.call(arguments, 2);
13688 args.unshift(value);
13690 return /** eval:var:value */ eval(fn).apply(window, args);
13692 /** eval:var:value */
13693 return /** eval:var:value */ eval(fn).call(window, value);
13699 * safer version of Math.toFixed..??/
13700 * @param {Number/String} value The numeric value to format
13701 * @param {Number/String} value Decimal places
13702 * @return {String} The formatted currency string
13704 toFixed : function(v, n)
13706 // why not use to fixed - precision is buggered???
13708 return Math.round(v-0);
13710 var fact = Math.pow(10,n+1);
13711 v = (Math.round((v-0)*fact))/fact;
13712 var z = (''+fact).substring(2);
13713 if (v == Math.floor(v)) {
13714 return Math.floor(v) + '.' + z;
13717 // now just padd decimals..
13718 var ps = String(v).split('.');
13719 var fd = (ps[1] + z);
13720 var r = fd.substring(0,n);
13721 var rm = fd.substring(n);
13723 return ps[0] + '.' + r;
13725 r*=1; // turn it into a number;
13727 if (String(r).length != n) {
13730 r = String(r).substring(1); // chop the end off.
13733 return ps[0] + '.' + r;
13738 * Format a number as US currency
13739 * @param {Number/String} value The numeric value to format
13740 * @return {String} The formatted currency string
13742 usMoney : function(v){
13743 return '$' + Roo.util.Format.number(v);
13748 * eventually this should probably emulate php's number_format
13749 * @param {Number/String} value The numeric value to format
13750 * @param {Number} decimals number of decimal places
13751 * @return {String} The formatted currency string
13753 number : function(v,decimals)
13755 // multiply and round.
13756 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13757 var mul = Math.pow(10, decimals);
13758 var zero = String(mul).substring(1);
13759 v = (Math.round((v-0)*mul))/mul;
13761 // if it's '0' number.. then
13763 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13765 var ps = v.split('.');
13769 var r = /(\d+)(\d{3})/;
13771 while (r.test(whole)) {
13772 whole = whole.replace(r, '$1' + ',' + '$2');
13778 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13779 // does not have decimals
13780 (decimals ? ('.' + zero) : '');
13783 return whole + sub ;
13787 * Parse a value into a formatted date using the specified format pattern.
13788 * @param {Mixed} value The value to format
13789 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13790 * @return {String} The formatted date string
13792 date : function(v, format){
13796 if(!(v instanceof Date)){
13797 v = new Date(Date.parse(v));
13799 return v.dateFormat(format || Roo.util.Format.defaults.date);
13803 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13804 * @param {String} format Any valid date format string
13805 * @return {Function} The date formatting function
13807 dateRenderer : function(format){
13808 return function(v){
13809 return Roo.util.Format.date(v, format);
13814 stripTagsRE : /<\/?[^>]+>/gi,
13817 * Strips all HTML tags
13818 * @param {Mixed} value The text from which to strip tags
13819 * @return {String} The stripped text
13821 stripTags : function(v){
13822 return !v ? v : String(v).replace(this.stripTagsRE, "");
13826 Roo.util.Format.defaults = {
13830 * Ext JS Library 1.1.1
13831 * Copyright(c) 2006-2007, Ext JS, LLC.
13833 * Originally Released Under LGPL - original licence link has changed is not relivant.
13836 * <script type="text/javascript">
13843 * @class Roo.MasterTemplate
13844 * @extends Roo.Template
13845 * Provides a template that can have child templates. The syntax is:
13847 var t = new Roo.MasterTemplate(
13848 '<select name="{name}">',
13849 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13852 t.add('options', {value: 'foo', text: 'bar'});
13853 // or you can add multiple child elements in one shot
13854 t.addAll('options', [
13855 {value: 'foo', text: 'bar'},
13856 {value: 'foo2', text: 'bar2'},
13857 {value: 'foo3', text: 'bar3'}
13859 // then append, applying the master template values
13860 t.append('my-form', {name: 'my-select'});
13862 * A name attribute for the child template is not required if you have only one child
13863 * template or you want to refer to them by index.
13865 Roo.MasterTemplate = function(){
13866 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13867 this.originalHtml = this.html;
13869 var m, re = this.subTemplateRe;
13872 while(m = re.exec(this.html)){
13873 var name = m[1], content = m[2];
13878 tpl : new Roo.Template(content)
13881 st[name] = st[subIndex];
13883 st[subIndex].tpl.compile();
13884 st[subIndex].tpl.call = this.call.createDelegate(this);
13887 this.subCount = subIndex;
13890 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13892 * The regular expression used to match sub templates
13896 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13899 * Applies the passed values to a child template.
13900 * @param {String/Number} name (optional) The name or index of the child template
13901 * @param {Array/Object} values The values to be applied to the template
13902 * @return {MasterTemplate} this
13904 add : function(name, values){
13905 if(arguments.length == 1){
13906 values = arguments[0];
13909 var s = this.subs[name];
13910 s.buffer[s.buffer.length] = s.tpl.apply(values);
13915 * Applies all the passed values to a child template.
13916 * @param {String/Number} name (optional) The name or index of the child template
13917 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13918 * @param {Boolean} reset (optional) True to reset the template first
13919 * @return {MasterTemplate} this
13921 fill : function(name, values, reset){
13923 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13931 for(var i = 0, len = values.length; i < len; i++){
13932 this.add(name, values[i]);
13938 * Resets the template for reuse
13939 * @return {MasterTemplate} this
13941 reset : function(){
13943 for(var i = 0; i < this.subCount; i++){
13949 applyTemplate : function(values){
13951 var replaceIndex = -1;
13952 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13953 return s[++replaceIndex].buffer.join("");
13955 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13958 apply : function(){
13959 return this.applyTemplate.apply(this, arguments);
13962 compile : function(){return this;}
13966 * Alias for fill().
13969 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13971 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13972 * var tpl = Roo.MasterTemplate.from('element-id');
13973 * @param {String/HTMLElement} el
13974 * @param {Object} config
13977 Roo.MasterTemplate.from = function(el, config){
13978 el = Roo.getDom(el);
13979 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13982 * Ext JS Library 1.1.1
13983 * Copyright(c) 2006-2007, Ext JS, LLC.
13985 * Originally Released Under LGPL - original licence link has changed is not relivant.
13988 * <script type="text/javascript">
13993 * @class Roo.util.CSS
13994 * Utility class for manipulating CSS rules
13997 Roo.util.CSS = function(){
13999 var doc = document;
14001 var camelRe = /(-[a-z])/gi;
14002 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14006 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14007 * tag and appended to the HEAD of the document.
14008 * @param {String|Object} cssText The text containing the css rules
14009 * @param {String} id An id to add to the stylesheet for later removal
14010 * @return {StyleSheet}
14012 createStyleSheet : function(cssText, id){
14014 var head = doc.getElementsByTagName("head")[0];
14015 var nrules = doc.createElement("style");
14016 nrules.setAttribute("type", "text/css");
14018 nrules.setAttribute("id", id);
14020 if (typeof(cssText) != 'string') {
14021 // support object maps..
14022 // not sure if this a good idea..
14023 // perhaps it should be merged with the general css handling
14024 // and handle js style props.
14025 var cssTextNew = [];
14026 for(var n in cssText) {
14028 for(var k in cssText[n]) {
14029 citems.push( k + ' : ' +cssText[n][k] + ';' );
14031 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14034 cssText = cssTextNew.join("\n");
14040 head.appendChild(nrules);
14041 ss = nrules.styleSheet;
14042 ss.cssText = cssText;
14045 nrules.appendChild(doc.createTextNode(cssText));
14047 nrules.cssText = cssText;
14049 head.appendChild(nrules);
14050 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14052 this.cacheStyleSheet(ss);
14057 * Removes a style or link tag by id
14058 * @param {String} id The id of the tag
14060 removeStyleSheet : function(id){
14061 var existing = doc.getElementById(id);
14063 existing.parentNode.removeChild(existing);
14068 * Dynamically swaps an existing stylesheet reference for a new one
14069 * @param {String} id The id of an existing link tag to remove
14070 * @param {String} url The href of the new stylesheet to include
14072 swapStyleSheet : function(id, url){
14073 this.removeStyleSheet(id);
14074 var ss = doc.createElement("link");
14075 ss.setAttribute("rel", "stylesheet");
14076 ss.setAttribute("type", "text/css");
14077 ss.setAttribute("id", id);
14078 ss.setAttribute("href", url);
14079 doc.getElementsByTagName("head")[0].appendChild(ss);
14083 * Refresh the rule cache if you have dynamically added stylesheets
14084 * @return {Object} An object (hash) of rules indexed by selector
14086 refreshCache : function(){
14087 return this.getRules(true);
14091 cacheStyleSheet : function(stylesheet){
14095 try{// try catch for cross domain access issue
14096 var ssRules = stylesheet.cssRules || stylesheet.rules;
14097 for(var j = ssRules.length-1; j >= 0; --j){
14098 rules[ssRules[j].selectorText] = ssRules[j];
14104 * Gets all css rules for the document
14105 * @param {Boolean} refreshCache true to refresh the internal cache
14106 * @return {Object} An object (hash) of rules indexed by selector
14108 getRules : function(refreshCache){
14109 if(rules == null || refreshCache){
14111 var ds = doc.styleSheets;
14112 for(var i =0, len = ds.length; i < len; i++){
14114 this.cacheStyleSheet(ds[i]);
14122 * Gets an an individual CSS rule by selector(s)
14123 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14124 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14125 * @return {CSSRule} The CSS rule or null if one is not found
14127 getRule : function(selector, refreshCache){
14128 var rs = this.getRules(refreshCache);
14129 if(!(selector instanceof Array)){
14130 return rs[selector];
14132 for(var i = 0; i < selector.length; i++){
14133 if(rs[selector[i]]){
14134 return rs[selector[i]];
14142 * Updates a rule property
14143 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14144 * @param {String} property The css property
14145 * @param {String} value The new value for the property
14146 * @return {Boolean} true If a rule was found and updated
14148 updateRule : function(selector, property, value){
14149 if(!(selector instanceof Array)){
14150 var rule = this.getRule(selector);
14152 rule.style[property.replace(camelRe, camelFn)] = value;
14156 for(var i = 0; i < selector.length; i++){
14157 if(this.updateRule(selector[i], property, value)){
14167 * Ext JS Library 1.1.1
14168 * Copyright(c) 2006-2007, Ext JS, LLC.
14170 * Originally Released Under LGPL - original licence link has changed is not relivant.
14173 * <script type="text/javascript">
14179 * @class Roo.util.ClickRepeater
14180 * @extends Roo.util.Observable
14182 * A wrapper class which can be applied to any element. Fires a "click" event while the
14183 * mouse is pressed. The interval between firings may be specified in the config but
14184 * defaults to 10 milliseconds.
14186 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14188 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14189 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14190 * Similar to an autorepeat key delay.
14191 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14192 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14193 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14194 * "interval" and "delay" are ignored. "immediate" is honored.
14195 * @cfg {Boolean} preventDefault True to prevent the default click event
14196 * @cfg {Boolean} stopDefault True to stop the default click event
14199 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14200 * 2007-02-02 jvs Renamed to ClickRepeater
14201 * 2007-02-03 jvs Modifications for FF Mac and Safari
14204 * @param {String/HTMLElement/Element} el The element to listen on
14205 * @param {Object} config
14207 Roo.util.ClickRepeater = function(el, config)
14209 this.el = Roo.get(el);
14210 this.el.unselectable();
14212 Roo.apply(this, config);
14217 * Fires when the mouse button is depressed.
14218 * @param {Roo.util.ClickRepeater} this
14220 "mousedown" : true,
14223 * Fires on a specified interval during the time the element is pressed.
14224 * @param {Roo.util.ClickRepeater} this
14229 * Fires when the mouse key is released.
14230 * @param {Roo.util.ClickRepeater} this
14235 this.el.on("mousedown", this.handleMouseDown, this);
14236 if(this.preventDefault || this.stopDefault){
14237 this.el.on("click", function(e){
14238 if(this.preventDefault){
14239 e.preventDefault();
14241 if(this.stopDefault){
14247 // allow inline handler
14249 this.on("click", this.handler, this.scope || this);
14252 Roo.util.ClickRepeater.superclass.constructor.call(this);
14255 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14258 preventDefault : true,
14259 stopDefault : false,
14263 handleMouseDown : function(){
14264 clearTimeout(this.timer);
14266 if(this.pressClass){
14267 this.el.addClass(this.pressClass);
14269 this.mousedownTime = new Date();
14271 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14272 this.el.on("mouseout", this.handleMouseOut, this);
14274 this.fireEvent("mousedown", this);
14275 this.fireEvent("click", this);
14277 this.timer = this.click.defer(this.delay || this.interval, this);
14281 click : function(){
14282 this.fireEvent("click", this);
14283 this.timer = this.click.defer(this.getInterval(), this);
14287 getInterval: function(){
14288 if(!this.accelerate){
14289 return this.interval;
14291 var pressTime = this.mousedownTime.getElapsed();
14292 if(pressTime < 500){
14294 }else if(pressTime < 1700){
14296 }else if(pressTime < 2600){
14298 }else if(pressTime < 3500){
14300 }else if(pressTime < 4400){
14302 }else if(pressTime < 5300){
14304 }else if(pressTime < 6200){
14312 handleMouseOut : function(){
14313 clearTimeout(this.timer);
14314 if(this.pressClass){
14315 this.el.removeClass(this.pressClass);
14317 this.el.on("mouseover", this.handleMouseReturn, this);
14321 handleMouseReturn : function(){
14322 this.el.un("mouseover", this.handleMouseReturn);
14323 if(this.pressClass){
14324 this.el.addClass(this.pressClass);
14330 handleMouseUp : function(){
14331 clearTimeout(this.timer);
14332 this.el.un("mouseover", this.handleMouseReturn);
14333 this.el.un("mouseout", this.handleMouseOut);
14334 Roo.get(document).un("mouseup", this.handleMouseUp);
14335 this.el.removeClass(this.pressClass);
14336 this.fireEvent("mouseup", this);
14340 * Ext JS Library 1.1.1
14341 * Copyright(c) 2006-2007, Ext JS, LLC.
14343 * Originally Released Under LGPL - original licence link has changed is not relivant.
14346 * <script type="text/javascript">
14351 * @class Roo.KeyNav
14352 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14353 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14354 * way to implement custom navigation schemes for any UI component.</p>
14355 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14356 * pageUp, pageDown, del, home, end. Usage:</p>
14358 var nav = new Roo.KeyNav("my-element", {
14359 "left" : function(e){
14360 this.moveLeft(e.ctrlKey);
14362 "right" : function(e){
14363 this.moveRight(e.ctrlKey);
14365 "enter" : function(e){
14372 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14373 * @param {Object} config The config
14375 Roo.KeyNav = function(el, config){
14376 this.el = Roo.get(el);
14377 Roo.apply(this, config);
14378 if(!this.disabled){
14379 this.disabled = true;
14384 Roo.KeyNav.prototype = {
14386 * @cfg {Boolean} disabled
14387 * True to disable this KeyNav instance (defaults to false)
14391 * @cfg {String} defaultEventAction
14392 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14393 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14394 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14396 defaultEventAction: "stopEvent",
14398 * @cfg {Boolean} forceKeyDown
14399 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14400 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14401 * handle keydown instead of keypress.
14403 forceKeyDown : false,
14406 prepareEvent : function(e){
14407 var k = e.getKey();
14408 var h = this.keyToHandler[k];
14409 //if(h && this[h]){
14410 // e.stopPropagation();
14412 if(Roo.isSafari && h && k >= 37 && k <= 40){
14418 relay : function(e){
14419 var k = e.getKey();
14420 var h = this.keyToHandler[k];
14422 if(this.doRelay(e, this[h], h) !== true){
14423 e[this.defaultEventAction]();
14429 doRelay : function(e, h, hname){
14430 return h.call(this.scope || this, e);
14433 // possible handlers
14447 // quick lookup hash
14464 * Enable this KeyNav
14466 enable: function(){
14468 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14469 // the EventObject will normalize Safari automatically
14470 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14471 this.el.on("keydown", this.relay, this);
14473 this.el.on("keydown", this.prepareEvent, this);
14474 this.el.on("keypress", this.relay, this);
14476 this.disabled = false;
14481 * Disable this KeyNav
14483 disable: function(){
14484 if(!this.disabled){
14485 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14486 this.el.un("keydown", this.relay);
14488 this.el.un("keydown", this.prepareEvent);
14489 this.el.un("keypress", this.relay);
14491 this.disabled = true;
14496 * Ext JS Library 1.1.1
14497 * Copyright(c) 2006-2007, Ext JS, LLC.
14499 * Originally Released Under LGPL - original licence link has changed is not relivant.
14502 * <script type="text/javascript">
14507 * @class Roo.KeyMap
14508 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14509 * The constructor accepts the same config object as defined by {@link #addBinding}.
14510 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14511 * combination it will call the function with this signature (if the match is a multi-key
14512 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14513 * A KeyMap can also handle a string representation of keys.<br />
14516 // map one key by key code
14517 var map = new Roo.KeyMap("my-element", {
14518 key: 13, // or Roo.EventObject.ENTER
14523 // map multiple keys to one action by string
14524 var map = new Roo.KeyMap("my-element", {
14530 // map multiple keys to multiple actions by strings and array of codes
14531 var map = new Roo.KeyMap("my-element", [
14534 fn: function(){ alert("Return was pressed"); }
14537 fn: function(){ alert('a, b or c was pressed'); }
14542 fn: function(){ alert('Control + shift + tab was pressed.'); }
14546 * <b>Note: A KeyMap starts enabled</b>
14548 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14549 * @param {Object} config The config (see {@link #addBinding})
14550 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14552 Roo.KeyMap = function(el, config, eventName){
14553 this.el = Roo.get(el);
14554 this.eventName = eventName || "keydown";
14555 this.bindings = [];
14557 this.addBinding(config);
14562 Roo.KeyMap.prototype = {
14564 * True to stop the event from bubbling and prevent the default browser action if the
14565 * key was handled by the KeyMap (defaults to false)
14571 * Add a new binding to this KeyMap. The following config object properties are supported:
14573 Property Type Description
14574 ---------- --------------- ----------------------------------------------------------------------
14575 key String/Array A single keycode or an array of keycodes to handle
14576 shift Boolean True to handle key only when shift is pressed (defaults to false)
14577 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14578 alt Boolean True to handle key only when alt is pressed (defaults to false)
14579 fn Function The function to call when KeyMap finds the expected key combination
14580 scope Object The scope of the callback function
14586 var map = new Roo.KeyMap(document, {
14587 key: Roo.EventObject.ENTER,
14592 //Add a new binding to the existing KeyMap later
14600 * @param {Object/Array} config A single KeyMap config or an array of configs
14602 addBinding : function(config){
14603 if(config instanceof Array){
14604 for(var i = 0, len = config.length; i < len; i++){
14605 this.addBinding(config[i]);
14609 var keyCode = config.key,
14610 shift = config.shift,
14611 ctrl = config.ctrl,
14614 scope = config.scope;
14615 if(typeof keyCode == "string"){
14617 var keyString = keyCode.toUpperCase();
14618 for(var j = 0, len = keyString.length; j < len; j++){
14619 ks.push(keyString.charCodeAt(j));
14623 var keyArray = keyCode instanceof Array;
14624 var handler = function(e){
14625 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14626 var k = e.getKey();
14628 for(var i = 0, len = keyCode.length; i < len; i++){
14629 if(keyCode[i] == k){
14630 if(this.stopEvent){
14633 fn.call(scope || window, k, e);
14639 if(this.stopEvent){
14642 fn.call(scope || window, k, e);
14647 this.bindings.push(handler);
14651 * Shorthand for adding a single key listener
14652 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14653 * following options:
14654 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14655 * @param {Function} fn The function to call
14656 * @param {Object} scope (optional) The scope of the function
14658 on : function(key, fn, scope){
14659 var keyCode, shift, ctrl, alt;
14660 if(typeof key == "object" && !(key instanceof Array)){
14679 handleKeyDown : function(e){
14680 if(this.enabled){ //just in case
14681 var b = this.bindings;
14682 for(var i = 0, len = b.length; i < len; i++){
14683 b[i].call(this, e);
14689 * Returns true if this KeyMap is enabled
14690 * @return {Boolean}
14692 isEnabled : function(){
14693 return this.enabled;
14697 * Enables this KeyMap
14699 enable: function(){
14701 this.el.on(this.eventName, this.handleKeyDown, this);
14702 this.enabled = true;
14707 * Disable this KeyMap
14709 disable: function(){
14711 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14712 this.enabled = false;
14717 * Ext JS Library 1.1.1
14718 * Copyright(c) 2006-2007, Ext JS, LLC.
14720 * Originally Released Under LGPL - original licence link has changed is not relivant.
14723 * <script type="text/javascript">
14728 * @class Roo.util.TextMetrics
14729 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14730 * wide, in pixels, a given block of text will be.
14733 Roo.util.TextMetrics = function(){
14737 * Measures the size of the specified text
14738 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14739 * that can affect the size of the rendered text
14740 * @param {String} text The text to measure
14741 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14742 * in order to accurately measure the text height
14743 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14745 measure : function(el, text, fixedWidth){
14747 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14750 shared.setFixedWidth(fixedWidth || 'auto');
14751 return shared.getSize(text);
14755 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14756 * the overhead of multiple calls to initialize the style properties on each measurement.
14757 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14758 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14759 * in order to accurately measure the text height
14760 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14762 createInstance : function(el, fixedWidth){
14763 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14770 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14771 var ml = new Roo.Element(document.createElement('div'));
14772 document.body.appendChild(ml.dom);
14773 ml.position('absolute');
14774 ml.setLeftTop(-1000, -1000);
14778 ml.setWidth(fixedWidth);
14783 * Returns the size of the specified text based on the internal element's style and width properties
14784 * @memberOf Roo.util.TextMetrics.Instance#
14785 * @param {String} text The text to measure
14786 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14788 getSize : function(text){
14790 var s = ml.getSize();
14796 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14797 * that can affect the size of the rendered text
14798 * @memberOf Roo.util.TextMetrics.Instance#
14799 * @param {String/HTMLElement} el The element, dom node or id
14801 bind : function(el){
14803 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14808 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14809 * to set a fixed width in order to accurately measure the text height.
14810 * @memberOf Roo.util.TextMetrics.Instance#
14811 * @param {Number} width The width to set on the element
14813 setFixedWidth : function(width){
14814 ml.setWidth(width);
14818 * Returns the measured width of the specified text
14819 * @memberOf Roo.util.TextMetrics.Instance#
14820 * @param {String} text The text to measure
14821 * @return {Number} width The width in pixels
14823 getWidth : function(text){
14824 ml.dom.style.width = 'auto';
14825 return this.getSize(text).width;
14829 * Returns the measured height of the specified text. For multiline text, be sure to call
14830 * {@link #setFixedWidth} if necessary.
14831 * @memberOf Roo.util.TextMetrics.Instance#
14832 * @param {String} text The text to measure
14833 * @return {Number} height The height in pixels
14835 getHeight : function(text){
14836 return this.getSize(text).height;
14840 instance.bind(bindTo);
14845 // backwards compat
14846 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14848 * Ext JS Library 1.1.1
14849 * Copyright(c) 2006-2007, Ext JS, LLC.
14851 * Originally Released Under LGPL - original licence link has changed is not relivant.
14854 * <script type="text/javascript">
14858 * @class Roo.state.Provider
14859 * Abstract base class for state provider implementations. This class provides methods
14860 * for encoding and decoding <b>typed</b> variables including dates and defines the
14861 * Provider interface.
14863 Roo.state.Provider = function(){
14865 * @event statechange
14866 * Fires when a state change occurs.
14867 * @param {Provider} this This state provider
14868 * @param {String} key The state key which was changed
14869 * @param {String} value The encoded value for the state
14872 "statechange": true
14875 Roo.state.Provider.superclass.constructor.call(this);
14877 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14879 * Returns the current value for a key
14880 * @param {String} name The key name
14881 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14882 * @return {Mixed} The state data
14884 get : function(name, defaultValue){
14885 return typeof this.state[name] == "undefined" ?
14886 defaultValue : this.state[name];
14890 * Clears a value from the state
14891 * @param {String} name The key name
14893 clear : function(name){
14894 delete this.state[name];
14895 this.fireEvent("statechange", this, name, null);
14899 * Sets the value for a key
14900 * @param {String} name The key name
14901 * @param {Mixed} value The value to set
14903 set : function(name, value){
14904 this.state[name] = value;
14905 this.fireEvent("statechange", this, name, value);
14909 * Decodes a string previously encoded with {@link #encodeValue}.
14910 * @param {String} value The value to decode
14911 * @return {Mixed} The decoded value
14913 decodeValue : function(cookie){
14914 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14915 var matches = re.exec(unescape(cookie));
14916 if(!matches || !matches[1]) {
14917 return; // non state cookie
14919 var type = matches[1];
14920 var v = matches[2];
14923 return parseFloat(v);
14925 return new Date(Date.parse(v));
14930 var values = v.split("^");
14931 for(var i = 0, len = values.length; i < len; i++){
14932 all.push(this.decodeValue(values[i]));
14937 var values = v.split("^");
14938 for(var i = 0, len = values.length; i < len; i++){
14939 var kv = values[i].split("=");
14940 all[kv[0]] = this.decodeValue(kv[1]);
14949 * Encodes a value including type information. Decode with {@link #decodeValue}.
14950 * @param {Mixed} value The value to encode
14951 * @return {String} The encoded value
14953 encodeValue : function(v){
14955 if(typeof v == "number"){
14957 }else if(typeof v == "boolean"){
14958 enc = "b:" + (v ? "1" : "0");
14959 }else if(v instanceof Date){
14960 enc = "d:" + v.toGMTString();
14961 }else if(v instanceof Array){
14963 for(var i = 0, len = v.length; i < len; i++){
14964 flat += this.encodeValue(v[i]);
14970 }else if(typeof v == "object"){
14973 if(typeof v[key] != "function"){
14974 flat += key + "=" + this.encodeValue(v[key]) + "^";
14977 enc = "o:" + flat.substring(0, flat.length-1);
14981 return escape(enc);
14987 * Ext JS Library 1.1.1
14988 * Copyright(c) 2006-2007, Ext JS, LLC.
14990 * Originally Released Under LGPL - original licence link has changed is not relivant.
14993 * <script type="text/javascript">
14996 * @class Roo.state.Manager
14997 * This is the global state manager. By default all components that are "state aware" check this class
14998 * for state information if you don't pass them a custom state provider. In order for this class
14999 * to be useful, it must be initialized with a provider when your application initializes.
15001 // in your initialization function
15003 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15005 // supposed you have a {@link Roo.BorderLayout}
15006 var layout = new Roo.BorderLayout(...);
15007 layout.restoreState();
15008 // or a {Roo.BasicDialog}
15009 var dialog = new Roo.BasicDialog(...);
15010 dialog.restoreState();
15014 Roo.state.Manager = function(){
15015 var provider = new Roo.state.Provider();
15019 * Configures the default state provider for your application
15020 * @param {Provider} stateProvider The state provider to set
15022 setProvider : function(stateProvider){
15023 provider = stateProvider;
15027 * Returns the current value for a key
15028 * @param {String} name The key name
15029 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15030 * @return {Mixed} The state data
15032 get : function(key, defaultValue){
15033 return provider.get(key, defaultValue);
15037 * Sets the value for a key
15038 * @param {String} name The key name
15039 * @param {Mixed} value The state data
15041 set : function(key, value){
15042 provider.set(key, value);
15046 * Clears a value from the state
15047 * @param {String} name The key name
15049 clear : function(key){
15050 provider.clear(key);
15054 * Gets the currently configured state provider
15055 * @return {Provider} The state provider
15057 getProvider : function(){
15064 * Ext JS Library 1.1.1
15065 * Copyright(c) 2006-2007, Ext JS, LLC.
15067 * Originally Released Under LGPL - original licence link has changed is not relivant.
15070 * <script type="text/javascript">
15073 * @class Roo.state.CookieProvider
15074 * @extends Roo.state.Provider
15075 * The default Provider implementation which saves state via cookies.
15078 var cp = new Roo.state.CookieProvider({
15080 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15081 domain: "roojs.com"
15083 Roo.state.Manager.setProvider(cp);
15085 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15086 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15087 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15088 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15089 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15090 * domain the page is running on including the 'www' like 'www.roojs.com')
15091 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15093 * Create a new CookieProvider
15094 * @param {Object} config The configuration object
15096 Roo.state.CookieProvider = function(config){
15097 Roo.state.CookieProvider.superclass.constructor.call(this);
15099 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15100 this.domain = null;
15101 this.secure = false;
15102 Roo.apply(this, config);
15103 this.state = this.readCookies();
15106 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15108 set : function(name, value){
15109 if(typeof value == "undefined" || value === null){
15113 this.setCookie(name, value);
15114 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15118 clear : function(name){
15119 this.clearCookie(name);
15120 Roo.state.CookieProvider.superclass.clear.call(this, name);
15124 readCookies : function(){
15126 var c = document.cookie + ";";
15127 var re = /\s?(.*?)=(.*?);/g;
15129 while((matches = re.exec(c)) != null){
15130 var name = matches[1];
15131 var value = matches[2];
15132 if(name && name.substring(0,3) == "ys-"){
15133 cookies[name.substr(3)] = this.decodeValue(value);
15140 setCookie : function(name, value){
15141 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15142 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15143 ((this.path == null) ? "" : ("; path=" + this.path)) +
15144 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15145 ((this.secure == true) ? "; secure" : "");
15149 clearCookie : function(name){
15150 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15151 ((this.path == null) ? "" : ("; path=" + this.path)) +
15152 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15153 ((this.secure == true) ? "; secure" : "");
15157 * Ext JS Library 1.1.1
15158 * Copyright(c) 2006-2007, Ext JS, LLC.
15160 * Originally Released Under LGPL - original licence link has changed is not relivant.
15163 * <script type="text/javascript">
15168 * @class Roo.ComponentMgr
15169 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15172 Roo.ComponentMgr = function(){
15173 var all = new Roo.util.MixedCollection();
15177 * Registers a component.
15178 * @param {Roo.Component} c The component
15180 register : function(c){
15185 * Unregisters a component.
15186 * @param {Roo.Component} c The component
15188 unregister : function(c){
15193 * Returns a component by id
15194 * @param {String} id The component id
15196 get : function(id){
15197 return all.get(id);
15201 * Registers a function that will be called when a specified component is added to ComponentMgr
15202 * @param {String} id The component id
15203 * @param {Funtction} fn The callback function
15204 * @param {Object} scope The scope of the callback
15206 onAvailable : function(id, fn, scope){
15207 all.on("add", function(index, o){
15209 fn.call(scope || o, o);
15210 all.un("add", fn, scope);
15217 * Ext JS Library 1.1.1
15218 * Copyright(c) 2006-2007, Ext JS, LLC.
15220 * Originally Released Under LGPL - original licence link has changed is not relivant.
15223 * <script type="text/javascript">
15227 * @class Roo.Component
15228 * @extends Roo.util.Observable
15229 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15230 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15231 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15232 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15233 * All visual components (widgets) that require rendering into a layout should subclass Component.
15235 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15236 * 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
15237 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15239 Roo.Component = function(config){
15240 config = config || {};
15241 if(config.tagName || config.dom || typeof config == "string"){ // element object
15242 config = {el: config, id: config.id || config};
15244 this.initialConfig = config;
15246 Roo.apply(this, config);
15250 * Fires after the component is disabled.
15251 * @param {Roo.Component} this
15256 * Fires after the component is enabled.
15257 * @param {Roo.Component} this
15261 * @event beforeshow
15262 * Fires before the component is shown. Return false to stop the show.
15263 * @param {Roo.Component} this
15268 * Fires after the component is shown.
15269 * @param {Roo.Component} this
15273 * @event beforehide
15274 * Fires before the component is hidden. Return false to stop the hide.
15275 * @param {Roo.Component} this
15280 * Fires after the component is hidden.
15281 * @param {Roo.Component} this
15285 * @event beforerender
15286 * Fires before the component is rendered. Return false to stop the render.
15287 * @param {Roo.Component} this
15289 beforerender : true,
15292 * Fires after the component is rendered.
15293 * @param {Roo.Component} this
15297 * @event beforedestroy
15298 * Fires before the component is destroyed. Return false to stop the destroy.
15299 * @param {Roo.Component} this
15301 beforedestroy : true,
15304 * Fires after the component is destroyed.
15305 * @param {Roo.Component} this
15310 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15312 Roo.ComponentMgr.register(this);
15313 Roo.Component.superclass.constructor.call(this);
15314 this.initComponent();
15315 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15316 this.render(this.renderTo);
15317 delete this.renderTo;
15322 Roo.Component.AUTO_ID = 1000;
15324 Roo.extend(Roo.Component, Roo.util.Observable, {
15326 * @scope Roo.Component.prototype
15328 * true if this component is hidden. Read-only.
15333 * true if this component is disabled. Read-only.
15338 * true if this component has been rendered. Read-only.
15342 /** @cfg {String} disableClass
15343 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15345 disabledClass : "x-item-disabled",
15346 /** @cfg {Boolean} allowDomMove
15347 * Whether the component can move the Dom node when rendering (defaults to true).
15349 allowDomMove : true,
15350 /** @cfg {String} hideMode (display|visibility)
15351 * How this component should hidden. Supported values are
15352 * "visibility" (css visibility), "offsets" (negative offset position) and
15353 * "display" (css display) - defaults to "display".
15355 hideMode: 'display',
15358 ctype : "Roo.Component",
15361 * @cfg {String} actionMode
15362 * which property holds the element that used for hide() / show() / disable() / enable()
15368 getActionEl : function(){
15369 return this[this.actionMode];
15372 initComponent : Roo.emptyFn,
15374 * If this is a lazy rendering component, render it to its container element.
15375 * @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.
15377 render : function(container, position){
15378 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15379 if(!container && this.el){
15380 this.el = Roo.get(this.el);
15381 container = this.el.dom.parentNode;
15382 this.allowDomMove = false;
15384 this.container = Roo.get(container);
15385 this.rendered = true;
15386 if(position !== undefined){
15387 if(typeof position == 'number'){
15388 position = this.container.dom.childNodes[position];
15390 position = Roo.getDom(position);
15393 this.onRender(this.container, position || null);
15395 this.el.addClass(this.cls);
15399 this.el.applyStyles(this.style);
15402 this.fireEvent("render", this);
15403 this.afterRender(this.container);
15415 // default function is not really useful
15416 onRender : function(ct, position){
15418 this.el = Roo.get(this.el);
15419 if(this.allowDomMove !== false){
15420 ct.dom.insertBefore(this.el.dom, position);
15426 getAutoCreate : function(){
15427 var cfg = typeof this.autoCreate == "object" ?
15428 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15429 if(this.id && !cfg.id){
15436 afterRender : Roo.emptyFn,
15439 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15440 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15442 destroy : function(){
15443 if(this.fireEvent("beforedestroy", this) !== false){
15444 this.purgeListeners();
15445 this.beforeDestroy();
15447 this.el.removeAllListeners();
15449 if(this.actionMode == "container"){
15450 this.container.remove();
15454 Roo.ComponentMgr.unregister(this);
15455 this.fireEvent("destroy", this);
15460 beforeDestroy : function(){
15465 onDestroy : function(){
15470 * Returns the underlying {@link Roo.Element}.
15471 * @return {Roo.Element} The element
15473 getEl : function(){
15478 * Returns the id of this component.
15481 getId : function(){
15486 * Try to focus this component.
15487 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15488 * @return {Roo.Component} this
15490 focus : function(selectText){
15493 if(selectText === true){
15494 this.el.dom.select();
15509 * Disable this component.
15510 * @return {Roo.Component} this
15512 disable : function(){
15516 this.disabled = true;
15517 this.fireEvent("disable", this);
15522 onDisable : function(){
15523 this.getActionEl().addClass(this.disabledClass);
15524 this.el.dom.disabled = true;
15528 * Enable this component.
15529 * @return {Roo.Component} this
15531 enable : function(){
15535 this.disabled = false;
15536 this.fireEvent("enable", this);
15541 onEnable : function(){
15542 this.getActionEl().removeClass(this.disabledClass);
15543 this.el.dom.disabled = false;
15547 * Convenience function for setting disabled/enabled by boolean.
15548 * @param {Boolean} disabled
15550 setDisabled : function(disabled){
15551 this[disabled ? "disable" : "enable"]();
15555 * Show this component.
15556 * @return {Roo.Component} this
15559 if(this.fireEvent("beforeshow", this) !== false){
15560 this.hidden = false;
15564 this.fireEvent("show", this);
15570 onShow : function(){
15571 var ae = this.getActionEl();
15572 if(this.hideMode == 'visibility'){
15573 ae.dom.style.visibility = "visible";
15574 }else if(this.hideMode == 'offsets'){
15575 ae.removeClass('x-hidden');
15577 ae.dom.style.display = "";
15582 * Hide this component.
15583 * @return {Roo.Component} this
15586 if(this.fireEvent("beforehide", this) !== false){
15587 this.hidden = true;
15591 this.fireEvent("hide", this);
15597 onHide : function(){
15598 var ae = this.getActionEl();
15599 if(this.hideMode == 'visibility'){
15600 ae.dom.style.visibility = "hidden";
15601 }else if(this.hideMode == 'offsets'){
15602 ae.addClass('x-hidden');
15604 ae.dom.style.display = "none";
15609 * Convenience function to hide or show this component by boolean.
15610 * @param {Boolean} visible True to show, false to hide
15611 * @return {Roo.Component} this
15613 setVisible: function(visible){
15623 * Returns true if this component is visible.
15625 isVisible : function(){
15626 return this.getActionEl().isVisible();
15629 cloneConfig : function(overrides){
15630 overrides = overrides || {};
15631 var id = overrides.id || Roo.id();
15632 var cfg = Roo.applyIf(overrides, this.initialConfig);
15633 cfg.id = id; // prevent dup id
15634 return new this.constructor(cfg);
15638 * Ext JS Library 1.1.1
15639 * Copyright(c) 2006-2007, Ext JS, LLC.
15641 * Originally Released Under LGPL - original licence link has changed is not relivant.
15644 * <script type="text/javascript">
15648 * @class Roo.BoxComponent
15649 * @extends Roo.Component
15650 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15651 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15652 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15653 * layout containers.
15655 * @param {Roo.Element/String/Object} config The configuration options.
15657 Roo.BoxComponent = function(config){
15658 Roo.Component.call(this, config);
15662 * Fires after the component is resized.
15663 * @param {Roo.Component} this
15664 * @param {Number} adjWidth The box-adjusted width that was set
15665 * @param {Number} adjHeight The box-adjusted height that was set
15666 * @param {Number} rawWidth The width that was originally specified
15667 * @param {Number} rawHeight The height that was originally specified
15672 * Fires after the component is moved.
15673 * @param {Roo.Component} this
15674 * @param {Number} x The new x position
15675 * @param {Number} y The new y position
15681 Roo.extend(Roo.BoxComponent, Roo.Component, {
15682 // private, set in afterRender to signify that the component has been rendered
15684 // private, used to defer height settings to subclasses
15685 deferHeight: false,
15686 /** @cfg {Number} width
15687 * width (optional) size of component
15689 /** @cfg {Number} height
15690 * height (optional) size of component
15694 * Sets the width and height of the component. This method fires the resize event. This method can accept
15695 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15696 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15697 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15698 * @return {Roo.BoxComponent} this
15700 setSize : function(w, h){
15701 // support for standard size objects
15702 if(typeof w == 'object'){
15707 if(!this.boxReady){
15713 // prevent recalcs when not needed
15714 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15717 this.lastSize = {width: w, height: h};
15719 var adj = this.adjustSize(w, h);
15720 var aw = adj.width, ah = adj.height;
15721 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15722 var rz = this.getResizeEl();
15723 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15724 rz.setSize(aw, ah);
15725 }else if(!this.deferHeight && ah !== undefined){
15727 }else if(aw !== undefined){
15730 this.onResize(aw, ah, w, h);
15731 this.fireEvent('resize', this, aw, ah, w, h);
15737 * Gets the current size of the component's underlying element.
15738 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15740 getSize : function(){
15741 return this.el.getSize();
15745 * Gets the current XY position of the component's underlying element.
15746 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15747 * @return {Array} The XY position of the element (e.g., [100, 200])
15749 getPosition : function(local){
15750 if(local === true){
15751 return [this.el.getLeft(true), this.el.getTop(true)];
15753 return this.xy || this.el.getXY();
15757 * Gets the current box measurements of the component's underlying element.
15758 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15759 * @returns {Object} box An object in the format {x, y, width, height}
15761 getBox : function(local){
15762 var s = this.el.getSize();
15764 s.x = this.el.getLeft(true);
15765 s.y = this.el.getTop(true);
15767 var xy = this.xy || this.el.getXY();
15775 * Sets the current box measurements of the component's underlying element.
15776 * @param {Object} box An object in the format {x, y, width, height}
15777 * @returns {Roo.BoxComponent} this
15779 updateBox : function(box){
15780 this.setSize(box.width, box.height);
15781 this.setPagePosition(box.x, box.y);
15786 getResizeEl : function(){
15787 return this.resizeEl || this.el;
15791 getPositionEl : function(){
15792 return this.positionEl || this.el;
15796 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15797 * This method fires the move event.
15798 * @param {Number} left The new left
15799 * @param {Number} top The new top
15800 * @returns {Roo.BoxComponent} this
15802 setPosition : function(x, y){
15805 if(!this.boxReady){
15808 var adj = this.adjustPosition(x, y);
15809 var ax = adj.x, ay = adj.y;
15811 var el = this.getPositionEl();
15812 if(ax !== undefined || ay !== undefined){
15813 if(ax !== undefined && ay !== undefined){
15814 el.setLeftTop(ax, ay);
15815 }else if(ax !== undefined){
15817 }else if(ay !== undefined){
15820 this.onPosition(ax, ay);
15821 this.fireEvent('move', this, ax, ay);
15827 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15828 * This method fires the move event.
15829 * @param {Number} x The new x position
15830 * @param {Number} y The new y position
15831 * @returns {Roo.BoxComponent} this
15833 setPagePosition : function(x, y){
15836 if(!this.boxReady){
15839 if(x === undefined || y === undefined){ // cannot translate undefined points
15842 var p = this.el.translatePoints(x, y);
15843 this.setPosition(p.left, p.top);
15848 onRender : function(ct, position){
15849 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15851 this.resizeEl = Roo.get(this.resizeEl);
15853 if(this.positionEl){
15854 this.positionEl = Roo.get(this.positionEl);
15859 afterRender : function(){
15860 Roo.BoxComponent.superclass.afterRender.call(this);
15861 this.boxReady = true;
15862 this.setSize(this.width, this.height);
15863 if(this.x || this.y){
15864 this.setPosition(this.x, this.y);
15866 if(this.pageX || this.pageY){
15867 this.setPagePosition(this.pageX, this.pageY);
15872 * Force the component's size to recalculate based on the underlying element's current height and width.
15873 * @returns {Roo.BoxComponent} this
15875 syncSize : function(){
15876 delete this.lastSize;
15877 this.setSize(this.el.getWidth(), this.el.getHeight());
15882 * Called after the component is resized, this method is empty by default but can be implemented by any
15883 * subclass that needs to perform custom logic after a resize occurs.
15884 * @param {Number} adjWidth The box-adjusted width that was set
15885 * @param {Number} adjHeight The box-adjusted height that was set
15886 * @param {Number} rawWidth The width that was originally specified
15887 * @param {Number} rawHeight The height that was originally specified
15889 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15894 * Called after the component is moved, this method is empty by default but can be implemented by any
15895 * subclass that needs to perform custom logic after a move occurs.
15896 * @param {Number} x The new x position
15897 * @param {Number} y The new y position
15899 onPosition : function(x, y){
15904 adjustSize : function(w, h){
15905 if(this.autoWidth){
15908 if(this.autoHeight){
15911 return {width : w, height: h};
15915 adjustPosition : function(x, y){
15916 return {x : x, y: y};
15919 * Original code for Roojs - LGPL
15920 * <script type="text/javascript">
15924 * @class Roo.XComponent
15925 * A delayed Element creator...
15926 * Or a way to group chunks of interface together.
15927 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15928 * used in conjunction with XComponent.build() it will create an instance of each element,
15929 * then call addxtype() to build the User interface.
15931 * Mypart.xyx = new Roo.XComponent({
15933 parent : 'Mypart.xyz', // empty == document.element.!!
15937 disabled : function() {}
15939 tree : function() { // return an tree of xtype declared components
15943 xtype : 'NestedLayoutPanel',
15950 * It can be used to build a big heiracy, with parent etc.
15951 * or you can just use this to render a single compoent to a dom element
15952 * MYPART.render(Roo.Element | String(id) | dom_element )
15959 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15960 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15962 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15964 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15965 * - if mulitple topModules exist, the last one is defined as the top module.
15969 * When the top level or multiple modules are to embedded into a existing HTML page,
15970 * the parent element can container '#id' of the element where the module will be drawn.
15974 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15975 * it relies more on a include mechanism, where sub modules are included into an outer page.
15976 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15978 * Bootstrap Roo Included elements
15980 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15981 * hence confusing the component builder as it thinks there are multiple top level elements.
15985 * @extends Roo.util.Observable
15987 * @param cfg {Object} configuration of component
15990 Roo.XComponent = function(cfg) {
15991 Roo.apply(this, cfg);
15995 * Fires when this the componnt is built
15996 * @param {Roo.XComponent} c the component
16001 this.region = this.region || 'center'; // default..
16002 Roo.XComponent.register(this);
16003 this.modules = false;
16004 this.el = false; // where the layout goes..
16008 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16011 * The created element (with Roo.factory())
16012 * @type {Roo.Layout}
16018 * for BC - use el in new code
16019 * @type {Roo.Layout}
16025 * for BC - use el in new code
16026 * @type {Roo.Layout}
16031 * @cfg {Function|boolean} disabled
16032 * If this module is disabled by some rule, return true from the funtion
16037 * @cfg {String} parent
16038 * Name of parent element which it get xtype added to..
16043 * @cfg {String} order
16044 * Used to set the order in which elements are created (usefull for multiple tabs)
16049 * @cfg {String} name
16050 * String to display while loading.
16054 * @cfg {String} region
16055 * Region to render component to (defaults to center)
16060 * @cfg {Array} items
16061 * A single item array - the first element is the root of the tree..
16062 * It's done this way to stay compatible with the Xtype system...
16068 * The method that retuns the tree of parts that make up this compoennt
16075 * render element to dom or tree
16076 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16079 render : function(el)
16083 var hp = this.parent ? 1 : 0;
16084 Roo.debug && Roo.log(this);
16086 var tree = this._tree ? this._tree() : this.tree();
16089 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16090 // if parent is a '#.....' string, then let's use that..
16091 var ename = this.parent.substr(1);
16092 this.parent = false;
16093 Roo.debug && Roo.log(ename);
16095 case 'bootstrap-body':
16096 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16097 // this is the BorderLayout standard?
16098 this.parent = { el : true };
16101 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16102 // need to insert stuff...
16104 el : new Roo.bootstrap.layout.Border({
16105 el : document.body,
16111 tabPosition: 'top',
16112 //resizeTabs: true,
16113 alwaysShowTabs: true,
16123 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16124 this.parent = { el : new Roo.bootstrap.Body() };
16125 Roo.debug && Roo.log("setting el to doc body");
16128 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16132 this.parent = { el : true};
16135 el = Roo.get(ename);
16136 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16137 this.parent = { el : true};
16144 if (!el && !this.parent) {
16145 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16150 Roo.debug && Roo.log("EL:");
16151 Roo.debug && Roo.log(el);
16152 Roo.debug && Roo.log("this.parent.el:");
16153 Roo.debug && Roo.log(this.parent.el);
16156 // altertive root elements ??? - we need a better way to indicate these.
16157 var is_alt = Roo.XComponent.is_alt ||
16158 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16159 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16160 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16164 if (!this.parent && is_alt) {
16165 //el = Roo.get(document.body);
16166 this.parent = { el : true };
16171 if (!this.parent) {
16173 Roo.debug && Roo.log("no parent - creating one");
16175 el = el ? Roo.get(el) : false;
16177 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16180 el : new Roo.bootstrap.layout.Border({
16181 el: el || document.body,
16187 tabPosition: 'top',
16188 //resizeTabs: true,
16189 alwaysShowTabs: false,
16192 overflow: 'visible'
16198 // it's a top level one..
16200 el : new Roo.BorderLayout(el || document.body, {
16205 tabPosition: 'top',
16206 //resizeTabs: true,
16207 alwaysShowTabs: el && hp? false : true,
16208 hideTabs: el || !hp ? true : false,
16216 if (!this.parent.el) {
16217 // probably an old style ctor, which has been disabled.
16221 // The 'tree' method is '_tree now'
16223 tree.region = tree.region || this.region;
16224 var is_body = false;
16225 if (this.parent.el === true) {
16226 // bootstrap... - body..
16230 this.parent.el = Roo.factory(tree);
16234 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16235 this.fireEvent('built', this);
16237 this.panel = this.el;
16238 this.layout = this.panel.layout;
16239 this.parentLayout = this.parent.layout || false;
16245 Roo.apply(Roo.XComponent, {
16247 * @property hideProgress
16248 * true to disable the building progress bar.. usefull on single page renders.
16251 hideProgress : false,
16253 * @property buildCompleted
16254 * True when the builder has completed building the interface.
16257 buildCompleted : false,
16260 * @property topModule
16261 * the upper most module - uses document.element as it's constructor.
16268 * @property modules
16269 * array of modules to be created by registration system.
16270 * @type {Array} of Roo.XComponent
16275 * @property elmodules
16276 * array of modules to be created by which use #ID
16277 * @type {Array} of Roo.XComponent
16284 * Is an alternative Root - normally used by bootstrap or other systems,
16285 * where the top element in the tree can wrap 'body'
16286 * @type {boolean} (default false)
16291 * @property build_from_html
16292 * Build elements from html - used by bootstrap HTML stuff
16293 * - this is cleared after build is completed
16294 * @type {boolean} (default false)
16297 build_from_html : false,
16299 * Register components to be built later.
16301 * This solves the following issues
16302 * - Building is not done on page load, but after an authentication process has occured.
16303 * - Interface elements are registered on page load
16304 * - Parent Interface elements may not be loaded before child, so this handles that..
16311 module : 'Pman.Tab.projectMgr',
16313 parent : 'Pman.layout',
16314 disabled : false, // or use a function..
16317 * * @param {Object} details about module
16319 register : function(obj) {
16321 Roo.XComponent.event.fireEvent('register', obj);
16322 switch(typeof(obj.disabled) ) {
16328 if ( obj.disabled() ) {
16334 if (obj.disabled) {
16340 this.modules.push(obj);
16344 * convert a string to an object..
16345 * eg. 'AAA.BBB' -> finds AAA.BBB
16349 toObject : function(str)
16351 if (!str || typeof(str) == 'object') {
16354 if (str.substring(0,1) == '#') {
16358 var ar = str.split('.');
16363 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16365 throw "Module not found : " + str;
16369 throw "Module not found : " + str;
16371 Roo.each(ar, function(e) {
16372 if (typeof(o[e]) == 'undefined') {
16373 throw "Module not found : " + str;
16384 * move modules into their correct place in the tree..
16387 preBuild : function ()
16390 Roo.each(this.modules , function (obj)
16392 Roo.XComponent.event.fireEvent('beforebuild', obj);
16394 var opar = obj.parent;
16396 obj.parent = this.toObject(opar);
16398 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16403 Roo.debug && Roo.log("GOT top level module");
16404 Roo.debug && Roo.log(obj);
16405 obj.modules = new Roo.util.MixedCollection(false,
16406 function(o) { return o.order + '' }
16408 this.topModule = obj;
16411 // parent is a string (usually a dom element name..)
16412 if (typeof(obj.parent) == 'string') {
16413 this.elmodules.push(obj);
16416 if (obj.parent.constructor != Roo.XComponent) {
16417 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16419 if (!obj.parent.modules) {
16420 obj.parent.modules = new Roo.util.MixedCollection(false,
16421 function(o) { return o.order + '' }
16424 if (obj.parent.disabled) {
16425 obj.disabled = true;
16427 obj.parent.modules.add(obj);
16432 * make a list of modules to build.
16433 * @return {Array} list of modules.
16436 buildOrder : function()
16439 var cmp = function(a,b) {
16440 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16442 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16443 throw "No top level modules to build";
16446 // make a flat list in order of modules to build.
16447 var mods = this.topModule ? [ this.topModule ] : [];
16450 // elmodules (is a list of DOM based modules )
16451 Roo.each(this.elmodules, function(e) {
16453 if (!this.topModule &&
16454 typeof(e.parent) == 'string' &&
16455 e.parent.substring(0,1) == '#' &&
16456 Roo.get(e.parent.substr(1))
16459 _this.topModule = e;
16465 // add modules to their parents..
16466 var addMod = function(m) {
16467 Roo.debug && Roo.log("build Order: add: " + m.name);
16470 if (m.modules && !m.disabled) {
16471 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16472 m.modules.keySort('ASC', cmp );
16473 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16475 m.modules.each(addMod);
16477 Roo.debug && Roo.log("build Order: no child modules");
16479 // not sure if this is used any more..
16481 m.finalize.name = m.name + " (clean up) ";
16482 mods.push(m.finalize);
16486 if (this.topModule && this.topModule.modules) {
16487 this.topModule.modules.keySort('ASC', cmp );
16488 this.topModule.modules.each(addMod);
16494 * Build the registered modules.
16495 * @param {Object} parent element.
16496 * @param {Function} optional method to call after module has been added.
16500 build : function(opts)
16503 if (typeof(opts) != 'undefined') {
16504 Roo.apply(this,opts);
16508 var mods = this.buildOrder();
16510 //this.allmods = mods;
16511 //Roo.debug && Roo.log(mods);
16513 if (!mods.length) { // should not happen
16514 throw "NO modules!!!";
16518 var msg = "Building Interface...";
16519 // flash it up as modal - so we store the mask!?
16520 if (!this.hideProgress && Roo.MessageBox) {
16521 Roo.MessageBox.show({ title: 'loading' });
16522 Roo.MessageBox.show({
16523 title: "Please wait...",
16532 var total = mods.length;
16535 var progressRun = function() {
16536 if (!mods.length) {
16537 Roo.debug && Roo.log('hide?');
16538 if (!this.hideProgress && Roo.MessageBox) {
16539 Roo.MessageBox.hide();
16541 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16543 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16549 var m = mods.shift();
16552 Roo.debug && Roo.log(m);
16553 // not sure if this is supported any more.. - modules that are are just function
16554 if (typeof(m) == 'function') {
16556 return progressRun.defer(10, _this);
16560 msg = "Building Interface " + (total - mods.length) +
16562 (m.name ? (' - ' + m.name) : '');
16563 Roo.debug && Roo.log(msg);
16564 if (!_this.hideProgress && Roo.MessageBox) {
16565 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16569 // is the module disabled?
16570 var disabled = (typeof(m.disabled) == 'function') ?
16571 m.disabled.call(m.module.disabled) : m.disabled;
16575 return progressRun(); // we do not update the display!
16583 // it's 10 on top level, and 1 on others??? why...
16584 return progressRun.defer(10, _this);
16587 progressRun.defer(1, _this);
16601 * wrapper for event.on - aliased later..
16602 * Typically use to register a event handler for register:
16604 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16613 Roo.XComponent.event = new Roo.util.Observable({
16617 * Fires when an Component is registered,
16618 * set the disable property on the Component to stop registration.
16619 * @param {Roo.XComponent} c the component being registerd.
16624 * @event beforebuild
16625 * Fires before each Component is built
16626 * can be used to apply permissions.
16627 * @param {Roo.XComponent} c the component being registerd.
16630 'beforebuild' : true,
16632 * @event buildcomplete
16633 * Fires on the top level element when all elements have been built
16634 * @param {Roo.XComponent} the top level component.
16636 'buildcomplete' : true
16641 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16644 * marked - a markdown parser
16645 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16646 * https://github.com/chjj/marked
16652 * Roo.Markdown - is a very crude wrapper around marked..
16656 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16658 * Note: move the sample code to the bottom of this
16659 * file before uncommenting it.
16664 Roo.Markdown.toHtml = function(text) {
16666 var c = new Roo.Markdown.marked.setOptions({
16667 renderer: new Roo.Markdown.marked.Renderer(),
16678 text = text.replace(/\\\n/g,' ');
16679 return Roo.Markdown.marked(text);
16684 // Wraps all "globals" so that the only thing
16685 // exposed is makeHtml().
16690 * Block-Level Grammar
16695 code: /^( {4}[^\n]+\n*)+/,
16697 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16698 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16700 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16701 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16702 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16703 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16704 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16706 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16710 block.bullet = /(?:[*+-]|\d+\.)/;
16711 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16712 block.item = replace(block.item, 'gm')
16713 (/bull/g, block.bullet)
16716 block.list = replace(block.list)
16717 (/bull/g, block.bullet)
16718 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16719 ('def', '\\n+(?=' + block.def.source + ')')
16722 block.blockquote = replace(block.blockquote)
16726 block._tag = '(?!(?:'
16727 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16728 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16729 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16731 block.html = replace(block.html)
16732 ('comment', /<!--[\s\S]*?-->/)
16733 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16734 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16735 (/tag/g, block._tag)
16738 block.paragraph = replace(block.paragraph)
16740 ('heading', block.heading)
16741 ('lheading', block.lheading)
16742 ('blockquote', block.blockquote)
16743 ('tag', '<' + block._tag)
16748 * Normal Block Grammar
16751 block.normal = merge({}, block);
16754 * GFM Block Grammar
16757 block.gfm = merge({}, block.normal, {
16758 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16760 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16763 block.gfm.paragraph = replace(block.paragraph)
16765 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16766 + block.list.source.replace('\\1', '\\3') + '|')
16770 * GFM + Tables Block Grammar
16773 block.tables = merge({}, block.gfm, {
16774 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16775 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16782 function Lexer(options) {
16784 this.tokens.links = {};
16785 this.options = options || marked.defaults;
16786 this.rules = block.normal;
16788 if (this.options.gfm) {
16789 if (this.options.tables) {
16790 this.rules = block.tables;
16792 this.rules = block.gfm;
16798 * Expose Block Rules
16801 Lexer.rules = block;
16804 * Static Lex Method
16807 Lexer.lex = function(src, options) {
16808 var lexer = new Lexer(options);
16809 return lexer.lex(src);
16816 Lexer.prototype.lex = function(src) {
16818 .replace(/\r\n|\r/g, '\n')
16819 .replace(/\t/g, ' ')
16820 .replace(/\u00a0/g, ' ')
16821 .replace(/\u2424/g, '\n');
16823 return this.token(src, true);
16830 Lexer.prototype.token = function(src, top, bq) {
16831 var src = src.replace(/^ +$/gm, '')
16844 if (cap = this.rules.newline.exec(src)) {
16845 src = src.substring(cap[0].length);
16846 if (cap[0].length > 1) {
16854 if (cap = this.rules.code.exec(src)) {
16855 src = src.substring(cap[0].length);
16856 cap = cap[0].replace(/^ {4}/gm, '');
16859 text: !this.options.pedantic
16860 ? cap.replace(/\n+$/, '')
16867 if (cap = this.rules.fences.exec(src)) {
16868 src = src.substring(cap[0].length);
16878 if (cap = this.rules.heading.exec(src)) {
16879 src = src.substring(cap[0].length);
16882 depth: cap[1].length,
16888 // table no leading pipe (gfm)
16889 if (top && (cap = this.rules.nptable.exec(src))) {
16890 src = src.substring(cap[0].length);
16894 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16895 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16896 cells: cap[3].replace(/\n$/, '').split('\n')
16899 for (i = 0; i < item.align.length; i++) {
16900 if (/^ *-+: *$/.test(item.align[i])) {
16901 item.align[i] = 'right';
16902 } else if (/^ *:-+: *$/.test(item.align[i])) {
16903 item.align[i] = 'center';
16904 } else if (/^ *:-+ *$/.test(item.align[i])) {
16905 item.align[i] = 'left';
16907 item.align[i] = null;
16911 for (i = 0; i < item.cells.length; i++) {
16912 item.cells[i] = item.cells[i].split(/ *\| */);
16915 this.tokens.push(item);
16921 if (cap = this.rules.lheading.exec(src)) {
16922 src = src.substring(cap[0].length);
16925 depth: cap[2] === '=' ? 1 : 2,
16932 if (cap = this.rules.hr.exec(src)) {
16933 src = src.substring(cap[0].length);
16941 if (cap = this.rules.blockquote.exec(src)) {
16942 src = src.substring(cap[0].length);
16945 type: 'blockquote_start'
16948 cap = cap[0].replace(/^ *> ?/gm, '');
16950 // Pass `top` to keep the current
16951 // "toplevel" state. This is exactly
16952 // how markdown.pl works.
16953 this.token(cap, top, true);
16956 type: 'blockquote_end'
16963 if (cap = this.rules.list.exec(src)) {
16964 src = src.substring(cap[0].length);
16968 type: 'list_start',
16969 ordered: bull.length > 1
16972 // Get each top-level item.
16973 cap = cap[0].match(this.rules.item);
16979 for (; i < l; i++) {
16982 // Remove the list item's bullet
16983 // so it is seen as the next token.
16984 space = item.length;
16985 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16987 // Outdent whatever the
16988 // list item contains. Hacky.
16989 if (~item.indexOf('\n ')) {
16990 space -= item.length;
16991 item = !this.options.pedantic
16992 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16993 : item.replace(/^ {1,4}/gm, '');
16996 // Determine whether the next list item belongs here.
16997 // Backpedal if it does not belong in this list.
16998 if (this.options.smartLists && i !== l - 1) {
16999 b = block.bullet.exec(cap[i + 1])[0];
17000 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17001 src = cap.slice(i + 1).join('\n') + src;
17006 // Determine whether item is loose or not.
17007 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17008 // for discount behavior.
17009 loose = next || /\n\n(?!\s*$)/.test(item);
17011 next = item.charAt(item.length - 1) === '\n';
17012 if (!loose) { loose = next; }
17017 ? 'loose_item_start'
17018 : 'list_item_start'
17022 this.token(item, false, bq);
17025 type: 'list_item_end'
17037 if (cap = this.rules.html.exec(src)) {
17038 src = src.substring(cap[0].length);
17040 type: this.options.sanitize
17043 pre: !this.options.sanitizer
17044 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17051 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17052 src = src.substring(cap[0].length);
17053 this.tokens.links[cap[1].toLowerCase()] = {
17061 if (top && (cap = this.rules.table.exec(src))) {
17062 src = src.substring(cap[0].length);
17066 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17067 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17068 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17071 for (i = 0; i < item.align.length; i++) {
17072 if (/^ *-+: *$/.test(item.align[i])) {
17073 item.align[i] = 'right';
17074 } else if (/^ *:-+: *$/.test(item.align[i])) {
17075 item.align[i] = 'center';
17076 } else if (/^ *:-+ *$/.test(item.align[i])) {
17077 item.align[i] = 'left';
17079 item.align[i] = null;
17083 for (i = 0; i < item.cells.length; i++) {
17084 item.cells[i] = item.cells[i]
17085 .replace(/^ *\| *| *\| *$/g, '')
17089 this.tokens.push(item);
17094 // top-level paragraph
17095 if (top && (cap = this.rules.paragraph.exec(src))) {
17096 src = src.substring(cap[0].length);
17099 text: cap[1].charAt(cap[1].length - 1) === '\n'
17100 ? cap[1].slice(0, -1)
17107 if (cap = this.rules.text.exec(src)) {
17108 // Top-level should never reach here.
17109 src = src.substring(cap[0].length);
17119 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17123 return this.tokens;
17127 * Inline-Level Grammar
17131 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17132 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17134 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17135 link: /^!?\[(inside)\]\(href\)/,
17136 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17137 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17138 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17139 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17140 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17141 br: /^ {2,}\n(?!\s*$)/,
17143 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17146 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17147 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17149 inline.link = replace(inline.link)
17150 ('inside', inline._inside)
17151 ('href', inline._href)
17154 inline.reflink = replace(inline.reflink)
17155 ('inside', inline._inside)
17159 * Normal Inline Grammar
17162 inline.normal = merge({}, inline);
17165 * Pedantic Inline Grammar
17168 inline.pedantic = merge({}, inline.normal, {
17169 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17170 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17174 * GFM Inline Grammar
17177 inline.gfm = merge({}, inline.normal, {
17178 escape: replace(inline.escape)('])', '~|])')(),
17179 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17180 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17181 text: replace(inline.text)
17183 ('|', '|https?://|')
17188 * GFM + Line Breaks Inline Grammar
17191 inline.breaks = merge({}, inline.gfm, {
17192 br: replace(inline.br)('{2,}', '*')(),
17193 text: replace(inline.gfm.text)('{2,}', '*')()
17197 * Inline Lexer & Compiler
17200 function InlineLexer(links, options) {
17201 this.options = options || marked.defaults;
17202 this.links = links;
17203 this.rules = inline.normal;
17204 this.renderer = this.options.renderer || new Renderer;
17205 this.renderer.options = this.options;
17209 Error('Tokens array requires a `links` property.');
17212 if (this.options.gfm) {
17213 if (this.options.breaks) {
17214 this.rules = inline.breaks;
17216 this.rules = inline.gfm;
17218 } else if (this.options.pedantic) {
17219 this.rules = inline.pedantic;
17224 * Expose Inline Rules
17227 InlineLexer.rules = inline;
17230 * Static Lexing/Compiling Method
17233 InlineLexer.output = function(src, links, options) {
17234 var inline = new InlineLexer(links, options);
17235 return inline.output(src);
17242 InlineLexer.prototype.output = function(src) {
17251 if (cap = this.rules.escape.exec(src)) {
17252 src = src.substring(cap[0].length);
17258 if (cap = this.rules.autolink.exec(src)) {
17259 src = src.substring(cap[0].length);
17260 if (cap[2] === '@') {
17261 text = cap[1].charAt(6) === ':'
17262 ? this.mangle(cap[1].substring(7))
17263 : this.mangle(cap[1]);
17264 href = this.mangle('mailto:') + text;
17266 text = escape(cap[1]);
17269 out += this.renderer.link(href, null, text);
17274 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17275 src = src.substring(cap[0].length);
17276 text = escape(cap[1]);
17278 out += this.renderer.link(href, null, text);
17283 if (cap = this.rules.tag.exec(src)) {
17284 if (!this.inLink && /^<a /i.test(cap[0])) {
17285 this.inLink = true;
17286 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17287 this.inLink = false;
17289 src = src.substring(cap[0].length);
17290 out += this.options.sanitize
17291 ? this.options.sanitizer
17292 ? this.options.sanitizer(cap[0])
17299 if (cap = this.rules.link.exec(src)) {
17300 src = src.substring(cap[0].length);
17301 this.inLink = true;
17302 out += this.outputLink(cap, {
17306 this.inLink = false;
17311 if ((cap = this.rules.reflink.exec(src))
17312 || (cap = this.rules.nolink.exec(src))) {
17313 src = src.substring(cap[0].length);
17314 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17315 link = this.links[link.toLowerCase()];
17316 if (!link || !link.href) {
17317 out += cap[0].charAt(0);
17318 src = cap[0].substring(1) + src;
17321 this.inLink = true;
17322 out += this.outputLink(cap, link);
17323 this.inLink = false;
17328 if (cap = this.rules.strong.exec(src)) {
17329 src = src.substring(cap[0].length);
17330 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17335 if (cap = this.rules.em.exec(src)) {
17336 src = src.substring(cap[0].length);
17337 out += this.renderer.em(this.output(cap[2] || cap[1]));
17342 if (cap = this.rules.code.exec(src)) {
17343 src = src.substring(cap[0].length);
17344 out += this.renderer.codespan(escape(cap[2], true));
17349 if (cap = this.rules.br.exec(src)) {
17350 src = src.substring(cap[0].length);
17351 out += this.renderer.br();
17356 if (cap = this.rules.del.exec(src)) {
17357 src = src.substring(cap[0].length);
17358 out += this.renderer.del(this.output(cap[1]));
17363 if (cap = this.rules.text.exec(src)) {
17364 src = src.substring(cap[0].length);
17365 out += this.renderer.text(escape(this.smartypants(cap[0])));
17371 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17382 InlineLexer.prototype.outputLink = function(cap, link) {
17383 var href = escape(link.href)
17384 , title = link.title ? escape(link.title) : null;
17386 return cap[0].charAt(0) !== '!'
17387 ? this.renderer.link(href, title, this.output(cap[1]))
17388 : this.renderer.image(href, title, escape(cap[1]));
17392 * Smartypants Transformations
17395 InlineLexer.prototype.smartypants = function(text) {
17396 if (!this.options.smartypants) { return text; }
17399 .replace(/---/g, '\u2014')
17401 .replace(/--/g, '\u2013')
17403 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17404 // closing singles & apostrophes
17405 .replace(/'/g, '\u2019')
17407 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17409 .replace(/"/g, '\u201d')
17411 .replace(/\.{3}/g, '\u2026');
17418 InlineLexer.prototype.mangle = function(text) {
17419 if (!this.options.mangle) { return text; }
17425 for (; i < l; i++) {
17426 ch = text.charCodeAt(i);
17427 if (Math.random() > 0.5) {
17428 ch = 'x' + ch.toString(16);
17430 out += '&#' + ch + ';';
17440 function Renderer(options) {
17441 this.options = options || {};
17444 Renderer.prototype.code = function(code, lang, escaped) {
17445 if (this.options.highlight) {
17446 var out = this.options.highlight(code, lang);
17447 if (out != null && out !== code) {
17452 // hack!!! - it's already escapeD?
17457 return '<pre><code>'
17458 + (escaped ? code : escape(code, true))
17459 + '\n</code></pre>';
17462 return '<pre><code class="'
17463 + this.options.langPrefix
17464 + escape(lang, true)
17466 + (escaped ? code : escape(code, true))
17467 + '\n</code></pre>\n';
17470 Renderer.prototype.blockquote = function(quote) {
17471 return '<blockquote>\n' + quote + '</blockquote>\n';
17474 Renderer.prototype.html = function(html) {
17478 Renderer.prototype.heading = function(text, level, raw) {
17482 + this.options.headerPrefix
17483 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17491 Renderer.prototype.hr = function() {
17492 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17495 Renderer.prototype.list = function(body, ordered) {
17496 var type = ordered ? 'ol' : 'ul';
17497 return '<' + type + '>\n' + body + '</' + type + '>\n';
17500 Renderer.prototype.listitem = function(text) {
17501 return '<li>' + text + '</li>\n';
17504 Renderer.prototype.paragraph = function(text) {
17505 return '<p>' + text + '</p>\n';
17508 Renderer.prototype.table = function(header, body) {
17509 return '<table class="table table-striped">\n'
17519 Renderer.prototype.tablerow = function(content) {
17520 return '<tr>\n' + content + '</tr>\n';
17523 Renderer.prototype.tablecell = function(content, flags) {
17524 var type = flags.header ? 'th' : 'td';
17525 var tag = flags.align
17526 ? '<' + type + ' style="text-align:' + flags.align + '">'
17527 : '<' + type + '>';
17528 return tag + content + '</' + type + '>\n';
17531 // span level renderer
17532 Renderer.prototype.strong = function(text) {
17533 return '<strong>' + text + '</strong>';
17536 Renderer.prototype.em = function(text) {
17537 return '<em>' + text + '</em>';
17540 Renderer.prototype.codespan = function(text) {
17541 return '<code>' + text + '</code>';
17544 Renderer.prototype.br = function() {
17545 return this.options.xhtml ? '<br/>' : '<br>';
17548 Renderer.prototype.del = function(text) {
17549 return '<del>' + text + '</del>';
17552 Renderer.prototype.link = function(href, title, text) {
17553 if (this.options.sanitize) {
17555 var prot = decodeURIComponent(unescape(href))
17556 .replace(/[^\w:]/g, '')
17561 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17565 var out = '<a href="' + href + '"';
17567 out += ' title="' + title + '"';
17569 out += '>' + text + '</a>';
17573 Renderer.prototype.image = function(href, title, text) {
17574 var out = '<img src="' + href + '" alt="' + text + '"';
17576 out += ' title="' + title + '"';
17578 out += this.options.xhtml ? '/>' : '>';
17582 Renderer.prototype.text = function(text) {
17587 * Parsing & Compiling
17590 function Parser(options) {
17593 this.options = options || marked.defaults;
17594 this.options.renderer = this.options.renderer || new Renderer;
17595 this.renderer = this.options.renderer;
17596 this.renderer.options = this.options;
17600 * Static Parse Method
17603 Parser.parse = function(src, options, renderer) {
17604 var parser = new Parser(options, renderer);
17605 return parser.parse(src);
17612 Parser.prototype.parse = function(src) {
17613 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17614 this.tokens = src.reverse();
17617 while (this.next()) {
17628 Parser.prototype.next = function() {
17629 return this.token = this.tokens.pop();
17633 * Preview Next Token
17636 Parser.prototype.peek = function() {
17637 return this.tokens[this.tokens.length - 1] || 0;
17641 * Parse Text Tokens
17644 Parser.prototype.parseText = function() {
17645 var body = this.token.text;
17647 while (this.peek().type === 'text') {
17648 body += '\n' + this.next().text;
17651 return this.inline.output(body);
17655 * Parse Current Token
17658 Parser.prototype.tok = function() {
17659 switch (this.token.type) {
17664 return this.renderer.hr();
17667 return this.renderer.heading(
17668 this.inline.output(this.token.text),
17673 return this.renderer.code(this.token.text,
17675 this.token.escaped);
17688 for (i = 0; i < this.token.header.length; i++) {
17689 flags = { header: true, align: this.token.align[i] };
17690 cell += this.renderer.tablecell(
17691 this.inline.output(this.token.header[i]),
17692 { header: true, align: this.token.align[i] }
17695 header += this.renderer.tablerow(cell);
17697 for (i = 0; i < this.token.cells.length; i++) {
17698 row = this.token.cells[i];
17701 for (j = 0; j < row.length; j++) {
17702 cell += this.renderer.tablecell(
17703 this.inline.output(row[j]),
17704 { header: false, align: this.token.align[j] }
17708 body += this.renderer.tablerow(cell);
17710 return this.renderer.table(header, body);
17712 case 'blockquote_start': {
17715 while (this.next().type !== 'blockquote_end') {
17716 body += this.tok();
17719 return this.renderer.blockquote(body);
17721 case 'list_start': {
17723 , ordered = this.token.ordered;
17725 while (this.next().type !== 'list_end') {
17726 body += this.tok();
17729 return this.renderer.list(body, ordered);
17731 case 'list_item_start': {
17734 while (this.next().type !== 'list_item_end') {
17735 body += this.token.type === 'text'
17740 return this.renderer.listitem(body);
17742 case 'loose_item_start': {
17745 while (this.next().type !== 'list_item_end') {
17746 body += this.tok();
17749 return this.renderer.listitem(body);
17752 var html = !this.token.pre && !this.options.pedantic
17753 ? this.inline.output(this.token.text)
17755 return this.renderer.html(html);
17757 case 'paragraph': {
17758 return this.renderer.paragraph(this.inline.output(this.token.text));
17761 return this.renderer.paragraph(this.parseText());
17770 function escape(html, encode) {
17772 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17773 .replace(/</g, '<')
17774 .replace(/>/g, '>')
17775 .replace(/"/g, '"')
17776 .replace(/'/g, ''');
17779 function unescape(html) {
17780 // explicitly match decimal, hex, and named HTML entities
17781 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17782 n = n.toLowerCase();
17783 if (n === 'colon') { return ':'; }
17784 if (n.charAt(0) === '#') {
17785 return n.charAt(1) === 'x'
17786 ? String.fromCharCode(parseInt(n.substring(2), 16))
17787 : String.fromCharCode(+n.substring(1));
17793 function replace(regex, opt) {
17794 regex = regex.source;
17796 return function self(name, val) {
17797 if (!name) { return new RegExp(regex, opt); }
17798 val = val.source || val;
17799 val = val.replace(/(^|[^\[])\^/g, '$1');
17800 regex = regex.replace(name, val);
17808 function merge(obj) {
17813 for (; i < arguments.length; i++) {
17814 target = arguments[i];
17815 for (key in target) {
17816 if (Object.prototype.hasOwnProperty.call(target, key)) {
17817 obj[key] = target[key];
17830 function marked(src, opt, callback) {
17831 if (callback || typeof opt === 'function') {
17837 opt = merge({}, marked.defaults, opt || {});
17839 var highlight = opt.highlight
17845 tokens = Lexer.lex(src, opt)
17847 return callback(e);
17850 pending = tokens.length;
17852 var done = function(err) {
17854 opt.highlight = highlight;
17855 return callback(err);
17861 out = Parser.parse(tokens, opt);
17866 opt.highlight = highlight;
17870 : callback(null, out);
17873 if (!highlight || highlight.length < 3) {
17877 delete opt.highlight;
17879 if (!pending) { return done(); }
17881 for (; i < tokens.length; i++) {
17883 if (token.type !== 'code') {
17884 return --pending || done();
17886 return highlight(token.text, token.lang, function(err, code) {
17887 if (err) { return done(err); }
17888 if (code == null || code === token.text) {
17889 return --pending || done();
17892 token.escaped = true;
17893 --pending || done();
17901 if (opt) { opt = merge({}, marked.defaults, opt); }
17902 return Parser.parse(Lexer.lex(src, opt), opt);
17904 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17905 if ((opt || marked.defaults).silent) {
17906 return '<p>An error occured:</p><pre>'
17907 + escape(e.message + '', true)
17919 marked.setOptions = function(opt) {
17920 merge(marked.defaults, opt);
17924 marked.defaults = {
17935 langPrefix: 'lang-',
17936 smartypants: false,
17938 renderer: new Renderer,
17946 marked.Parser = Parser;
17947 marked.parser = Parser.parse;
17949 marked.Renderer = Renderer;
17951 marked.Lexer = Lexer;
17952 marked.lexer = Lexer.lex;
17954 marked.InlineLexer = InlineLexer;
17955 marked.inlineLexer = InlineLexer.output;
17957 marked.parse = marked;
17959 Roo.Markdown.marked = marked;
17963 * Ext JS Library 1.1.1
17964 * Copyright(c) 2006-2007, Ext JS, LLC.
17966 * Originally Released Under LGPL - original licence link has changed is not relivant.
17969 * <script type="text/javascript">
17975 * These classes are derivatives of the similarly named classes in the YUI Library.
17976 * The original license:
17977 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17978 * Code licensed under the BSD License:
17979 * http://developer.yahoo.net/yui/license.txt
17984 var Event=Roo.EventManager;
17985 var Dom=Roo.lib.Dom;
17988 * @class Roo.dd.DragDrop
17989 * @extends Roo.util.Observable
17990 * Defines the interface and base operation of items that that can be
17991 * dragged or can be drop targets. It was designed to be extended, overriding
17992 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17993 * Up to three html elements can be associated with a DragDrop instance:
17995 * <li>linked element: the element that is passed into the constructor.
17996 * This is the element which defines the boundaries for interaction with
17997 * other DragDrop objects.</li>
17998 * <li>handle element(s): The drag operation only occurs if the element that
17999 * was clicked matches a handle element. By default this is the linked
18000 * element, but there are times that you will want only a portion of the
18001 * linked element to initiate the drag operation, and the setHandleElId()
18002 * method provides a way to define this.</li>
18003 * <li>drag element: this represents the element that would be moved along
18004 * with the cursor during a drag operation. By default, this is the linked
18005 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18006 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18009 * This class should not be instantiated until the onload event to ensure that
18010 * the associated elements are available.
18011 * The following would define a DragDrop obj that would interact with any
18012 * other DragDrop obj in the "group1" group:
18014 * dd = new Roo.dd.DragDrop("div1", "group1");
18016 * Since none of the event handlers have been implemented, nothing would
18017 * actually happen if you were to run the code above. Normally you would
18018 * override this class or one of the default implementations, but you can
18019 * also override the methods you want on an instance of the class...
18021 * dd.onDragDrop = function(e, id) {
18022 * alert("dd was dropped on " + id);
18026 * @param {String} id of the element that is linked to this instance
18027 * @param {String} sGroup the group of related DragDrop objects
18028 * @param {object} config an object containing configurable attributes
18029 * Valid properties for DragDrop:
18030 * padding, isTarget, maintainOffset, primaryButtonOnly
18032 Roo.dd.DragDrop = function(id, sGroup, config) {
18034 this.init(id, sGroup, config);
18039 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18042 * The id of the element associated with this object. This is what we
18043 * refer to as the "linked element" because the size and position of
18044 * this element is used to determine when the drag and drop objects have
18052 * Configuration attributes passed into the constructor
18059 * The id of the element that will be dragged. By default this is same
18060 * as the linked element , but could be changed to another element. Ex:
18062 * @property dragElId
18069 * the id of the element that initiates the drag operation. By default
18070 * this is the linked element, but could be changed to be a child of this
18071 * element. This lets us do things like only starting the drag when the
18072 * header element within the linked html element is clicked.
18073 * @property handleElId
18080 * An associative array of HTML tags that will be ignored if clicked.
18081 * @property invalidHandleTypes
18082 * @type {string: string}
18084 invalidHandleTypes: null,
18087 * An associative array of ids for elements that will be ignored if clicked
18088 * @property invalidHandleIds
18089 * @type {string: string}
18091 invalidHandleIds: null,
18094 * An indexted array of css class names for elements that will be ignored
18096 * @property invalidHandleClasses
18099 invalidHandleClasses: null,
18102 * The linked element's absolute X position at the time the drag was
18104 * @property startPageX
18111 * The linked element's absolute X position at the time the drag was
18113 * @property startPageY
18120 * The group defines a logical collection of DragDrop objects that are
18121 * related. Instances only get events when interacting with other
18122 * DragDrop object in the same group. This lets us define multiple
18123 * groups using a single DragDrop subclass if we want.
18125 * @type {string: string}
18130 * Individual drag/drop instances can be locked. This will prevent
18131 * onmousedown start drag.
18139 * Lock this instance
18142 lock: function() { this.locked = true; },
18145 * Unlock this instace
18148 unlock: function() { this.locked = false; },
18151 * By default, all insances can be a drop target. This can be disabled by
18152 * setting isTarget to false.
18159 * The padding configured for this drag and drop object for calculating
18160 * the drop zone intersection with this object.
18167 * Cached reference to the linked element
18168 * @property _domRef
18174 * Internal typeof flag
18175 * @property __ygDragDrop
18178 __ygDragDrop: true,
18181 * Set to true when horizontal contraints are applied
18182 * @property constrainX
18189 * Set to true when vertical contraints are applied
18190 * @property constrainY
18197 * The left constraint
18205 * The right constraint
18213 * The up constraint
18222 * The down constraint
18230 * Maintain offsets when we resetconstraints. Set to true when you want
18231 * the position of the element relative to its parent to stay the same
18232 * when the page changes
18234 * @property maintainOffset
18237 maintainOffset: false,
18240 * Array of pixel locations the element will snap to if we specified a
18241 * horizontal graduation/interval. This array is generated automatically
18242 * when you define a tick interval.
18249 * Array of pixel locations the element will snap to if we specified a
18250 * vertical graduation/interval. This array is generated automatically
18251 * when you define a tick interval.
18258 * By default the drag and drop instance will only respond to the primary
18259 * button click (left button for a right-handed mouse). Set to true to
18260 * allow drag and drop to start with any mouse click that is propogated
18262 * @property primaryButtonOnly
18265 primaryButtonOnly: true,
18268 * The availabe property is false until the linked dom element is accessible.
18269 * @property available
18275 * By default, drags can only be initiated if the mousedown occurs in the
18276 * region the linked element is. This is done in part to work around a
18277 * bug in some browsers that mis-report the mousedown if the previous
18278 * mouseup happened outside of the window. This property is set to true
18279 * if outer handles are defined.
18281 * @property hasOuterHandles
18285 hasOuterHandles: false,
18288 * Code that executes immediately before the startDrag event
18289 * @method b4StartDrag
18292 b4StartDrag: function(x, y) { },
18295 * Abstract method called after a drag/drop object is clicked
18296 * and the drag or mousedown time thresholds have beeen met.
18297 * @method startDrag
18298 * @param {int} X click location
18299 * @param {int} Y click location
18301 startDrag: function(x, y) { /* override this */ },
18304 * Code that executes immediately before the onDrag event
18308 b4Drag: function(e) { },
18311 * Abstract method called during the onMouseMove event while dragging an
18314 * @param {Event} e the mousemove event
18316 onDrag: function(e) { /* override this */ },
18319 * Abstract method called when this element fist begins hovering over
18320 * another DragDrop obj
18321 * @method onDragEnter
18322 * @param {Event} e the mousemove event
18323 * @param {String|DragDrop[]} id In POINT mode, the element
18324 * id this is hovering over. In INTERSECT mode, an array of one or more
18325 * dragdrop items being hovered over.
18327 onDragEnter: function(e, id) { /* override this */ },
18330 * Code that executes immediately before the onDragOver event
18331 * @method b4DragOver
18334 b4DragOver: function(e) { },
18337 * Abstract method called when this element is hovering over another
18339 * @method onDragOver
18340 * @param {Event} e the mousemove event
18341 * @param {String|DragDrop[]} id In POINT mode, the element
18342 * id this is hovering over. In INTERSECT mode, an array of dd items
18343 * being hovered over.
18345 onDragOver: function(e, id) { /* override this */ },
18348 * Code that executes immediately before the onDragOut event
18349 * @method b4DragOut
18352 b4DragOut: function(e) { },
18355 * Abstract method called when we are no longer hovering over an element
18356 * @method onDragOut
18357 * @param {Event} e the mousemove event
18358 * @param {String|DragDrop[]} id In POINT mode, the element
18359 * id this was hovering over. In INTERSECT mode, an array of dd items
18360 * that the mouse is no longer over.
18362 onDragOut: function(e, id) { /* override this */ },
18365 * Code that executes immediately before the onDragDrop event
18366 * @method b4DragDrop
18369 b4DragDrop: function(e) { },
18372 * Abstract method called when this item is dropped on another DragDrop
18374 * @method onDragDrop
18375 * @param {Event} e the mouseup event
18376 * @param {String|DragDrop[]} id In POINT mode, the element
18377 * id this was dropped on. In INTERSECT mode, an array of dd items this
18380 onDragDrop: function(e, id) { /* override this */ },
18383 * Abstract method called when this item is dropped on an area with no
18385 * @method onInvalidDrop
18386 * @param {Event} e the mouseup event
18388 onInvalidDrop: function(e) { /* override this */ },
18391 * Code that executes immediately before the endDrag event
18392 * @method b4EndDrag
18395 b4EndDrag: function(e) { },
18398 * Fired when we are done dragging the object
18400 * @param {Event} e the mouseup event
18402 endDrag: function(e) { /* override this */ },
18405 * Code executed immediately before the onMouseDown event
18406 * @method b4MouseDown
18407 * @param {Event} e the mousedown event
18410 b4MouseDown: function(e) { },
18413 * Event handler that fires when a drag/drop obj gets a mousedown
18414 * @method onMouseDown
18415 * @param {Event} e the mousedown event
18417 onMouseDown: function(e) { /* override this */ },
18420 * Event handler that fires when a drag/drop obj gets a mouseup
18421 * @method onMouseUp
18422 * @param {Event} e the mouseup event
18424 onMouseUp: function(e) { /* override this */ },
18427 * Override the onAvailable method to do what is needed after the initial
18428 * position was determined.
18429 * @method onAvailable
18431 onAvailable: function () {
18435 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18438 defaultPadding : {left:0, right:0, top:0, bottom:0},
18441 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18445 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18446 { dragElId: "existingProxyDiv" });
18447 dd.startDrag = function(){
18448 this.constrainTo("parent-id");
18451 * Or you can initalize it using the {@link Roo.Element} object:
18453 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18454 startDrag : function(){
18455 this.constrainTo("parent-id");
18459 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18460 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18461 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18462 * an object containing the sides to pad. For example: {right:10, bottom:10}
18463 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18465 constrainTo : function(constrainTo, pad, inContent){
18466 if(typeof pad == "number"){
18467 pad = {left: pad, right:pad, top:pad, bottom:pad};
18469 pad = pad || this.defaultPadding;
18470 var b = Roo.get(this.getEl()).getBox();
18471 var ce = Roo.get(constrainTo);
18472 var s = ce.getScroll();
18473 var c, cd = ce.dom;
18474 if(cd == document.body){
18475 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18478 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18482 var topSpace = b.y - c.y;
18483 var leftSpace = b.x - c.x;
18485 this.resetConstraints();
18486 this.setXConstraint(leftSpace - (pad.left||0), // left
18487 c.width - leftSpace - b.width - (pad.right||0) //right
18489 this.setYConstraint(topSpace - (pad.top||0), //top
18490 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18495 * Returns a reference to the linked element
18497 * @return {HTMLElement} the html element
18499 getEl: function() {
18500 if (!this._domRef) {
18501 this._domRef = Roo.getDom(this.id);
18504 return this._domRef;
18508 * Returns a reference to the actual element to drag. By default this is
18509 * the same as the html element, but it can be assigned to another
18510 * element. An example of this can be found in Roo.dd.DDProxy
18511 * @method getDragEl
18512 * @return {HTMLElement} the html element
18514 getDragEl: function() {
18515 return Roo.getDom(this.dragElId);
18519 * Sets up the DragDrop object. Must be called in the constructor of any
18520 * Roo.dd.DragDrop subclass
18522 * @param id the id of the linked element
18523 * @param {String} sGroup the group of related items
18524 * @param {object} config configuration attributes
18526 init: function(id, sGroup, config) {
18527 this.initTarget(id, sGroup, config);
18528 if (!Roo.isTouch) {
18529 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18531 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18532 // Event.on(this.id, "selectstart", Event.preventDefault);
18536 * Initializes Targeting functionality only... the object does not
18537 * get a mousedown handler.
18538 * @method initTarget
18539 * @param id the id of the linked element
18540 * @param {String} sGroup the group of related items
18541 * @param {object} config configuration attributes
18543 initTarget: function(id, sGroup, config) {
18545 // configuration attributes
18546 this.config = config || {};
18548 // create a local reference to the drag and drop manager
18549 this.DDM = Roo.dd.DDM;
18550 // initialize the groups array
18553 // assume that we have an element reference instead of an id if the
18554 // parameter is not a string
18555 if (typeof id !== "string") {
18562 // add to an interaction group
18563 this.addToGroup((sGroup) ? sGroup : "default");
18565 // We don't want to register this as the handle with the manager
18566 // so we just set the id rather than calling the setter.
18567 this.handleElId = id;
18569 // the linked element is the element that gets dragged by default
18570 this.setDragElId(id);
18572 // by default, clicked anchors will not start drag operations.
18573 this.invalidHandleTypes = { A: "A" };
18574 this.invalidHandleIds = {};
18575 this.invalidHandleClasses = [];
18577 this.applyConfig();
18579 this.handleOnAvailable();
18583 * Applies the configuration parameters that were passed into the constructor.
18584 * This is supposed to happen at each level through the inheritance chain. So
18585 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18586 * DragDrop in order to get all of the parameters that are available in
18588 * @method applyConfig
18590 applyConfig: function() {
18592 // configurable properties:
18593 // padding, isTarget, maintainOffset, primaryButtonOnly
18594 this.padding = this.config.padding || [0, 0, 0, 0];
18595 this.isTarget = (this.config.isTarget !== false);
18596 this.maintainOffset = (this.config.maintainOffset);
18597 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18602 * Executed when the linked element is available
18603 * @method handleOnAvailable
18606 handleOnAvailable: function() {
18607 this.available = true;
18608 this.resetConstraints();
18609 this.onAvailable();
18613 * Configures the padding for the target zone in px. Effectively expands
18614 * (or reduces) the virtual object size for targeting calculations.
18615 * Supports css-style shorthand; if only one parameter is passed, all sides
18616 * will have that padding, and if only two are passed, the top and bottom
18617 * will have the first param, the left and right the second.
18618 * @method setPadding
18619 * @param {int} iTop Top pad
18620 * @param {int} iRight Right pad
18621 * @param {int} iBot Bot pad
18622 * @param {int} iLeft Left pad
18624 setPadding: function(iTop, iRight, iBot, iLeft) {
18625 // this.padding = [iLeft, iRight, iTop, iBot];
18626 if (!iRight && 0 !== iRight) {
18627 this.padding = [iTop, iTop, iTop, iTop];
18628 } else if (!iBot && 0 !== iBot) {
18629 this.padding = [iTop, iRight, iTop, iRight];
18631 this.padding = [iTop, iRight, iBot, iLeft];
18636 * Stores the initial placement of the linked element.
18637 * @method setInitialPosition
18638 * @param {int} diffX the X offset, default 0
18639 * @param {int} diffY the Y offset, default 0
18641 setInitPosition: function(diffX, diffY) {
18642 var el = this.getEl();
18644 if (!this.DDM.verifyEl(el)) {
18648 var dx = diffX || 0;
18649 var dy = diffY || 0;
18651 var p = Dom.getXY( el );
18653 this.initPageX = p[0] - dx;
18654 this.initPageY = p[1] - dy;
18656 this.lastPageX = p[0];
18657 this.lastPageY = p[1];
18660 this.setStartPosition(p);
18664 * Sets the start position of the element. This is set when the obj
18665 * is initialized, the reset when a drag is started.
18666 * @method setStartPosition
18667 * @param pos current position (from previous lookup)
18670 setStartPosition: function(pos) {
18671 var p = pos || Dom.getXY( this.getEl() );
18672 this.deltaSetXY = null;
18674 this.startPageX = p[0];
18675 this.startPageY = p[1];
18679 * Add this instance to a group of related drag/drop objects. All
18680 * instances belong to at least one group, and can belong to as many
18681 * groups as needed.
18682 * @method addToGroup
18683 * @param sGroup {string} the name of the group
18685 addToGroup: function(sGroup) {
18686 this.groups[sGroup] = true;
18687 this.DDM.regDragDrop(this, sGroup);
18691 * Remove's this instance from the supplied interaction group
18692 * @method removeFromGroup
18693 * @param {string} sGroup The group to drop
18695 removeFromGroup: function(sGroup) {
18696 if (this.groups[sGroup]) {
18697 delete this.groups[sGroup];
18700 this.DDM.removeDDFromGroup(this, sGroup);
18704 * Allows you to specify that an element other than the linked element
18705 * will be moved with the cursor during a drag
18706 * @method setDragElId
18707 * @param id {string} the id of the element that will be used to initiate the drag
18709 setDragElId: function(id) {
18710 this.dragElId = id;
18714 * Allows you to specify a child of the linked element that should be
18715 * used to initiate the drag operation. An example of this would be if
18716 * you have a content div with text and links. Clicking anywhere in the
18717 * content area would normally start the drag operation. Use this method
18718 * to specify that an element inside of the content div is the element
18719 * that starts the drag operation.
18720 * @method setHandleElId
18721 * @param id {string} the id of the element that will be used to
18722 * initiate the drag.
18724 setHandleElId: function(id) {
18725 if (typeof id !== "string") {
18728 this.handleElId = id;
18729 this.DDM.regHandle(this.id, id);
18733 * Allows you to set an element outside of the linked element as a drag
18735 * @method setOuterHandleElId
18736 * @param id the id of the element that will be used to initiate the drag
18738 setOuterHandleElId: function(id) {
18739 if (typeof id !== "string") {
18742 Event.on(id, "mousedown",
18743 this.handleMouseDown, this);
18744 this.setHandleElId(id);
18746 this.hasOuterHandles = true;
18750 * Remove all drag and drop hooks for this element
18753 unreg: function() {
18754 Event.un(this.id, "mousedown",
18755 this.handleMouseDown);
18756 Event.un(this.id, "touchstart",
18757 this.handleMouseDown);
18758 this._domRef = null;
18759 this.DDM._remove(this);
18762 destroy : function(){
18767 * Returns true if this instance is locked, or the drag drop mgr is locked
18768 * (meaning that all drag/drop is disabled on the page.)
18770 * @return {boolean} true if this obj or all drag/drop is locked, else
18773 isLocked: function() {
18774 return (this.DDM.isLocked() || this.locked);
18778 * Fired when this object is clicked
18779 * @method handleMouseDown
18781 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18784 handleMouseDown: function(e, oDD){
18786 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18787 //Roo.log('not touch/ button !=0');
18790 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18791 return; // double touch..
18795 if (this.isLocked()) {
18796 //Roo.log('locked');
18800 this.DDM.refreshCache(this.groups);
18801 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18802 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18803 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18804 //Roo.log('no outer handes or not over target');
18807 // Roo.log('check validator');
18808 if (this.clickValidator(e)) {
18809 // Roo.log('validate success');
18810 // set the initial element position
18811 this.setStartPosition();
18814 this.b4MouseDown(e);
18815 this.onMouseDown(e);
18817 this.DDM.handleMouseDown(e, this);
18819 this.DDM.stopEvent(e);
18827 clickValidator: function(e) {
18828 var target = e.getTarget();
18829 return ( this.isValidHandleChild(target) &&
18830 (this.id == this.handleElId ||
18831 this.DDM.handleWasClicked(target, this.id)) );
18835 * Allows you to specify a tag name that should not start a drag operation
18836 * when clicked. This is designed to facilitate embedding links within a
18837 * drag handle that do something other than start the drag.
18838 * @method addInvalidHandleType
18839 * @param {string} tagName the type of element to exclude
18841 addInvalidHandleType: function(tagName) {
18842 var type = tagName.toUpperCase();
18843 this.invalidHandleTypes[type] = type;
18847 * Lets you to specify an element id for a child of a drag handle
18848 * that should not initiate a drag
18849 * @method addInvalidHandleId
18850 * @param {string} id the element id of the element you wish to ignore
18852 addInvalidHandleId: function(id) {
18853 if (typeof id !== "string") {
18856 this.invalidHandleIds[id] = id;
18860 * Lets you specify a css class of elements that will not initiate a drag
18861 * @method addInvalidHandleClass
18862 * @param {string} cssClass the class of the elements you wish to ignore
18864 addInvalidHandleClass: function(cssClass) {
18865 this.invalidHandleClasses.push(cssClass);
18869 * Unsets an excluded tag name set by addInvalidHandleType
18870 * @method removeInvalidHandleType
18871 * @param {string} tagName the type of element to unexclude
18873 removeInvalidHandleType: function(tagName) {
18874 var type = tagName.toUpperCase();
18875 // this.invalidHandleTypes[type] = null;
18876 delete this.invalidHandleTypes[type];
18880 * Unsets an invalid handle id
18881 * @method removeInvalidHandleId
18882 * @param {string} id the id of the element to re-enable
18884 removeInvalidHandleId: function(id) {
18885 if (typeof id !== "string") {
18888 delete this.invalidHandleIds[id];
18892 * Unsets an invalid css class
18893 * @method removeInvalidHandleClass
18894 * @param {string} cssClass the class of the element(s) you wish to
18897 removeInvalidHandleClass: function(cssClass) {
18898 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18899 if (this.invalidHandleClasses[i] == cssClass) {
18900 delete this.invalidHandleClasses[i];
18906 * Checks the tag exclusion list to see if this click should be ignored
18907 * @method isValidHandleChild
18908 * @param {HTMLElement} node the HTMLElement to evaluate
18909 * @return {boolean} true if this is a valid tag type, false if not
18911 isValidHandleChild: function(node) {
18914 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18917 nodeName = node.nodeName.toUpperCase();
18919 nodeName = node.nodeName;
18921 valid = valid && !this.invalidHandleTypes[nodeName];
18922 valid = valid && !this.invalidHandleIds[node.id];
18924 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18925 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18934 * Create the array of horizontal tick marks if an interval was specified
18935 * in setXConstraint().
18936 * @method setXTicks
18939 setXTicks: function(iStartX, iTickSize) {
18941 this.xTickSize = iTickSize;
18945 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18947 this.xTicks[this.xTicks.length] = i;
18952 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18954 this.xTicks[this.xTicks.length] = i;
18959 this.xTicks.sort(this.DDM.numericSort) ;
18963 * Create the array of vertical tick marks if an interval was specified in
18964 * setYConstraint().
18965 * @method setYTicks
18968 setYTicks: function(iStartY, iTickSize) {
18970 this.yTickSize = iTickSize;
18974 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18976 this.yTicks[this.yTicks.length] = i;
18981 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18983 this.yTicks[this.yTicks.length] = i;
18988 this.yTicks.sort(this.DDM.numericSort) ;
18992 * By default, the element can be dragged any place on the screen. Use
18993 * this method to limit the horizontal travel of the element. Pass in
18994 * 0,0 for the parameters if you want to lock the drag to the y axis.
18995 * @method setXConstraint
18996 * @param {int} iLeft the number of pixels the element can move to the left
18997 * @param {int} iRight the number of pixels the element can move to the
18999 * @param {int} iTickSize optional parameter for specifying that the
19001 * should move iTickSize pixels at a time.
19003 setXConstraint: function(iLeft, iRight, iTickSize) {
19004 this.leftConstraint = iLeft;
19005 this.rightConstraint = iRight;
19007 this.minX = this.initPageX - iLeft;
19008 this.maxX = this.initPageX + iRight;
19009 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19011 this.constrainX = true;
19015 * Clears any constraints applied to this instance. Also clears ticks
19016 * since they can't exist independent of a constraint at this time.
19017 * @method clearConstraints
19019 clearConstraints: function() {
19020 this.constrainX = false;
19021 this.constrainY = false;
19026 * Clears any tick interval defined for this instance
19027 * @method clearTicks
19029 clearTicks: function() {
19030 this.xTicks = null;
19031 this.yTicks = null;
19032 this.xTickSize = 0;
19033 this.yTickSize = 0;
19037 * By default, the element can be dragged any place on the screen. Set
19038 * this to limit the vertical travel of the element. Pass in 0,0 for the
19039 * parameters if you want to lock the drag to the x axis.
19040 * @method setYConstraint
19041 * @param {int} iUp the number of pixels the element can move up
19042 * @param {int} iDown the number of pixels the element can move down
19043 * @param {int} iTickSize optional parameter for specifying that the
19044 * element should move iTickSize pixels at a time.
19046 setYConstraint: function(iUp, iDown, iTickSize) {
19047 this.topConstraint = iUp;
19048 this.bottomConstraint = iDown;
19050 this.minY = this.initPageY - iUp;
19051 this.maxY = this.initPageY + iDown;
19052 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19054 this.constrainY = true;
19059 * resetConstraints must be called if you manually reposition a dd element.
19060 * @method resetConstraints
19061 * @param {boolean} maintainOffset
19063 resetConstraints: function() {
19066 // Maintain offsets if necessary
19067 if (this.initPageX || this.initPageX === 0) {
19068 // figure out how much this thing has moved
19069 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19070 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19072 this.setInitPosition(dx, dy);
19074 // This is the first time we have detected the element's position
19076 this.setInitPosition();
19079 if (this.constrainX) {
19080 this.setXConstraint( this.leftConstraint,
19081 this.rightConstraint,
19085 if (this.constrainY) {
19086 this.setYConstraint( this.topConstraint,
19087 this.bottomConstraint,
19093 * Normally the drag element is moved pixel by pixel, but we can specify
19094 * that it move a number of pixels at a time. This method resolves the
19095 * location when we have it set up like this.
19097 * @param {int} val where we want to place the object
19098 * @param {int[]} tickArray sorted array of valid points
19099 * @return {int} the closest tick
19102 getTick: function(val, tickArray) {
19105 // If tick interval is not defined, it is effectively 1 pixel,
19106 // so we return the value passed to us.
19108 } else if (tickArray[0] >= val) {
19109 // The value is lower than the first tick, so we return the first
19111 return tickArray[0];
19113 for (var i=0, len=tickArray.length; i<len; ++i) {
19115 if (tickArray[next] && tickArray[next] >= val) {
19116 var diff1 = val - tickArray[i];
19117 var diff2 = tickArray[next] - val;
19118 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19122 // The value is larger than the last tick, so we return the last
19124 return tickArray[tickArray.length - 1];
19131 * @return {string} string representation of the dd obj
19133 toString: function() {
19134 return ("DragDrop " + this.id);
19142 * Ext JS Library 1.1.1
19143 * Copyright(c) 2006-2007, Ext JS, LLC.
19145 * Originally Released Under LGPL - original licence link has changed is not relivant.
19148 * <script type="text/javascript">
19153 * The drag and drop utility provides a framework for building drag and drop
19154 * applications. In addition to enabling drag and drop for specific elements,
19155 * the drag and drop elements are tracked by the manager class, and the
19156 * interactions between the various elements are tracked during the drag and
19157 * the implementing code is notified about these important moments.
19160 // Only load the library once. Rewriting the manager class would orphan
19161 // existing drag and drop instances.
19162 if (!Roo.dd.DragDropMgr) {
19165 * @class Roo.dd.DragDropMgr
19166 * DragDropMgr is a singleton that tracks the element interaction for
19167 * all DragDrop items in the window. Generally, you will not call
19168 * this class directly, but it does have helper methods that could
19169 * be useful in your DragDrop implementations.
19172 Roo.dd.DragDropMgr = function() {
19174 var Event = Roo.EventManager;
19179 * Two dimensional Array of registered DragDrop objects. The first
19180 * dimension is the DragDrop item group, the second the DragDrop
19183 * @type {string: string}
19190 * Array of element ids defined as drag handles. Used to determine
19191 * if the element that generated the mousedown event is actually the
19192 * handle and not the html element itself.
19193 * @property handleIds
19194 * @type {string: string}
19201 * the DragDrop object that is currently being dragged
19202 * @property dragCurrent
19210 * the DragDrop object(s) that are being hovered over
19211 * @property dragOvers
19219 * the X distance between the cursor and the object being dragged
19228 * the Y distance between the cursor and the object being dragged
19237 * Flag to determine if we should prevent the default behavior of the
19238 * events we define. By default this is true, but this can be set to
19239 * false if you need the default behavior (not recommended)
19240 * @property preventDefault
19244 preventDefault: true,
19247 * Flag to determine if we should stop the propagation of the events
19248 * we generate. This is true by default but you may want to set it to
19249 * false if the html element contains other features that require the
19251 * @property stopPropagation
19255 stopPropagation: true,
19258 * Internal flag that is set to true when drag and drop has been
19260 * @property initialized
19267 * All drag and drop can be disabled.
19275 * Called the first time an element is registered.
19281 this.initialized = true;
19285 * In point mode, drag and drop interaction is defined by the
19286 * location of the cursor during the drag/drop
19294 * In intersect mode, drag and drop interactio nis defined by the
19295 * overlap of two or more drag and drop objects.
19296 * @property INTERSECT
19303 * The current drag and drop mode. Default: POINT
19311 * Runs method on all drag and drop objects
19312 * @method _execOnAll
19316 _execOnAll: function(sMethod, args) {
19317 for (var i in this.ids) {
19318 for (var j in this.ids[i]) {
19319 var oDD = this.ids[i][j];
19320 if (! this.isTypeOfDD(oDD)) {
19323 oDD[sMethod].apply(oDD, args);
19329 * Drag and drop initialization. Sets up the global event handlers
19334 _onLoad: function() {
19338 if (!Roo.isTouch) {
19339 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19340 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19342 Event.on(document, "touchend", this.handleMouseUp, this, true);
19343 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19345 Event.on(window, "unload", this._onUnload, this, true);
19346 Event.on(window, "resize", this._onResize, this, true);
19347 // Event.on(window, "mouseout", this._test);
19352 * Reset constraints on all drag and drop objs
19353 * @method _onResize
19357 _onResize: function(e) {
19358 this._execOnAll("resetConstraints", []);
19362 * Lock all drag and drop functionality
19366 lock: function() { this.locked = true; },
19369 * Unlock all drag and drop functionality
19373 unlock: function() { this.locked = false; },
19376 * Is drag and drop locked?
19378 * @return {boolean} True if drag and drop is locked, false otherwise.
19381 isLocked: function() { return this.locked; },
19384 * Location cache that is set for all drag drop objects when a drag is
19385 * initiated, cleared when the drag is finished.
19386 * @property locationCache
19393 * Set useCache to false if you want to force object the lookup of each
19394 * drag and drop linked element constantly during a drag.
19395 * @property useCache
19402 * The number of pixels that the mouse needs to move after the
19403 * mousedown before the drag is initiated. Default=3;
19404 * @property clickPixelThresh
19408 clickPixelThresh: 3,
19411 * The number of milliseconds after the mousedown event to initiate the
19412 * drag if we don't get a mouseup event. Default=1000
19413 * @property clickTimeThresh
19417 clickTimeThresh: 350,
19420 * Flag that indicates that either the drag pixel threshold or the
19421 * mousdown time threshold has been met
19422 * @property dragThreshMet
19427 dragThreshMet: false,
19430 * Timeout used for the click time threshold
19431 * @property clickTimeout
19436 clickTimeout: null,
19439 * The X position of the mousedown event stored for later use when a
19440 * drag threshold is met.
19449 * The Y position of the mousedown event stored for later use when a
19450 * drag threshold is met.
19459 * Each DragDrop instance must be registered with the DragDropMgr.
19460 * This is executed in DragDrop.init()
19461 * @method regDragDrop
19462 * @param {DragDrop} oDD the DragDrop object to register
19463 * @param {String} sGroup the name of the group this element belongs to
19466 regDragDrop: function(oDD, sGroup) {
19467 if (!this.initialized) { this.init(); }
19469 if (!this.ids[sGroup]) {
19470 this.ids[sGroup] = {};
19472 this.ids[sGroup][oDD.id] = oDD;
19476 * Removes the supplied dd instance from the supplied group. Executed
19477 * by DragDrop.removeFromGroup, so don't call this function directly.
19478 * @method removeDDFromGroup
19482 removeDDFromGroup: function(oDD, sGroup) {
19483 if (!this.ids[sGroup]) {
19484 this.ids[sGroup] = {};
19487 var obj = this.ids[sGroup];
19488 if (obj && obj[oDD.id]) {
19489 delete obj[oDD.id];
19494 * Unregisters a drag and drop item. This is executed in
19495 * DragDrop.unreg, use that method instead of calling this directly.
19500 _remove: function(oDD) {
19501 for (var g in oDD.groups) {
19502 if (g && this.ids[g][oDD.id]) {
19503 delete this.ids[g][oDD.id];
19506 delete this.handleIds[oDD.id];
19510 * Each DragDrop handle element must be registered. This is done
19511 * automatically when executing DragDrop.setHandleElId()
19512 * @method regHandle
19513 * @param {String} sDDId the DragDrop id this element is a handle for
19514 * @param {String} sHandleId the id of the element that is the drag
19518 regHandle: function(sDDId, sHandleId) {
19519 if (!this.handleIds[sDDId]) {
19520 this.handleIds[sDDId] = {};
19522 this.handleIds[sDDId][sHandleId] = sHandleId;
19526 * Utility function to determine if a given element has been
19527 * registered as a drag drop item.
19528 * @method isDragDrop
19529 * @param {String} id the element id to check
19530 * @return {boolean} true if this element is a DragDrop item,
19534 isDragDrop: function(id) {
19535 return ( this.getDDById(id) ) ? true : false;
19539 * Returns the drag and drop instances that are in all groups the
19540 * passed in instance belongs to.
19541 * @method getRelated
19542 * @param {DragDrop} p_oDD the obj to get related data for
19543 * @param {boolean} bTargetsOnly if true, only return targetable objs
19544 * @return {DragDrop[]} the related instances
19547 getRelated: function(p_oDD, bTargetsOnly) {
19549 for (var i in p_oDD.groups) {
19550 for (j in this.ids[i]) {
19551 var dd = this.ids[i][j];
19552 if (! this.isTypeOfDD(dd)) {
19555 if (!bTargetsOnly || dd.isTarget) {
19556 oDDs[oDDs.length] = dd;
19565 * Returns true if the specified dd target is a legal target for
19566 * the specifice drag obj
19567 * @method isLegalTarget
19568 * @param {DragDrop} the drag obj
19569 * @param {DragDrop} the target
19570 * @return {boolean} true if the target is a legal target for the
19574 isLegalTarget: function (oDD, oTargetDD) {
19575 var targets = this.getRelated(oDD, true);
19576 for (var i=0, len=targets.length;i<len;++i) {
19577 if (targets[i].id == oTargetDD.id) {
19586 * My goal is to be able to transparently determine if an object is
19587 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19588 * returns "object", oDD.constructor.toString() always returns
19589 * "DragDrop" and not the name of the subclass. So for now it just
19590 * evaluates a well-known variable in DragDrop.
19591 * @method isTypeOfDD
19592 * @param {Object} the object to evaluate
19593 * @return {boolean} true if typeof oDD = DragDrop
19596 isTypeOfDD: function (oDD) {
19597 return (oDD && oDD.__ygDragDrop);
19601 * Utility function to determine if a given element has been
19602 * registered as a drag drop handle for the given Drag Drop object.
19604 * @param {String} id the element id to check
19605 * @return {boolean} true if this element is a DragDrop handle, false
19609 isHandle: function(sDDId, sHandleId) {
19610 return ( this.handleIds[sDDId] &&
19611 this.handleIds[sDDId][sHandleId] );
19615 * Returns the DragDrop instance for a given id
19616 * @method getDDById
19617 * @param {String} id the id of the DragDrop object
19618 * @return {DragDrop} the drag drop object, null if it is not found
19621 getDDById: function(id) {
19622 for (var i in this.ids) {
19623 if (this.ids[i][id]) {
19624 return this.ids[i][id];
19631 * Fired after a registered DragDrop object gets the mousedown event.
19632 * Sets up the events required to track the object being dragged
19633 * @method handleMouseDown
19634 * @param {Event} e the event
19635 * @param oDD the DragDrop object being dragged
19639 handleMouseDown: function(e, oDD) {
19641 Roo.QuickTips.disable();
19643 this.currentTarget = e.getTarget();
19645 this.dragCurrent = oDD;
19647 var el = oDD.getEl();
19649 // track start position
19650 this.startX = e.getPageX();
19651 this.startY = e.getPageY();
19653 this.deltaX = this.startX - el.offsetLeft;
19654 this.deltaY = this.startY - el.offsetTop;
19656 this.dragThreshMet = false;
19658 this.clickTimeout = setTimeout(
19660 var DDM = Roo.dd.DDM;
19661 DDM.startDrag(DDM.startX, DDM.startY);
19663 this.clickTimeThresh );
19667 * Fired when either the drag pixel threshol or the mousedown hold
19668 * time threshold has been met.
19669 * @method startDrag
19670 * @param x {int} the X position of the original mousedown
19671 * @param y {int} the Y position of the original mousedown
19674 startDrag: function(x, y) {
19675 clearTimeout(this.clickTimeout);
19676 if (this.dragCurrent) {
19677 this.dragCurrent.b4StartDrag(x, y);
19678 this.dragCurrent.startDrag(x, y);
19680 this.dragThreshMet = true;
19684 * Internal function to handle the mouseup event. Will be invoked
19685 * from the context of the document.
19686 * @method handleMouseUp
19687 * @param {Event} e the event
19691 handleMouseUp: function(e) {
19694 Roo.QuickTips.enable();
19696 if (! this.dragCurrent) {
19700 clearTimeout(this.clickTimeout);
19702 if (this.dragThreshMet) {
19703 this.fireEvents(e, true);
19713 * Utility to stop event propagation and event default, if these
19714 * features are turned on.
19715 * @method stopEvent
19716 * @param {Event} e the event as returned by this.getEvent()
19719 stopEvent: function(e){
19720 if(this.stopPropagation) {
19721 e.stopPropagation();
19724 if (this.preventDefault) {
19725 e.preventDefault();
19730 * Internal function to clean up event handlers after the drag
19731 * operation is complete
19733 * @param {Event} e the event
19737 stopDrag: function(e) {
19738 // Fire the drag end event for the item that was dragged
19739 if (this.dragCurrent) {
19740 if (this.dragThreshMet) {
19741 this.dragCurrent.b4EndDrag(e);
19742 this.dragCurrent.endDrag(e);
19745 this.dragCurrent.onMouseUp(e);
19748 this.dragCurrent = null;
19749 this.dragOvers = {};
19753 * Internal function to handle the mousemove event. Will be invoked
19754 * from the context of the html element.
19756 * @TODO figure out what we can do about mouse events lost when the
19757 * user drags objects beyond the window boundary. Currently we can
19758 * detect this in internet explorer by verifying that the mouse is
19759 * down during the mousemove event. Firefox doesn't give us the
19760 * button state on the mousemove event.
19761 * @method handleMouseMove
19762 * @param {Event} e the event
19766 handleMouseMove: function(e) {
19767 if (! this.dragCurrent) {
19771 // var button = e.which || e.button;
19773 // check for IE mouseup outside of page boundary
19774 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19776 return this.handleMouseUp(e);
19779 if (!this.dragThreshMet) {
19780 var diffX = Math.abs(this.startX - e.getPageX());
19781 var diffY = Math.abs(this.startY - e.getPageY());
19782 if (diffX > this.clickPixelThresh ||
19783 diffY > this.clickPixelThresh) {
19784 this.startDrag(this.startX, this.startY);
19788 if (this.dragThreshMet) {
19789 this.dragCurrent.b4Drag(e);
19790 this.dragCurrent.onDrag(e);
19791 if(!this.dragCurrent.moveOnly){
19792 this.fireEvents(e, false);
19802 * Iterates over all of the DragDrop elements to find ones we are
19803 * hovering over or dropping on
19804 * @method fireEvents
19805 * @param {Event} e the event
19806 * @param {boolean} isDrop is this a drop op or a mouseover op?
19810 fireEvents: function(e, isDrop) {
19811 var dc = this.dragCurrent;
19813 // If the user did the mouse up outside of the window, we could
19814 // get here even though we have ended the drag.
19815 if (!dc || dc.isLocked()) {
19819 var pt = e.getPoint();
19821 // cache the previous dragOver array
19827 var enterEvts = [];
19829 // Check to see if the object(s) we were hovering over is no longer
19830 // being hovered over so we can fire the onDragOut event
19831 for (var i in this.dragOvers) {
19833 var ddo = this.dragOvers[i];
19835 if (! this.isTypeOfDD(ddo)) {
19839 if (! this.isOverTarget(pt, ddo, this.mode)) {
19840 outEvts.push( ddo );
19843 oldOvers[i] = true;
19844 delete this.dragOvers[i];
19847 for (var sGroup in dc.groups) {
19849 if ("string" != typeof sGroup) {
19853 for (i in this.ids[sGroup]) {
19854 var oDD = this.ids[sGroup][i];
19855 if (! this.isTypeOfDD(oDD)) {
19859 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19860 if (this.isOverTarget(pt, oDD, this.mode)) {
19861 // look for drop interactions
19863 dropEvts.push( oDD );
19864 // look for drag enter and drag over interactions
19867 // initial drag over: dragEnter fires
19868 if (!oldOvers[oDD.id]) {
19869 enterEvts.push( oDD );
19870 // subsequent drag overs: dragOver fires
19872 overEvts.push( oDD );
19875 this.dragOvers[oDD.id] = oDD;
19883 if (outEvts.length) {
19884 dc.b4DragOut(e, outEvts);
19885 dc.onDragOut(e, outEvts);
19888 if (enterEvts.length) {
19889 dc.onDragEnter(e, enterEvts);
19892 if (overEvts.length) {
19893 dc.b4DragOver(e, overEvts);
19894 dc.onDragOver(e, overEvts);
19897 if (dropEvts.length) {
19898 dc.b4DragDrop(e, dropEvts);
19899 dc.onDragDrop(e, dropEvts);
19903 // fire dragout events
19905 for (i=0, len=outEvts.length; i<len; ++i) {
19906 dc.b4DragOut(e, outEvts[i].id);
19907 dc.onDragOut(e, outEvts[i].id);
19910 // fire enter events
19911 for (i=0,len=enterEvts.length; i<len; ++i) {
19912 // dc.b4DragEnter(e, oDD.id);
19913 dc.onDragEnter(e, enterEvts[i].id);
19916 // fire over events
19917 for (i=0,len=overEvts.length; i<len; ++i) {
19918 dc.b4DragOver(e, overEvts[i].id);
19919 dc.onDragOver(e, overEvts[i].id);
19922 // fire drop events
19923 for (i=0, len=dropEvts.length; i<len; ++i) {
19924 dc.b4DragDrop(e, dropEvts[i].id);
19925 dc.onDragDrop(e, dropEvts[i].id);
19930 // notify about a drop that did not find a target
19931 if (isDrop && !dropEvts.length) {
19932 dc.onInvalidDrop(e);
19938 * Helper function for getting the best match from the list of drag
19939 * and drop objects returned by the drag and drop events when we are
19940 * in INTERSECT mode. It returns either the first object that the
19941 * cursor is over, or the object that has the greatest overlap with
19942 * the dragged element.
19943 * @method getBestMatch
19944 * @param {DragDrop[]} dds The array of drag and drop objects
19946 * @return {DragDrop} The best single match
19949 getBestMatch: function(dds) {
19951 // Return null if the input is not what we expect
19952 //if (!dds || !dds.length || dds.length == 0) {
19954 // If there is only one item, it wins
19955 //} else if (dds.length == 1) {
19957 var len = dds.length;
19962 // Loop through the targeted items
19963 for (var i=0; i<len; ++i) {
19965 // If the cursor is over the object, it wins. If the
19966 // cursor is over multiple matches, the first one we come
19968 if (dd.cursorIsOver) {
19971 // Otherwise the object with the most overlap wins
19974 winner.overlap.getArea() < dd.overlap.getArea()) {
19985 * Refreshes the cache of the top-left and bottom-right points of the
19986 * drag and drop objects in the specified group(s). This is in the
19987 * format that is stored in the drag and drop instance, so typical
19990 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19994 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19996 * @TODO this really should be an indexed array. Alternatively this
19997 * method could accept both.
19998 * @method refreshCache
19999 * @param {Object} groups an associative array of groups to refresh
20002 refreshCache: function(groups) {
20003 for (var sGroup in groups) {
20004 if ("string" != typeof sGroup) {
20007 for (var i in this.ids[sGroup]) {
20008 var oDD = this.ids[sGroup][i];
20010 if (this.isTypeOfDD(oDD)) {
20011 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20012 var loc = this.getLocation(oDD);
20014 this.locationCache[oDD.id] = loc;
20016 delete this.locationCache[oDD.id];
20017 // this will unregister the drag and drop object if
20018 // the element is not in a usable state
20027 * This checks to make sure an element exists and is in the DOM. The
20028 * main purpose is to handle cases where innerHTML is used to remove
20029 * drag and drop objects from the DOM. IE provides an 'unspecified
20030 * error' when trying to access the offsetParent of such an element
20032 * @param {HTMLElement} el the element to check
20033 * @return {boolean} true if the element looks usable
20036 verifyEl: function(el) {
20041 parent = el.offsetParent;
20044 parent = el.offsetParent;
20055 * Returns a Region object containing the drag and drop element's position
20056 * and size, including the padding configured for it
20057 * @method getLocation
20058 * @param {DragDrop} oDD the drag and drop object to get the
20060 * @return {Roo.lib.Region} a Region object representing the total area
20061 * the element occupies, including any padding
20062 * the instance is configured for.
20065 getLocation: function(oDD) {
20066 if (! this.isTypeOfDD(oDD)) {
20070 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20073 pos= Roo.lib.Dom.getXY(el);
20081 x2 = x1 + el.offsetWidth;
20083 y2 = y1 + el.offsetHeight;
20085 t = y1 - oDD.padding[0];
20086 r = x2 + oDD.padding[1];
20087 b = y2 + oDD.padding[2];
20088 l = x1 - oDD.padding[3];
20090 return new Roo.lib.Region( t, r, b, l );
20094 * Checks the cursor location to see if it over the target
20095 * @method isOverTarget
20096 * @param {Roo.lib.Point} pt The point to evaluate
20097 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20098 * @return {boolean} true if the mouse is over the target
20102 isOverTarget: function(pt, oTarget, intersect) {
20103 // use cache if available
20104 var loc = this.locationCache[oTarget.id];
20105 if (!loc || !this.useCache) {
20106 loc = this.getLocation(oTarget);
20107 this.locationCache[oTarget.id] = loc;
20115 oTarget.cursorIsOver = loc.contains( pt );
20117 // DragDrop is using this as a sanity check for the initial mousedown
20118 // in this case we are done. In POINT mode, if the drag obj has no
20119 // contraints, we are also done. Otherwise we need to evaluate the
20120 // location of the target as related to the actual location of the
20121 // dragged element.
20122 var dc = this.dragCurrent;
20123 if (!dc || !dc.getTargetCoord ||
20124 (!intersect && !dc.constrainX && !dc.constrainY)) {
20125 return oTarget.cursorIsOver;
20128 oTarget.overlap = null;
20130 // Get the current location of the drag element, this is the
20131 // location of the mouse event less the delta that represents
20132 // where the original mousedown happened on the element. We
20133 // need to consider constraints and ticks as well.
20134 var pos = dc.getTargetCoord(pt.x, pt.y);
20136 var el = dc.getDragEl();
20137 var curRegion = new Roo.lib.Region( pos.y,
20138 pos.x + el.offsetWidth,
20139 pos.y + el.offsetHeight,
20142 var overlap = curRegion.intersect(loc);
20145 oTarget.overlap = overlap;
20146 return (intersect) ? true : oTarget.cursorIsOver;
20153 * unload event handler
20154 * @method _onUnload
20158 _onUnload: function(e, me) {
20159 Roo.dd.DragDropMgr.unregAll();
20163 * Cleans up the drag and drop events and objects.
20168 unregAll: function() {
20170 if (this.dragCurrent) {
20172 this.dragCurrent = null;
20175 this._execOnAll("unreg", []);
20177 for (i in this.elementCache) {
20178 delete this.elementCache[i];
20181 this.elementCache = {};
20186 * A cache of DOM elements
20187 * @property elementCache
20194 * Get the wrapper for the DOM element specified
20195 * @method getElWrapper
20196 * @param {String} id the id of the element to get
20197 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20199 * @deprecated This wrapper isn't that useful
20202 getElWrapper: function(id) {
20203 var oWrapper = this.elementCache[id];
20204 if (!oWrapper || !oWrapper.el) {
20205 oWrapper = this.elementCache[id] =
20206 new this.ElementWrapper(Roo.getDom(id));
20212 * Returns the actual DOM element
20213 * @method getElement
20214 * @param {String} id the id of the elment to get
20215 * @return {Object} The element
20216 * @deprecated use Roo.getDom instead
20219 getElement: function(id) {
20220 return Roo.getDom(id);
20224 * Returns the style property for the DOM element (i.e.,
20225 * document.getElById(id).style)
20227 * @param {String} id the id of the elment to get
20228 * @return {Object} The style property of the element
20229 * @deprecated use Roo.getDom instead
20232 getCss: function(id) {
20233 var el = Roo.getDom(id);
20234 return (el) ? el.style : null;
20238 * Inner class for cached elements
20239 * @class DragDropMgr.ElementWrapper
20244 ElementWrapper: function(el) {
20249 this.el = el || null;
20254 this.id = this.el && el.id;
20256 * A reference to the style property
20259 this.css = this.el && el.style;
20263 * Returns the X position of an html element
20265 * @param el the element for which to get the position
20266 * @return {int} the X coordinate
20268 * @deprecated use Roo.lib.Dom.getX instead
20271 getPosX: function(el) {
20272 return Roo.lib.Dom.getX(el);
20276 * Returns the Y position of an html element
20278 * @param el the element for which to get the position
20279 * @return {int} the Y coordinate
20280 * @deprecated use Roo.lib.Dom.getY instead
20283 getPosY: function(el) {
20284 return Roo.lib.Dom.getY(el);
20288 * Swap two nodes. In IE, we use the native method, for others we
20289 * emulate the IE behavior
20291 * @param n1 the first node to swap
20292 * @param n2 the other node to swap
20295 swapNode: function(n1, n2) {
20299 var p = n2.parentNode;
20300 var s = n2.nextSibling;
20303 p.insertBefore(n1, n2);
20304 } else if (n2 == n1.nextSibling) {
20305 p.insertBefore(n2, n1);
20307 n1.parentNode.replaceChild(n2, n1);
20308 p.insertBefore(n1, s);
20314 * Returns the current scroll position
20315 * @method getScroll
20319 getScroll: function () {
20320 var t, l, dde=document.documentElement, db=document.body;
20321 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20323 l = dde.scrollLeft;
20330 return { top: t, left: l };
20334 * Returns the specified element style property
20336 * @param {HTMLElement} el the element
20337 * @param {string} styleProp the style property
20338 * @return {string} The value of the style property
20339 * @deprecated use Roo.lib.Dom.getStyle
20342 getStyle: function(el, styleProp) {
20343 return Roo.fly(el).getStyle(styleProp);
20347 * Gets the scrollTop
20348 * @method getScrollTop
20349 * @return {int} the document's scrollTop
20352 getScrollTop: function () { return this.getScroll().top; },
20355 * Gets the scrollLeft
20356 * @method getScrollLeft
20357 * @return {int} the document's scrollTop
20360 getScrollLeft: function () { return this.getScroll().left; },
20363 * Sets the x/y position of an element to the location of the
20366 * @param {HTMLElement} moveEl The element to move
20367 * @param {HTMLElement} targetEl The position reference element
20370 moveToEl: function (moveEl, targetEl) {
20371 var aCoord = Roo.lib.Dom.getXY(targetEl);
20372 Roo.lib.Dom.setXY(moveEl, aCoord);
20376 * Numeric array sort function
20377 * @method numericSort
20380 numericSort: function(a, b) { return (a - b); },
20384 * @property _timeoutCount
20391 * Trying to make the load order less important. Without this we get
20392 * an error if this file is loaded before the Event Utility.
20393 * @method _addListeners
20397 _addListeners: function() {
20398 var DDM = Roo.dd.DDM;
20399 if ( Roo.lib.Event && document ) {
20402 if (DDM._timeoutCount > 2000) {
20404 setTimeout(DDM._addListeners, 10);
20405 if (document && document.body) {
20406 DDM._timeoutCount += 1;
20413 * Recursively searches the immediate parent and all child nodes for
20414 * the handle element in order to determine wheter or not it was
20416 * @method handleWasClicked
20417 * @param node the html element to inspect
20420 handleWasClicked: function(node, id) {
20421 if (this.isHandle(id, node.id)) {
20424 // check to see if this is a text node child of the one we want
20425 var p = node.parentNode;
20428 if (this.isHandle(id, p.id)) {
20443 // shorter alias, save a few bytes
20444 Roo.dd.DDM = Roo.dd.DragDropMgr;
20445 Roo.dd.DDM._addListeners();
20449 * Ext JS Library 1.1.1
20450 * Copyright(c) 2006-2007, Ext JS, LLC.
20452 * Originally Released Under LGPL - original licence link has changed is not relivant.
20455 * <script type="text/javascript">
20460 * A DragDrop implementation where the linked element follows the
20461 * mouse cursor during a drag.
20462 * @extends Roo.dd.DragDrop
20464 * @param {String} id the id of the linked element
20465 * @param {String} sGroup the group of related DragDrop items
20466 * @param {object} config an object containing configurable attributes
20467 * Valid properties for DD:
20470 Roo.dd.DD = function(id, sGroup, config) {
20472 this.init(id, sGroup, config);
20476 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20479 * When set to true, the utility automatically tries to scroll the browser
20480 * window wehn a drag and drop element is dragged near the viewport boundary.
20481 * Defaults to true.
20488 * Sets the pointer offset to the distance between the linked element's top
20489 * left corner and the location the element was clicked
20490 * @method autoOffset
20491 * @param {int} iPageX the X coordinate of the click
20492 * @param {int} iPageY the Y coordinate of the click
20494 autoOffset: function(iPageX, iPageY) {
20495 var x = iPageX - this.startPageX;
20496 var y = iPageY - this.startPageY;
20497 this.setDelta(x, y);
20501 * Sets the pointer offset. You can call this directly to force the
20502 * offset to be in a particular location (e.g., pass in 0,0 to set it
20503 * to the center of the object)
20505 * @param {int} iDeltaX the distance from the left
20506 * @param {int} iDeltaY the distance from the top
20508 setDelta: function(iDeltaX, iDeltaY) {
20509 this.deltaX = iDeltaX;
20510 this.deltaY = iDeltaY;
20514 * Sets the drag element to the location of the mousedown or click event,
20515 * maintaining the cursor location relative to the location on the element
20516 * that was clicked. Override this if you want to place the element in a
20517 * location other than where the cursor is.
20518 * @method setDragElPos
20519 * @param {int} iPageX the X coordinate of the mousedown or drag event
20520 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20522 setDragElPos: function(iPageX, iPageY) {
20523 // the first time we do this, we are going to check to make sure
20524 // the element has css positioning
20526 var el = this.getDragEl();
20527 this.alignElWithMouse(el, iPageX, iPageY);
20531 * Sets the element to the location of the mousedown or click event,
20532 * maintaining the cursor location relative to the location on the element
20533 * that was clicked. Override this if you want to place the element in a
20534 * location other than where the cursor is.
20535 * @method alignElWithMouse
20536 * @param {HTMLElement} el the element to move
20537 * @param {int} iPageX the X coordinate of the mousedown or drag event
20538 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20540 alignElWithMouse: function(el, iPageX, iPageY) {
20541 var oCoord = this.getTargetCoord(iPageX, iPageY);
20542 var fly = el.dom ? el : Roo.fly(el);
20543 if (!this.deltaSetXY) {
20544 var aCoord = [oCoord.x, oCoord.y];
20546 var newLeft = fly.getLeft(true);
20547 var newTop = fly.getTop(true);
20548 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20550 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20553 this.cachePosition(oCoord.x, oCoord.y);
20554 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20559 * Saves the most recent position so that we can reset the constraints and
20560 * tick marks on-demand. We need to know this so that we can calculate the
20561 * number of pixels the element is offset from its original position.
20562 * @method cachePosition
20563 * @param iPageX the current x position (optional, this just makes it so we
20564 * don't have to look it up again)
20565 * @param iPageY the current y position (optional, this just makes it so we
20566 * don't have to look it up again)
20568 cachePosition: function(iPageX, iPageY) {
20570 this.lastPageX = iPageX;
20571 this.lastPageY = iPageY;
20573 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20574 this.lastPageX = aCoord[0];
20575 this.lastPageY = aCoord[1];
20580 * Auto-scroll the window if the dragged object has been moved beyond the
20581 * visible window boundary.
20582 * @method autoScroll
20583 * @param {int} x the drag element's x position
20584 * @param {int} y the drag element's y position
20585 * @param {int} h the height of the drag element
20586 * @param {int} w the width of the drag element
20589 autoScroll: function(x, y, h, w) {
20592 // The client height
20593 var clientH = Roo.lib.Dom.getViewWidth();
20595 // The client width
20596 var clientW = Roo.lib.Dom.getViewHeight();
20598 // The amt scrolled down
20599 var st = this.DDM.getScrollTop();
20601 // The amt scrolled right
20602 var sl = this.DDM.getScrollLeft();
20604 // Location of the bottom of the element
20607 // Location of the right of the element
20610 // The distance from the cursor to the bottom of the visible area,
20611 // adjusted so that we don't scroll if the cursor is beyond the
20612 // element drag constraints
20613 var toBot = (clientH + st - y - this.deltaY);
20615 // The distance from the cursor to the right of the visible area
20616 var toRight = (clientW + sl - x - this.deltaX);
20619 // How close to the edge the cursor must be before we scroll
20620 // var thresh = (document.all) ? 100 : 40;
20623 // How many pixels to scroll per autoscroll op. This helps to reduce
20624 // clunky scrolling. IE is more sensitive about this ... it needs this
20625 // value to be higher.
20626 var scrAmt = (document.all) ? 80 : 30;
20628 // Scroll down if we are near the bottom of the visible page and the
20629 // obj extends below the crease
20630 if ( bot > clientH && toBot < thresh ) {
20631 window.scrollTo(sl, st + scrAmt);
20634 // Scroll up if the window is scrolled down and the top of the object
20635 // goes above the top border
20636 if ( y < st && st > 0 && y - st < thresh ) {
20637 window.scrollTo(sl, st - scrAmt);
20640 // Scroll right if the obj is beyond the right border and the cursor is
20641 // near the border.
20642 if ( right > clientW && toRight < thresh ) {
20643 window.scrollTo(sl + scrAmt, st);
20646 // Scroll left if the window has been scrolled to the right and the obj
20647 // extends past the left border
20648 if ( x < sl && sl > 0 && x - sl < thresh ) {
20649 window.scrollTo(sl - scrAmt, st);
20655 * Finds the location the element should be placed if we want to move
20656 * it to where the mouse location less the click offset would place us.
20657 * @method getTargetCoord
20658 * @param {int} iPageX the X coordinate of the click
20659 * @param {int} iPageY the Y coordinate of the click
20660 * @return an object that contains the coordinates (Object.x and Object.y)
20663 getTargetCoord: function(iPageX, iPageY) {
20666 var x = iPageX - this.deltaX;
20667 var y = iPageY - this.deltaY;
20669 if (this.constrainX) {
20670 if (x < this.minX) { x = this.minX; }
20671 if (x > this.maxX) { x = this.maxX; }
20674 if (this.constrainY) {
20675 if (y < this.minY) { y = this.minY; }
20676 if (y > this.maxY) { y = this.maxY; }
20679 x = this.getTick(x, this.xTicks);
20680 y = this.getTick(y, this.yTicks);
20687 * Sets up config options specific to this class. Overrides
20688 * Roo.dd.DragDrop, but all versions of this method through the
20689 * inheritance chain are called
20691 applyConfig: function() {
20692 Roo.dd.DD.superclass.applyConfig.call(this);
20693 this.scroll = (this.config.scroll !== false);
20697 * Event that fires prior to the onMouseDown event. Overrides
20700 b4MouseDown: function(e) {
20701 // this.resetConstraints();
20702 this.autoOffset(e.getPageX(),
20707 * Event that fires prior to the onDrag event. Overrides
20710 b4Drag: function(e) {
20711 this.setDragElPos(e.getPageX(),
20715 toString: function() {
20716 return ("DD " + this.id);
20719 //////////////////////////////////////////////////////////////////////////
20720 // Debugging ygDragDrop events that can be overridden
20721 //////////////////////////////////////////////////////////////////////////
20723 startDrag: function(x, y) {
20726 onDrag: function(e) {
20729 onDragEnter: function(e, id) {
20732 onDragOver: function(e, id) {
20735 onDragOut: function(e, id) {
20738 onDragDrop: function(e, id) {
20741 endDrag: function(e) {
20748 * Ext JS Library 1.1.1
20749 * Copyright(c) 2006-2007, Ext JS, LLC.
20751 * Originally Released Under LGPL - original licence link has changed is not relivant.
20754 * <script type="text/javascript">
20758 * @class Roo.dd.DDProxy
20759 * A DragDrop implementation that inserts an empty, bordered div into
20760 * the document that follows the cursor during drag operations. At the time of
20761 * the click, the frame div is resized to the dimensions of the linked html
20762 * element, and moved to the exact location of the linked element.
20764 * References to the "frame" element refer to the single proxy element that
20765 * was created to be dragged in place of all DDProxy elements on the
20768 * @extends Roo.dd.DD
20770 * @param {String} id the id of the linked html element
20771 * @param {String} sGroup the group of related DragDrop objects
20772 * @param {object} config an object containing configurable attributes
20773 * Valid properties for DDProxy in addition to those in DragDrop:
20774 * resizeFrame, centerFrame, dragElId
20776 Roo.dd.DDProxy = function(id, sGroup, config) {
20778 this.init(id, sGroup, config);
20784 * The default drag frame div id
20785 * @property Roo.dd.DDProxy.dragElId
20789 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20791 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20794 * By default we resize the drag frame to be the same size as the element
20795 * we want to drag (this is to get the frame effect). We can turn it off
20796 * if we want a different behavior.
20797 * @property resizeFrame
20803 * By default the frame is positioned exactly where the drag element is, so
20804 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20805 * you do not have constraints on the obj is to have the drag frame centered
20806 * around the cursor. Set centerFrame to true for this effect.
20807 * @property centerFrame
20810 centerFrame: false,
20813 * Creates the proxy element if it does not yet exist
20814 * @method createFrame
20816 createFrame: function() {
20818 var body = document.body;
20820 if (!body || !body.firstChild) {
20821 setTimeout( function() { self.createFrame(); }, 50 );
20825 var div = this.getDragEl();
20828 div = document.createElement("div");
20829 div.id = this.dragElId;
20832 s.position = "absolute";
20833 s.visibility = "hidden";
20835 s.border = "2px solid #aaa";
20838 // appendChild can blow up IE if invoked prior to the window load event
20839 // while rendering a table. It is possible there are other scenarios
20840 // that would cause this to happen as well.
20841 body.insertBefore(div, body.firstChild);
20846 * Initialization for the drag frame element. Must be called in the
20847 * constructor of all subclasses
20848 * @method initFrame
20850 initFrame: function() {
20851 this.createFrame();
20854 applyConfig: function() {
20855 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20857 this.resizeFrame = (this.config.resizeFrame !== false);
20858 this.centerFrame = (this.config.centerFrame);
20859 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20863 * Resizes the drag frame to the dimensions of the clicked object, positions
20864 * it over the object, and finally displays it
20865 * @method showFrame
20866 * @param {int} iPageX X click position
20867 * @param {int} iPageY Y click position
20870 showFrame: function(iPageX, iPageY) {
20871 var el = this.getEl();
20872 var dragEl = this.getDragEl();
20873 var s = dragEl.style;
20875 this._resizeProxy();
20877 if (this.centerFrame) {
20878 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20879 Math.round(parseInt(s.height, 10)/2) );
20882 this.setDragElPos(iPageX, iPageY);
20884 Roo.fly(dragEl).show();
20888 * The proxy is automatically resized to the dimensions of the linked
20889 * element when a drag is initiated, unless resizeFrame is set to false
20890 * @method _resizeProxy
20893 _resizeProxy: function() {
20894 if (this.resizeFrame) {
20895 var el = this.getEl();
20896 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20900 // overrides Roo.dd.DragDrop
20901 b4MouseDown: function(e) {
20902 var x = e.getPageX();
20903 var y = e.getPageY();
20904 this.autoOffset(x, y);
20905 this.setDragElPos(x, y);
20908 // overrides Roo.dd.DragDrop
20909 b4StartDrag: function(x, y) {
20910 // show the drag frame
20911 this.showFrame(x, y);
20914 // overrides Roo.dd.DragDrop
20915 b4EndDrag: function(e) {
20916 Roo.fly(this.getDragEl()).hide();
20919 // overrides Roo.dd.DragDrop
20920 // By default we try to move the element to the last location of the frame.
20921 // This is so that the default behavior mirrors that of Roo.dd.DD.
20922 endDrag: function(e) {
20924 var lel = this.getEl();
20925 var del = this.getDragEl();
20927 // Show the drag frame briefly so we can get its position
20928 del.style.visibility = "";
20931 // Hide the linked element before the move to get around a Safari
20933 lel.style.visibility = "hidden";
20934 Roo.dd.DDM.moveToEl(lel, del);
20935 del.style.visibility = "hidden";
20936 lel.style.visibility = "";
20941 beforeMove : function(){
20945 afterDrag : function(){
20949 toString: function() {
20950 return ("DDProxy " + this.id);
20956 * Ext JS Library 1.1.1
20957 * Copyright(c) 2006-2007, Ext JS, LLC.
20959 * Originally Released Under LGPL - original licence link has changed is not relivant.
20962 * <script type="text/javascript">
20966 * @class Roo.dd.DDTarget
20967 * A DragDrop implementation that does not move, but can be a drop
20968 * target. You would get the same result by simply omitting implementation
20969 * for the event callbacks, but this way we reduce the processing cost of the
20970 * event listener and the callbacks.
20971 * @extends Roo.dd.DragDrop
20973 * @param {String} id the id of the element that is a drop target
20974 * @param {String} sGroup the group of related DragDrop objects
20975 * @param {object} config an object containing configurable attributes
20976 * Valid properties for DDTarget in addition to those in
20980 Roo.dd.DDTarget = function(id, sGroup, config) {
20982 this.initTarget(id, sGroup, config);
20984 if (config.listeners || config.events) {
20985 Roo.dd.DragDrop.superclass.constructor.call(this, {
20986 listeners : config.listeners || {},
20987 events : config.events || {}
20992 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20993 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20994 toString: function() {
20995 return ("DDTarget " + this.id);
21000 * Ext JS Library 1.1.1
21001 * Copyright(c) 2006-2007, Ext JS, LLC.
21003 * Originally Released Under LGPL - original licence link has changed is not relivant.
21006 * <script type="text/javascript">
21011 * @class Roo.dd.ScrollManager
21012 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21013 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21016 Roo.dd.ScrollManager = function(){
21017 var ddm = Roo.dd.DragDropMgr;
21024 var onStop = function(e){
21029 var triggerRefresh = function(){
21030 if(ddm.dragCurrent){
21031 ddm.refreshCache(ddm.dragCurrent.groups);
21035 var doScroll = function(){
21036 if(ddm.dragCurrent){
21037 var dds = Roo.dd.ScrollManager;
21039 if(proc.el.scroll(proc.dir, dds.increment)){
21043 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21048 var clearProc = function(){
21050 clearInterval(proc.id);
21057 var startProc = function(el, dir){
21058 Roo.log('scroll startproc');
21062 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21065 var onFire = function(e, isDrop){
21067 if(isDrop || !ddm.dragCurrent){ return; }
21068 var dds = Roo.dd.ScrollManager;
21069 if(!dragEl || dragEl != ddm.dragCurrent){
21070 dragEl = ddm.dragCurrent;
21071 // refresh regions on drag start
21072 dds.refreshCache();
21075 var xy = Roo.lib.Event.getXY(e);
21076 var pt = new Roo.lib.Point(xy[0], xy[1]);
21077 for(var id in els){
21078 var el = els[id], r = el._region;
21079 if(r && r.contains(pt) && el.isScrollable()){
21080 if(r.bottom - pt.y <= dds.thresh){
21082 startProc(el, "down");
21085 }else if(r.right - pt.x <= dds.thresh){
21087 startProc(el, "left");
21090 }else if(pt.y - r.top <= dds.thresh){
21092 startProc(el, "up");
21095 }else if(pt.x - r.left <= dds.thresh){
21097 startProc(el, "right");
21106 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21107 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21111 * Registers new overflow element(s) to auto scroll
21112 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21114 register : function(el){
21115 if(el instanceof Array){
21116 for(var i = 0, len = el.length; i < len; i++) {
21117 this.register(el[i]);
21123 Roo.dd.ScrollManager.els = els;
21127 * Unregisters overflow element(s) so they are no longer scrolled
21128 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21130 unregister : function(el){
21131 if(el instanceof Array){
21132 for(var i = 0, len = el.length; i < len; i++) {
21133 this.unregister(el[i]);
21142 * The number of pixels from the edge of a container the pointer needs to be to
21143 * trigger scrolling (defaults to 25)
21149 * The number of pixels to scroll in each scroll increment (defaults to 50)
21155 * The frequency of scrolls in milliseconds (defaults to 500)
21161 * True to animate the scroll (defaults to true)
21167 * The animation duration in seconds -
21168 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21174 * Manually trigger a cache refresh.
21176 refreshCache : function(){
21177 for(var id in els){
21178 if(typeof els[id] == 'object'){ // for people extending the object prototype
21179 els[id]._region = els[id].getRegion();
21186 * Ext JS Library 1.1.1
21187 * Copyright(c) 2006-2007, Ext JS, LLC.
21189 * Originally Released Under LGPL - original licence link has changed is not relivant.
21192 * <script type="text/javascript">
21197 * @class Roo.dd.Registry
21198 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21199 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21202 Roo.dd.Registry = function(){
21205 var autoIdSeed = 0;
21207 var getId = function(el, autogen){
21208 if(typeof el == "string"){
21212 if(!id && autogen !== false){
21213 id = "roodd-" + (++autoIdSeed);
21221 * Register a drag drop element
21222 * @param {String|HTMLElement} element The id or DOM node to register
21223 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21224 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21225 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21226 * populated in the data object (if applicable):
21228 Value Description<br />
21229 --------- ------------------------------------------<br />
21230 handles Array of DOM nodes that trigger dragging<br />
21231 for the element being registered<br />
21232 isHandle True if the element passed in triggers<br />
21233 dragging itself, else false
21236 register : function(el, data){
21238 if(typeof el == "string"){
21239 el = document.getElementById(el);
21242 elements[getId(el)] = data;
21243 if(data.isHandle !== false){
21244 handles[data.ddel.id] = data;
21247 var hs = data.handles;
21248 for(var i = 0, len = hs.length; i < len; i++){
21249 handles[getId(hs[i])] = data;
21255 * Unregister a drag drop element
21256 * @param {String|HTMLElement} element The id or DOM node to unregister
21258 unregister : function(el){
21259 var id = getId(el, false);
21260 var data = elements[id];
21262 delete elements[id];
21264 var hs = data.handles;
21265 for(var i = 0, len = hs.length; i < len; i++){
21266 delete handles[getId(hs[i], false)];
21273 * Returns the handle registered for a DOM Node by id
21274 * @param {String|HTMLElement} id The DOM node or id to look up
21275 * @return {Object} handle The custom handle data
21277 getHandle : function(id){
21278 if(typeof id != "string"){ // must be element?
21281 return handles[id];
21285 * Returns the handle that is registered for the DOM node that is the target of the event
21286 * @param {Event} e The event
21287 * @return {Object} handle The custom handle data
21289 getHandleFromEvent : function(e){
21290 var t = Roo.lib.Event.getTarget(e);
21291 return t ? handles[t.id] : null;
21295 * Returns a custom data object that is registered for a DOM node by id
21296 * @param {String|HTMLElement} id The DOM node or id to look up
21297 * @return {Object} data The custom data
21299 getTarget : function(id){
21300 if(typeof id != "string"){ // must be element?
21303 return elements[id];
21307 * Returns a custom data object that is registered for the DOM node that is the target of the event
21308 * @param {Event} e The event
21309 * @return {Object} data The custom data
21311 getTargetFromEvent : function(e){
21312 var t = Roo.lib.Event.getTarget(e);
21313 return t ? elements[t.id] || handles[t.id] : null;
21318 * Ext JS Library 1.1.1
21319 * Copyright(c) 2006-2007, Ext JS, LLC.
21321 * Originally Released Under LGPL - original licence link has changed is not relivant.
21324 * <script type="text/javascript">
21329 * @class Roo.dd.StatusProxy
21330 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21331 * default drag proxy used by all Roo.dd components.
21333 * @param {Object} config
21335 Roo.dd.StatusProxy = function(config){
21336 Roo.apply(this, config);
21337 this.id = this.id || Roo.id();
21338 this.el = new Roo.Layer({
21340 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21341 {tag: "div", cls: "x-dd-drop-icon"},
21342 {tag: "div", cls: "x-dd-drag-ghost"}
21345 shadow: !config || config.shadow !== false
21347 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21348 this.dropStatus = this.dropNotAllowed;
21351 Roo.dd.StatusProxy.prototype = {
21353 * @cfg {String} dropAllowed
21354 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21356 dropAllowed : "x-dd-drop-ok",
21358 * @cfg {String} dropNotAllowed
21359 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21361 dropNotAllowed : "x-dd-drop-nodrop",
21364 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21365 * over the current target element.
21366 * @param {String} cssClass The css class for the new drop status indicator image
21368 setStatus : function(cssClass){
21369 cssClass = cssClass || this.dropNotAllowed;
21370 if(this.dropStatus != cssClass){
21371 this.el.replaceClass(this.dropStatus, cssClass);
21372 this.dropStatus = cssClass;
21377 * Resets the status indicator to the default dropNotAllowed value
21378 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21380 reset : function(clearGhost){
21381 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21382 this.dropStatus = this.dropNotAllowed;
21384 this.ghost.update("");
21389 * Updates the contents of the ghost element
21390 * @param {String} html The html that will replace the current innerHTML of the ghost element
21392 update : function(html){
21393 if(typeof html == "string"){
21394 this.ghost.update(html);
21396 this.ghost.update("");
21397 html.style.margin = "0";
21398 this.ghost.dom.appendChild(html);
21400 // ensure float = none set?? cant remember why though.
21401 var el = this.ghost.dom.firstChild;
21403 Roo.fly(el).setStyle('float', 'none');
21408 * Returns the underlying proxy {@link Roo.Layer}
21409 * @return {Roo.Layer} el
21411 getEl : function(){
21416 * Returns the ghost element
21417 * @return {Roo.Element} el
21419 getGhost : function(){
21425 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21427 hide : function(clear){
21435 * Stops the repair animation if it's currently running
21438 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21444 * Displays this proxy
21451 * Force the Layer to sync its shadow and shim positions to the element
21458 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21459 * invalid drop operation by the item being dragged.
21460 * @param {Array} xy The XY position of the element ([x, y])
21461 * @param {Function} callback The function to call after the repair is complete
21462 * @param {Object} scope The scope in which to execute the callback
21464 repair : function(xy, callback, scope){
21465 this.callback = callback;
21466 this.scope = scope;
21467 if(xy && this.animRepair !== false){
21468 this.el.addClass("x-dd-drag-repair");
21469 this.el.hideUnders(true);
21470 this.anim = this.el.shift({
21471 duration: this.repairDuration || .5,
21475 callback: this.afterRepair,
21479 this.afterRepair();
21484 afterRepair : function(){
21486 if(typeof this.callback == "function"){
21487 this.callback.call(this.scope || this);
21489 this.callback = null;
21494 * Ext JS Library 1.1.1
21495 * Copyright(c) 2006-2007, Ext JS, LLC.
21497 * Originally Released Under LGPL - original licence link has changed is not relivant.
21500 * <script type="text/javascript">
21504 * @class Roo.dd.DragSource
21505 * @extends Roo.dd.DDProxy
21506 * A simple class that provides the basic implementation needed to make any element draggable.
21508 * @param {String/HTMLElement/Element} el The container element
21509 * @param {Object} config
21511 Roo.dd.DragSource = function(el, config){
21512 this.el = Roo.get(el);
21513 this.dragData = {};
21515 Roo.apply(this, config);
21518 this.proxy = new Roo.dd.StatusProxy();
21521 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21522 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21524 this.dragging = false;
21527 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21529 * @cfg {String} dropAllowed
21530 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21532 dropAllowed : "x-dd-drop-ok",
21534 * @cfg {String} dropNotAllowed
21535 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21537 dropNotAllowed : "x-dd-drop-nodrop",
21540 * Returns the data object associated with this drag source
21541 * @return {Object} data An object containing arbitrary data
21543 getDragData : function(e){
21544 return this.dragData;
21548 onDragEnter : function(e, id){
21549 var target = Roo.dd.DragDropMgr.getDDById(id);
21550 this.cachedTarget = target;
21551 if(this.beforeDragEnter(target, e, id) !== false){
21552 if(target.isNotifyTarget){
21553 var status = target.notifyEnter(this, e, this.dragData);
21554 this.proxy.setStatus(status);
21556 this.proxy.setStatus(this.dropAllowed);
21559 if(this.afterDragEnter){
21561 * An empty function by default, but provided so that you can perform a custom action
21562 * when the dragged item enters the drop target by providing an implementation.
21563 * @param {Roo.dd.DragDrop} target The drop target
21564 * @param {Event} e The event object
21565 * @param {String} id The id of the dragged element
21566 * @method afterDragEnter
21568 this.afterDragEnter(target, e, id);
21574 * An empty function by default, but provided so that you can perform a custom action
21575 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21576 * @param {Roo.dd.DragDrop} target The drop target
21577 * @param {Event} e The event object
21578 * @param {String} id The id of the dragged element
21579 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21581 beforeDragEnter : function(target, e, id){
21586 alignElWithMouse: function() {
21587 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21592 onDragOver : function(e, id){
21593 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21594 if(this.beforeDragOver(target, e, id) !== false){
21595 if(target.isNotifyTarget){
21596 var status = target.notifyOver(this, e, this.dragData);
21597 this.proxy.setStatus(status);
21600 if(this.afterDragOver){
21602 * An empty function by default, but provided so that you can perform a custom action
21603 * while the dragged item is over the drop target by providing an implementation.
21604 * @param {Roo.dd.DragDrop} target The drop target
21605 * @param {Event} e The event object
21606 * @param {String} id The id of the dragged element
21607 * @method afterDragOver
21609 this.afterDragOver(target, e, id);
21615 * An empty function by default, but provided so that you can perform a custom action
21616 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21617 * @param {Roo.dd.DragDrop} target The drop target
21618 * @param {Event} e The event object
21619 * @param {String} id The id of the dragged element
21620 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21622 beforeDragOver : function(target, e, id){
21627 onDragOut : function(e, id){
21628 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21629 if(this.beforeDragOut(target, e, id) !== false){
21630 if(target.isNotifyTarget){
21631 target.notifyOut(this, e, this.dragData);
21633 this.proxy.reset();
21634 if(this.afterDragOut){
21636 * An empty function by default, but provided so that you can perform a custom action
21637 * after the dragged item is dragged out of the target without dropping.
21638 * @param {Roo.dd.DragDrop} target The drop target
21639 * @param {Event} e The event object
21640 * @param {String} id The id of the dragged element
21641 * @method afterDragOut
21643 this.afterDragOut(target, e, id);
21646 this.cachedTarget = null;
21650 * An empty function by default, but provided so that you can perform a custom action before the dragged
21651 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21652 * @param {Roo.dd.DragDrop} target The drop target
21653 * @param {Event} e The event object
21654 * @param {String} id The id of the dragged element
21655 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21657 beforeDragOut : function(target, e, id){
21662 onDragDrop : function(e, id){
21663 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21664 if(this.beforeDragDrop(target, e, id) !== false){
21665 if(target.isNotifyTarget){
21666 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21667 this.onValidDrop(target, e, id);
21669 this.onInvalidDrop(target, e, id);
21672 this.onValidDrop(target, e, id);
21675 if(this.afterDragDrop){
21677 * An empty function by default, but provided so that you can perform a custom action
21678 * after a valid drag drop has occurred by providing an implementation.
21679 * @param {Roo.dd.DragDrop} target The drop target
21680 * @param {Event} e The event object
21681 * @param {String} id The id of the dropped element
21682 * @method afterDragDrop
21684 this.afterDragDrop(target, e, id);
21687 delete this.cachedTarget;
21691 * An empty function by default, but provided so that you can perform a custom action before the dragged
21692 * item is dropped onto the target and optionally cancel the onDragDrop.
21693 * @param {Roo.dd.DragDrop} target The drop target
21694 * @param {Event} e The event object
21695 * @param {String} id The id of the dragged element
21696 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21698 beforeDragDrop : function(target, e, id){
21703 onValidDrop : function(target, e, id){
21705 if(this.afterValidDrop){
21707 * An empty function by default, but provided so that you can perform a custom action
21708 * after a valid drop has occurred by providing an implementation.
21709 * @param {Object} target The target DD
21710 * @param {Event} e The event object
21711 * @param {String} id The id of the dropped element
21712 * @method afterInvalidDrop
21714 this.afterValidDrop(target, e, id);
21719 getRepairXY : function(e, data){
21720 return this.el.getXY();
21724 onInvalidDrop : function(target, e, id){
21725 this.beforeInvalidDrop(target, e, id);
21726 if(this.cachedTarget){
21727 if(this.cachedTarget.isNotifyTarget){
21728 this.cachedTarget.notifyOut(this, e, this.dragData);
21730 this.cacheTarget = null;
21732 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21734 if(this.afterInvalidDrop){
21736 * An empty function by default, but provided so that you can perform a custom action
21737 * after an invalid drop has occurred by providing an implementation.
21738 * @param {Event} e The event object
21739 * @param {String} id The id of the dropped element
21740 * @method afterInvalidDrop
21742 this.afterInvalidDrop(e, id);
21747 afterRepair : function(){
21749 this.el.highlight(this.hlColor || "c3daf9");
21751 this.dragging = false;
21755 * An empty function by default, but provided so that you can perform a custom action after an invalid
21756 * drop has occurred.
21757 * @param {Roo.dd.DragDrop} target The drop target
21758 * @param {Event} e The event object
21759 * @param {String} id The id of the dragged element
21760 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21762 beforeInvalidDrop : function(target, e, id){
21767 handleMouseDown : function(e){
21768 if(this.dragging) {
21771 var data = this.getDragData(e);
21772 if(data && this.onBeforeDrag(data, e) !== false){
21773 this.dragData = data;
21775 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21780 * An empty function by default, but provided so that you can perform a custom action before the initial
21781 * drag event begins and optionally cancel it.
21782 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21783 * @param {Event} e The event object
21784 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21786 onBeforeDrag : function(data, e){
21791 * An empty function by default, but provided so that you can perform a custom action once the initial
21792 * drag event has begun. The drag cannot be canceled from this function.
21793 * @param {Number} x The x position of the click on the dragged object
21794 * @param {Number} y The y position of the click on the dragged object
21796 onStartDrag : Roo.emptyFn,
21798 // private - YUI override
21799 startDrag : function(x, y){
21800 this.proxy.reset();
21801 this.dragging = true;
21802 this.proxy.update("");
21803 this.onInitDrag(x, y);
21808 onInitDrag : function(x, y){
21809 var clone = this.el.dom.cloneNode(true);
21810 clone.id = Roo.id(); // prevent duplicate ids
21811 this.proxy.update(clone);
21812 this.onStartDrag(x, y);
21817 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21818 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21820 getProxy : function(){
21825 * Hides the drag source's {@link Roo.dd.StatusProxy}
21827 hideProxy : function(){
21829 this.proxy.reset(true);
21830 this.dragging = false;
21834 triggerCacheRefresh : function(){
21835 Roo.dd.DDM.refreshCache(this.groups);
21838 // private - override to prevent hiding
21839 b4EndDrag: function(e) {
21842 // private - override to prevent moving
21843 endDrag : function(e){
21844 this.onEndDrag(this.dragData, e);
21848 onEndDrag : function(data, e){
21851 // private - pin to cursor
21852 autoOffset : function(x, y) {
21853 this.setDelta(-12, -20);
21857 * Ext JS Library 1.1.1
21858 * Copyright(c) 2006-2007, Ext JS, LLC.
21860 * Originally Released Under LGPL - original licence link has changed is not relivant.
21863 * <script type="text/javascript">
21868 * @class Roo.dd.DropTarget
21869 * @extends Roo.dd.DDTarget
21870 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21871 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21873 * @param {String/HTMLElement/Element} el The container element
21874 * @param {Object} config
21876 Roo.dd.DropTarget = function(el, config){
21877 this.el = Roo.get(el);
21879 var listeners = false; ;
21880 if (config && config.listeners) {
21881 listeners= config.listeners;
21882 delete config.listeners;
21884 Roo.apply(this, config);
21886 if(this.containerScroll){
21887 Roo.dd.ScrollManager.register(this.el);
21891 * @scope Roo.dd.DropTarget
21896 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21897 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21898 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21900 * IMPORTANT : it should set this.overClass and this.dropAllowed
21902 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21903 * @param {Event} e The event
21904 * @param {Object} data An object containing arbitrary data supplied by the drag source
21910 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21911 * This method will be called on every mouse movement while the drag source is over the drop target.
21912 * This default implementation simply returns the dropAllowed config value.
21914 * IMPORTANT : it should set this.dropAllowed
21916 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21917 * @param {Event} e The event
21918 * @param {Object} data An object containing arbitrary data supplied by the drag source
21924 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21925 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21926 * overClass (if any) from the drop element.
21928 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21929 * @param {Event} e The event
21930 * @param {Object} data An object containing arbitrary data supplied by the drag source
21936 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21937 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21938 * implementation that does something to process the drop event and returns true so that the drag source's
21939 * repair action does not run.
21941 * IMPORTANT : it should set this.success
21943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21944 * @param {Event} e The event
21945 * @param {Object} data An object containing arbitrary data supplied by the drag source
21951 Roo.dd.DropTarget.superclass.constructor.call( this,
21953 this.ddGroup || this.group,
21956 listeners : listeners || {}
21964 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21966 * @cfg {String} overClass
21967 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21970 * @cfg {String} ddGroup
21971 * The drag drop group to handle drop events for
21975 * @cfg {String} dropAllowed
21976 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21978 dropAllowed : "x-dd-drop-ok",
21980 * @cfg {String} dropNotAllowed
21981 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21983 dropNotAllowed : "x-dd-drop-nodrop",
21985 * @cfg {boolean} success
21986 * set this after drop listener..
21990 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21991 * if the drop point is valid for over/enter..
21998 isNotifyTarget : true,
22003 notifyEnter : function(dd, e, data)
22006 this.fireEvent('enter', dd, e, data);
22007 if(this.overClass){
22008 this.el.addClass(this.overClass);
22010 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22011 this.valid ? this.dropAllowed : this.dropNotAllowed
22018 notifyOver : function(dd, e, data)
22021 this.fireEvent('over', dd, e, data);
22022 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22023 this.valid ? this.dropAllowed : this.dropNotAllowed
22030 notifyOut : function(dd, e, data)
22032 this.fireEvent('out', dd, e, data);
22033 if(this.overClass){
22034 this.el.removeClass(this.overClass);
22041 notifyDrop : function(dd, e, data)
22043 this.success = false;
22044 this.fireEvent('drop', dd, e, data);
22045 return this.success;
22049 * Ext JS Library 1.1.1
22050 * Copyright(c) 2006-2007, Ext JS, LLC.
22052 * Originally Released Under LGPL - original licence link has changed is not relivant.
22055 * <script type="text/javascript">
22060 * @class Roo.dd.DragZone
22061 * @extends Roo.dd.DragSource
22062 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22063 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22065 * @param {String/HTMLElement/Element} el The container element
22066 * @param {Object} config
22068 Roo.dd.DragZone = function(el, config){
22069 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22070 if(this.containerScroll){
22071 Roo.dd.ScrollManager.register(this.el);
22075 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22077 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22078 * for auto scrolling during drag operations.
22081 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22082 * method after a failed drop (defaults to "c3daf9" - light blue)
22086 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22087 * for a valid target to drag based on the mouse down. Override this method
22088 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22089 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22090 * @param {EventObject} e The mouse down event
22091 * @return {Object} The dragData
22093 getDragData : function(e){
22094 return Roo.dd.Registry.getHandleFromEvent(e);
22098 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22099 * this.dragData.ddel
22100 * @param {Number} x The x position of the click on the dragged object
22101 * @param {Number} y The y position of the click on the dragged object
22102 * @return {Boolean} true to continue the drag, false to cancel
22104 onInitDrag : function(x, y){
22105 this.proxy.update(this.dragData.ddel.cloneNode(true));
22106 this.onStartDrag(x, y);
22111 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22113 afterRepair : function(){
22115 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22117 this.dragging = false;
22121 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22122 * the XY of this.dragData.ddel
22123 * @param {EventObject} e The mouse up event
22124 * @return {Array} The xy location (e.g. [100, 200])
22126 getRepairXY : function(e){
22127 return Roo.Element.fly(this.dragData.ddel).getXY();
22131 * Ext JS Library 1.1.1
22132 * Copyright(c) 2006-2007, Ext JS, LLC.
22134 * Originally Released Under LGPL - original licence link has changed is not relivant.
22137 * <script type="text/javascript">
22140 * @class Roo.dd.DropZone
22141 * @extends Roo.dd.DropTarget
22142 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22143 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22145 * @param {String/HTMLElement/Element} el The container element
22146 * @param {Object} config
22148 Roo.dd.DropZone = function(el, config){
22149 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22152 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22154 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22155 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22156 * provide your own custom lookup.
22157 * @param {Event} e The event
22158 * @return {Object} data The custom data
22160 getTargetFromEvent : function(e){
22161 return Roo.dd.Registry.getTargetFromEvent(e);
22165 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22166 * that it has registered. This method has no default implementation and should be overridden to provide
22167 * node-specific processing if necessary.
22168 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22169 * {@link #getTargetFromEvent} for this node)
22170 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22171 * @param {Event} e The event
22172 * @param {Object} data An object containing arbitrary data supplied by the drag source
22174 onNodeEnter : function(n, dd, e, data){
22179 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22180 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22181 * overridden to provide the proper feedback.
22182 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22183 * {@link #getTargetFromEvent} for this node)
22184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185 * @param {Event} e The event
22186 * @param {Object} data An object containing arbitrary data supplied by the drag source
22187 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22188 * underlying {@link Roo.dd.StatusProxy} can be updated
22190 onNodeOver : function(n, dd, e, data){
22191 return this.dropAllowed;
22195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22196 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22197 * node-specific processing if necessary.
22198 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22199 * {@link #getTargetFromEvent} for this node)
22200 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22201 * @param {Event} e The event
22202 * @param {Object} data An object containing arbitrary data supplied by the drag source
22204 onNodeOut : function(n, dd, e, data){
22209 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22210 * the drop node. The default implementation returns false, so it should be overridden to provide the
22211 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22212 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22213 * {@link #getTargetFromEvent} for this node)
22214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22215 * @param {Event} e The event
22216 * @param {Object} data An object containing arbitrary data supplied by the drag source
22217 * @return {Boolean} True if the drop was valid, else false
22219 onNodeDrop : function(n, dd, e, data){
22224 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22225 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22226 * it should be overridden to provide the proper feedback if necessary.
22227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22228 * @param {Event} e The event
22229 * @param {Object} data An object containing arbitrary data supplied by the drag source
22230 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22231 * underlying {@link Roo.dd.StatusProxy} can be updated
22233 onContainerOver : function(dd, e, data){
22234 return this.dropNotAllowed;
22238 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22239 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22240 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22241 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22242 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22243 * @param {Event} e The event
22244 * @param {Object} data An object containing arbitrary data supplied by the drag source
22245 * @return {Boolean} True if the drop was valid, else false
22247 onContainerDrop : function(dd, e, data){
22252 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22253 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22254 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22255 * you should override this method and provide a custom implementation.
22256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22257 * @param {Event} e The event
22258 * @param {Object} data An object containing arbitrary data supplied by the drag source
22259 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22260 * underlying {@link Roo.dd.StatusProxy} can be updated
22262 notifyEnter : function(dd, e, data){
22263 return this.dropNotAllowed;
22267 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22268 * This method will be called on every mouse movement while the drag source is over the drop zone.
22269 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22270 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22271 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22272 * registered node, it will call {@link #onContainerOver}.
22273 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22274 * @param {Event} e The event
22275 * @param {Object} data An object containing arbitrary data supplied by the drag source
22276 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22277 * underlying {@link Roo.dd.StatusProxy} can be updated
22279 notifyOver : function(dd, e, data){
22280 var n = this.getTargetFromEvent(e);
22281 if(!n){ // not over valid drop target
22282 if(this.lastOverNode){
22283 this.onNodeOut(this.lastOverNode, dd, e, data);
22284 this.lastOverNode = null;
22286 return this.onContainerOver(dd, e, data);
22288 if(this.lastOverNode != n){
22289 if(this.lastOverNode){
22290 this.onNodeOut(this.lastOverNode, dd, e, data);
22292 this.onNodeEnter(n, dd, e, data);
22293 this.lastOverNode = n;
22295 return this.onNodeOver(n, dd, e, data);
22299 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22300 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22301 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22303 * @param {Event} e The event
22304 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22306 notifyOut : function(dd, e, data){
22307 if(this.lastOverNode){
22308 this.onNodeOut(this.lastOverNode, dd, e, data);
22309 this.lastOverNode = null;
22314 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22315 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22316 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22317 * otherwise it will call {@link #onContainerDrop}.
22318 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22319 * @param {Event} e The event
22320 * @param {Object} data An object containing arbitrary data supplied by the drag source
22321 * @return {Boolean} True if the drop was valid, else false
22323 notifyDrop : function(dd, e, data){
22324 if(this.lastOverNode){
22325 this.onNodeOut(this.lastOverNode, dd, e, data);
22326 this.lastOverNode = null;
22328 var n = this.getTargetFromEvent(e);
22330 this.onNodeDrop(n, dd, e, data) :
22331 this.onContainerDrop(dd, e, data);
22335 triggerCacheRefresh : function(){
22336 Roo.dd.DDM.refreshCache(this.groups);
22340 * Ext JS Library 1.1.1
22341 * Copyright(c) 2006-2007, Ext JS, LLC.
22343 * Originally Released Under LGPL - original licence link has changed is not relivant.
22346 * <script type="text/javascript">
22351 * @class Roo.data.SortTypes
22353 * Defines the default sorting (casting?) comparison functions used when sorting data.
22355 Roo.data.SortTypes = {
22357 * Default sort that does nothing
22358 * @param {Mixed} s The value being converted
22359 * @return {Mixed} The comparison value
22361 none : function(s){
22366 * The regular expression used to strip tags
22370 stripTagsRE : /<\/?[^>]+>/gi,
22373 * Strips all HTML tags to sort on text only
22374 * @param {Mixed} s The value being converted
22375 * @return {String} The comparison value
22377 asText : function(s){
22378 return String(s).replace(this.stripTagsRE, "");
22382 * Strips all HTML tags to sort on text only - Case insensitive
22383 * @param {Mixed} s The value being converted
22384 * @return {String} The comparison value
22386 asUCText : function(s){
22387 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22391 * Case insensitive string
22392 * @param {Mixed} s The value being converted
22393 * @return {String} The comparison value
22395 asUCString : function(s) {
22396 return String(s).toUpperCase();
22401 * @param {Mixed} s The value being converted
22402 * @return {Number} The comparison value
22404 asDate : function(s) {
22408 if(s instanceof Date){
22409 return s.getTime();
22411 return Date.parse(String(s));
22416 * @param {Mixed} s The value being converted
22417 * @return {Float} The comparison value
22419 asFloat : function(s) {
22420 var val = parseFloat(String(s).replace(/,/g, ""));
22429 * @param {Mixed} s The value being converted
22430 * @return {Number} The comparison value
22432 asInt : function(s) {
22433 var val = parseInt(String(s).replace(/,/g, ""));
22441 * Ext JS Library 1.1.1
22442 * Copyright(c) 2006-2007, Ext JS, LLC.
22444 * Originally Released Under LGPL - original licence link has changed is not relivant.
22447 * <script type="text/javascript">
22451 * @class Roo.data.Record
22452 * Instances of this class encapsulate both record <em>definition</em> information, and record
22453 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22454 * to access Records cached in an {@link Roo.data.Store} object.<br>
22456 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22457 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22460 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22462 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22463 * {@link #create}. The parameters are the same.
22464 * @param {Array} data An associative Array of data values keyed by the field name.
22465 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22466 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22467 * not specified an integer id is generated.
22469 Roo.data.Record = function(data, id){
22470 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22475 * Generate a constructor for a specific record layout.
22476 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22477 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22478 * Each field definition object may contain the following properties: <ul>
22479 * <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,
22480 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22481 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22482 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22483 * is being used, then this is a string containing the javascript expression to reference the data relative to
22484 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22485 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22486 * this may be omitted.</p></li>
22487 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22488 * <ul><li>auto (Default, implies no conversion)</li>
22493 * <li>date</li></ul></p></li>
22494 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22495 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22496 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22497 * by the Reader into an object that will be stored in the Record. It is passed the
22498 * following parameters:<ul>
22499 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22501 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22503 * <br>usage:<br><pre><code>
22504 var TopicRecord = Roo.data.Record.create(
22505 {name: 'title', mapping: 'topic_title'},
22506 {name: 'author', mapping: 'username'},
22507 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22508 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22509 {name: 'lastPoster', mapping: 'user2'},
22510 {name: 'excerpt', mapping: 'post_text'}
22513 var myNewRecord = new TopicRecord({
22514 title: 'Do my job please',
22517 lastPost: new Date(),
22518 lastPoster: 'Animal',
22519 excerpt: 'No way dude!'
22521 myStore.add(myNewRecord);
22526 Roo.data.Record.create = function(o){
22527 var f = function(){
22528 f.superclass.constructor.apply(this, arguments);
22530 Roo.extend(f, Roo.data.Record);
22531 var p = f.prototype;
22532 p.fields = new Roo.util.MixedCollection(false, function(field){
22535 for(var i = 0, len = o.length; i < len; i++){
22536 p.fields.add(new Roo.data.Field(o[i]));
22538 f.getField = function(name){
22539 return p.fields.get(name);
22544 Roo.data.Record.AUTO_ID = 1000;
22545 Roo.data.Record.EDIT = 'edit';
22546 Roo.data.Record.REJECT = 'reject';
22547 Roo.data.Record.COMMIT = 'commit';
22549 Roo.data.Record.prototype = {
22551 * Readonly flag - true if this record has been modified.
22560 join : function(store){
22561 this.store = store;
22565 * Set the named field to the specified value.
22566 * @param {String} name The name of the field to set.
22567 * @param {Object} value The value to set the field to.
22569 set : function(name, value){
22570 if(this.data[name] == value){
22574 if(!this.modified){
22575 this.modified = {};
22577 if(typeof this.modified[name] == 'undefined'){
22578 this.modified[name] = this.data[name];
22580 this.data[name] = value;
22581 if(!this.editing && this.store){
22582 this.store.afterEdit(this);
22587 * Get the value of the named field.
22588 * @param {String} name The name of the field to get the value of.
22589 * @return {Object} The value of the field.
22591 get : function(name){
22592 return this.data[name];
22596 beginEdit : function(){
22597 this.editing = true;
22598 this.modified = {};
22602 cancelEdit : function(){
22603 this.editing = false;
22604 delete this.modified;
22608 endEdit : function(){
22609 this.editing = false;
22610 if(this.dirty && this.store){
22611 this.store.afterEdit(this);
22616 * Usually called by the {@link Roo.data.Store} which owns the Record.
22617 * Rejects all changes made to the Record since either creation, or the last commit operation.
22618 * Modified fields are reverted to their original values.
22620 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22621 * of reject operations.
22623 reject : function(){
22624 var m = this.modified;
22626 if(typeof m[n] != "function"){
22627 this.data[n] = m[n];
22630 this.dirty = false;
22631 delete this.modified;
22632 this.editing = false;
22634 this.store.afterReject(this);
22639 * Usually called by the {@link Roo.data.Store} which owns the Record.
22640 * Commits all changes made to the Record since either creation, or the last commit operation.
22642 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22643 * of commit operations.
22645 commit : function(){
22646 this.dirty = false;
22647 delete this.modified;
22648 this.editing = false;
22650 this.store.afterCommit(this);
22655 hasError : function(){
22656 return this.error != null;
22660 clearError : function(){
22665 * Creates a copy of this record.
22666 * @param {String} id (optional) A new record id if you don't want to use this record's id
22669 copy : function(newId) {
22670 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22674 * Ext JS Library 1.1.1
22675 * Copyright(c) 2006-2007, Ext JS, LLC.
22677 * Originally Released Under LGPL - original licence link has changed is not relivant.
22680 * <script type="text/javascript">
22686 * @class Roo.data.Store
22687 * @extends Roo.util.Observable
22688 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22689 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22691 * 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
22692 * has no knowledge of the format of the data returned by the Proxy.<br>
22694 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22695 * instances from the data object. These records are cached and made available through accessor functions.
22697 * Creates a new Store.
22698 * @param {Object} config A config object containing the objects needed for the Store to access data,
22699 * and read the data into Records.
22701 Roo.data.Store = function(config){
22702 this.data = new Roo.util.MixedCollection(false);
22703 this.data.getKey = function(o){
22706 this.baseParams = {};
22708 this.paramNames = {
22713 "multisort" : "_multisort"
22716 if(config && config.data){
22717 this.inlineData = config.data;
22718 delete config.data;
22721 Roo.apply(this, config);
22723 if(this.reader){ // reader passed
22724 this.reader = Roo.factory(this.reader, Roo.data);
22725 this.reader.xmodule = this.xmodule || false;
22726 if(!this.recordType){
22727 this.recordType = this.reader.recordType;
22729 if(this.reader.onMetaChange){
22730 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22734 if(this.recordType){
22735 this.fields = this.recordType.prototype.fields;
22737 this.modified = [];
22741 * @event datachanged
22742 * Fires when the data cache has changed, and a widget which is using this Store
22743 * as a Record cache should refresh its view.
22744 * @param {Store} this
22746 datachanged : true,
22748 * @event metachange
22749 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22750 * @param {Store} this
22751 * @param {Object} meta The JSON metadata
22756 * Fires when Records have been added to the Store
22757 * @param {Store} this
22758 * @param {Roo.data.Record[]} records The array of Records added
22759 * @param {Number} index The index at which the record(s) were added
22764 * Fires when a Record has been removed from the Store
22765 * @param {Store} this
22766 * @param {Roo.data.Record} record The Record that was removed
22767 * @param {Number} index The index at which the record was removed
22772 * Fires when a Record has been updated
22773 * @param {Store} this
22774 * @param {Roo.data.Record} record The Record that was updated
22775 * @param {String} operation The update operation being performed. Value may be one of:
22777 Roo.data.Record.EDIT
22778 Roo.data.Record.REJECT
22779 Roo.data.Record.COMMIT
22785 * Fires when the data cache has been cleared.
22786 * @param {Store} this
22790 * @event beforeload
22791 * Fires before a request is made for a new data object. If the beforeload handler returns false
22792 * the load action will be canceled.
22793 * @param {Store} this
22794 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22798 * @event beforeloadadd
22799 * Fires after a new set of Records has been loaded.
22800 * @param {Store} this
22801 * @param {Roo.data.Record[]} records The Records that were loaded
22802 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22804 beforeloadadd : true,
22807 * Fires after a new set of Records has been loaded, before they are added to the store.
22808 * @param {Store} this
22809 * @param {Roo.data.Record[]} records The Records that were loaded
22810 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22811 * @params {Object} return from reader
22815 * @event loadexception
22816 * Fires if an exception occurs in the Proxy during loading.
22817 * Called with the signature of the Proxy's "loadexception" event.
22818 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22821 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22822 * @param {Object} load options
22823 * @param {Object} jsonData from your request (normally this contains the Exception)
22825 loadexception : true
22829 this.proxy = Roo.factory(this.proxy, Roo.data);
22830 this.proxy.xmodule = this.xmodule || false;
22831 this.relayEvents(this.proxy, ["loadexception"]);
22833 this.sortToggle = {};
22834 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22836 Roo.data.Store.superclass.constructor.call(this);
22838 if(this.inlineData){
22839 this.loadData(this.inlineData);
22840 delete this.inlineData;
22844 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22846 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22847 * without a remote query - used by combo/forms at present.
22851 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22854 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22857 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22858 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22861 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22862 * on any HTTP request
22865 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22868 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22872 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22873 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22875 remoteSort : false,
22878 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22879 * loaded or when a record is removed. (defaults to false).
22881 pruneModifiedRecords : false,
22884 lastOptions : null,
22887 * Add Records to the Store and fires the add event.
22888 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22890 add : function(records){
22891 records = [].concat(records);
22892 for(var i = 0, len = records.length; i < len; i++){
22893 records[i].join(this);
22895 var index = this.data.length;
22896 this.data.addAll(records);
22897 this.fireEvent("add", this, records, index);
22901 * Remove a Record from the Store and fires the remove event.
22902 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22904 remove : function(record){
22905 var index = this.data.indexOf(record);
22906 this.data.removeAt(index);
22907 if(this.pruneModifiedRecords){
22908 this.modified.remove(record);
22910 this.fireEvent("remove", this, record, index);
22914 * Remove all Records from the Store and fires the clear event.
22916 removeAll : function(){
22918 if(this.pruneModifiedRecords){
22919 this.modified = [];
22921 this.fireEvent("clear", this);
22925 * Inserts Records to the Store at the given index and fires the add event.
22926 * @param {Number} index The start index at which to insert the passed Records.
22927 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22929 insert : function(index, records){
22930 records = [].concat(records);
22931 for(var i = 0, len = records.length; i < len; i++){
22932 this.data.insert(index, records[i]);
22933 records[i].join(this);
22935 this.fireEvent("add", this, records, index);
22939 * Get the index within the cache of the passed Record.
22940 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22941 * @return {Number} The index of the passed Record. Returns -1 if not found.
22943 indexOf : function(record){
22944 return this.data.indexOf(record);
22948 * Get the index within the cache of the Record with the passed id.
22949 * @param {String} id The id of the Record to find.
22950 * @return {Number} The index of the Record. Returns -1 if not found.
22952 indexOfId : function(id){
22953 return this.data.indexOfKey(id);
22957 * Get the Record with the specified id.
22958 * @param {String} id The id of the Record to find.
22959 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22961 getById : function(id){
22962 return this.data.key(id);
22966 * Get the Record at the specified index.
22967 * @param {Number} index The index of the Record to find.
22968 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22970 getAt : function(index){
22971 return this.data.itemAt(index);
22975 * Returns a range of Records between specified indices.
22976 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22977 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22978 * @return {Roo.data.Record[]} An array of Records
22980 getRange : function(start, end){
22981 return this.data.getRange(start, end);
22985 storeOptions : function(o){
22986 o = Roo.apply({}, o);
22989 this.lastOptions = o;
22993 * Loads the Record cache from the configured Proxy using the configured Reader.
22995 * If using remote paging, then the first load call must specify the <em>start</em>
22996 * and <em>limit</em> properties in the options.params property to establish the initial
22997 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22999 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23000 * and this call will return before the new data has been loaded. Perform any post-processing
23001 * in a callback function, or in a "load" event handler.</strong>
23003 * @param {Object} options An object containing properties which control loading options:<ul>
23004 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23005 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23006 * passed the following arguments:<ul>
23007 * <li>r : Roo.data.Record[]</li>
23008 * <li>options: Options object from the load call</li>
23009 * <li>success: Boolean success indicator</li></ul></li>
23010 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23011 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23014 load : function(options){
23015 options = options || {};
23016 if(this.fireEvent("beforeload", this, options) !== false){
23017 this.storeOptions(options);
23018 var p = Roo.apply(options.params || {}, this.baseParams);
23019 // if meta was not loaded from remote source.. try requesting it.
23020 if (!this.reader.metaFromRemote) {
23021 p._requestMeta = 1;
23023 if(this.sortInfo && this.remoteSort){
23024 var pn = this.paramNames;
23025 p[pn["sort"]] = this.sortInfo.field;
23026 p[pn["dir"]] = this.sortInfo.direction;
23028 if (this.multiSort) {
23029 var pn = this.paramNames;
23030 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23033 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23038 * Reloads the Record cache from the configured Proxy using the configured Reader and
23039 * the options from the last load operation performed.
23040 * @param {Object} options (optional) An object containing properties which may override the options
23041 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23042 * the most recently used options are reused).
23044 reload : function(options){
23045 this.load(Roo.applyIf(options||{}, this.lastOptions));
23049 // Called as a callback by the Reader during a load operation.
23050 loadRecords : function(o, options, success){
23051 if(!o || success === false){
23052 if(success !== false){
23053 this.fireEvent("load", this, [], options, o);
23055 if(options.callback){
23056 options.callback.call(options.scope || this, [], options, false);
23060 // if data returned failure - throw an exception.
23061 if (o.success === false) {
23062 // show a message if no listener is registered.
23063 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23064 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23066 // loadmask wil be hooked into this..
23067 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23070 var r = o.records, t = o.totalRecords || r.length;
23072 this.fireEvent("beforeloadadd", this, r, options, o);
23074 if(!options || options.add !== true){
23075 if(this.pruneModifiedRecords){
23076 this.modified = [];
23078 for(var i = 0, len = r.length; i < len; i++){
23082 this.data = this.snapshot;
23083 delete this.snapshot;
23086 this.data.addAll(r);
23087 this.totalLength = t;
23089 this.fireEvent("datachanged", this);
23091 this.totalLength = Math.max(t, this.data.length+r.length);
23095 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23097 var e = new Roo.data.Record({});
23099 e.set(this.parent.displayField, this.parent.emptyTitle);
23100 e.set(this.parent.valueField, '');
23105 this.fireEvent("load", this, r, options, o);
23106 if(options.callback){
23107 options.callback.call(options.scope || this, r, options, true);
23113 * Loads data from a passed data block. A Reader which understands the format of the data
23114 * must have been configured in the constructor.
23115 * @param {Object} data The data block from which to read the Records. The format of the data expected
23116 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23117 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23119 loadData : function(o, append){
23120 var r = this.reader.readRecords(o);
23121 this.loadRecords(r, {add: append}, true);
23125 * Gets the number of cached records.
23127 * <em>If using paging, this may not be the total size of the dataset. If the data object
23128 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23129 * the data set size</em>
23131 getCount : function(){
23132 return this.data.length || 0;
23136 * Gets the total number of records in the dataset as returned by the server.
23138 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23139 * the dataset size</em>
23141 getTotalCount : function(){
23142 return this.totalLength || 0;
23146 * Returns the sort state of the Store as an object with two properties:
23148 field {String} The name of the field by which the Records are sorted
23149 direction {String} The sort order, "ASC" or "DESC"
23152 getSortState : function(){
23153 return this.sortInfo;
23157 applySort : function(){
23158 if(this.sortInfo && !this.remoteSort){
23159 var s = this.sortInfo, f = s.field;
23160 var st = this.fields.get(f).sortType;
23161 var fn = function(r1, r2){
23162 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23163 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23165 this.data.sort(s.direction, fn);
23166 if(this.snapshot && this.snapshot != this.data){
23167 this.snapshot.sort(s.direction, fn);
23173 * Sets the default sort column and order to be used by the next load operation.
23174 * @param {String} fieldName The name of the field to sort by.
23175 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23177 setDefaultSort : function(field, dir){
23178 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23182 * Sort the Records.
23183 * If remote sorting is used, the sort is performed on the server, and the cache is
23184 * reloaded. If local sorting is used, the cache is sorted internally.
23185 * @param {String} fieldName The name of the field to sort by.
23186 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23188 sort : function(fieldName, dir){
23189 var f = this.fields.get(fieldName);
23191 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23193 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23194 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23199 this.sortToggle[f.name] = dir;
23200 this.sortInfo = {field: f.name, direction: dir};
23201 if(!this.remoteSort){
23203 this.fireEvent("datachanged", this);
23205 this.load(this.lastOptions);
23210 * Calls the specified function for each of the Records in the cache.
23211 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23212 * Returning <em>false</em> aborts and exits the iteration.
23213 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23215 each : function(fn, scope){
23216 this.data.each(fn, scope);
23220 * Gets all records modified since the last commit. Modified records are persisted across load operations
23221 * (e.g., during paging).
23222 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23224 getModifiedRecords : function(){
23225 return this.modified;
23229 createFilterFn : function(property, value, anyMatch){
23230 if(!value.exec){ // not a regex
23231 value = String(value);
23232 if(value.length == 0){
23235 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23237 return function(r){
23238 return value.test(r.data[property]);
23243 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23244 * @param {String} property A field on your records
23245 * @param {Number} start The record index to start at (defaults to 0)
23246 * @param {Number} end The last record index to include (defaults to length - 1)
23247 * @return {Number} The sum
23249 sum : function(property, start, end){
23250 var rs = this.data.items, v = 0;
23251 start = start || 0;
23252 end = (end || end === 0) ? end : rs.length-1;
23254 for(var i = start; i <= end; i++){
23255 v += (rs[i].data[property] || 0);
23261 * Filter the records by a specified property.
23262 * @param {String} field A field on your records
23263 * @param {String/RegExp} value Either a string that the field
23264 * should start with or a RegExp to test against the field
23265 * @param {Boolean} anyMatch True to match any part not just the beginning
23267 filter : function(property, value, anyMatch){
23268 var fn = this.createFilterFn(property, value, anyMatch);
23269 return fn ? this.filterBy(fn) : this.clearFilter();
23273 * Filter by a function. The specified function will be called with each
23274 * record in this data source. If the function returns true the record is included,
23275 * otherwise it is filtered.
23276 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23277 * @param {Object} scope (optional) The scope of the function (defaults to this)
23279 filterBy : function(fn, scope){
23280 this.snapshot = this.snapshot || this.data;
23281 this.data = this.queryBy(fn, scope||this);
23282 this.fireEvent("datachanged", this);
23286 * Query the records by a specified property.
23287 * @param {String} field A field on your records
23288 * @param {String/RegExp} value Either a string that the field
23289 * should start with or a RegExp to test against the field
23290 * @param {Boolean} anyMatch True to match any part not just the beginning
23291 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23293 query : function(property, value, anyMatch){
23294 var fn = this.createFilterFn(property, value, anyMatch);
23295 return fn ? this.queryBy(fn) : this.data.clone();
23299 * Query by a function. The specified function will be called with each
23300 * record in this data source. If the function returns true the record is included
23302 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23303 * @param {Object} scope (optional) The scope of the function (defaults to this)
23304 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23306 queryBy : function(fn, scope){
23307 var data = this.snapshot || this.data;
23308 return data.filterBy(fn, scope||this);
23312 * Collects unique values for a particular dataIndex from this store.
23313 * @param {String} dataIndex The property to collect
23314 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23315 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23316 * @return {Array} An array of the unique values
23318 collect : function(dataIndex, allowNull, bypassFilter){
23319 var d = (bypassFilter === true && this.snapshot) ?
23320 this.snapshot.items : this.data.items;
23321 var v, sv, r = [], l = {};
23322 for(var i = 0, len = d.length; i < len; i++){
23323 v = d[i].data[dataIndex];
23325 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23334 * Revert to a view of the Record cache with no filtering applied.
23335 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23337 clearFilter : function(suppressEvent){
23338 if(this.snapshot && this.snapshot != this.data){
23339 this.data = this.snapshot;
23340 delete this.snapshot;
23341 if(suppressEvent !== true){
23342 this.fireEvent("datachanged", this);
23348 afterEdit : function(record){
23349 if(this.modified.indexOf(record) == -1){
23350 this.modified.push(record);
23352 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23356 afterReject : function(record){
23357 this.modified.remove(record);
23358 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23362 afterCommit : function(record){
23363 this.modified.remove(record);
23364 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23368 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23369 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23371 commitChanges : function(){
23372 var m = this.modified.slice(0);
23373 this.modified = [];
23374 for(var i = 0, len = m.length; i < len; i++){
23380 * Cancel outstanding changes on all changed records.
23382 rejectChanges : function(){
23383 var m = this.modified.slice(0);
23384 this.modified = [];
23385 for(var i = 0, len = m.length; i < len; i++){
23390 onMetaChange : function(meta, rtype, o){
23391 this.recordType = rtype;
23392 this.fields = rtype.prototype.fields;
23393 delete this.snapshot;
23394 this.sortInfo = meta.sortInfo || this.sortInfo;
23395 this.modified = [];
23396 this.fireEvent('metachange', this, this.reader.meta);
23399 moveIndex : function(data, type)
23401 var index = this.indexOf(data);
23403 var newIndex = index + type;
23407 this.insert(newIndex, data);
23412 * Ext JS Library 1.1.1
23413 * Copyright(c) 2006-2007, Ext JS, LLC.
23415 * Originally Released Under LGPL - original licence link has changed is not relivant.
23418 * <script type="text/javascript">
23422 * @class Roo.data.SimpleStore
23423 * @extends Roo.data.Store
23424 * Small helper class to make creating Stores from Array data easier.
23425 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23426 * @cfg {Array} fields An array of field definition objects, or field name strings.
23427 * @cfg {Array} data The multi-dimensional array of data
23429 * @param {Object} config
23431 Roo.data.SimpleStore = function(config){
23432 Roo.data.SimpleStore.superclass.constructor.call(this, {
23434 reader: new Roo.data.ArrayReader({
23437 Roo.data.Record.create(config.fields)
23439 proxy : new Roo.data.MemoryProxy(config.data)
23443 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23445 * Ext JS Library 1.1.1
23446 * Copyright(c) 2006-2007, Ext JS, LLC.
23448 * Originally Released Under LGPL - original licence link has changed is not relivant.
23451 * <script type="text/javascript">
23456 * @extends Roo.data.Store
23457 * @class Roo.data.JsonStore
23458 * Small helper class to make creating Stores for JSON data easier. <br/>
23460 var store = new Roo.data.JsonStore({
23461 url: 'get-images.php',
23463 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23466 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23467 * JsonReader and HttpProxy (unless inline data is provided).</b>
23468 * @cfg {Array} fields An array of field definition objects, or field name strings.
23470 * @param {Object} config
23472 Roo.data.JsonStore = function(c){
23473 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23474 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23475 reader: new Roo.data.JsonReader(c, c.fields)
23478 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23480 * Ext JS Library 1.1.1
23481 * Copyright(c) 2006-2007, Ext JS, LLC.
23483 * Originally Released Under LGPL - original licence link has changed is not relivant.
23486 * <script type="text/javascript">
23490 Roo.data.Field = function(config){
23491 if(typeof config == "string"){
23492 config = {name: config};
23494 Roo.apply(this, config);
23497 this.type = "auto";
23500 var st = Roo.data.SortTypes;
23501 // named sortTypes are supported, here we look them up
23502 if(typeof this.sortType == "string"){
23503 this.sortType = st[this.sortType];
23506 // set default sortType for strings and dates
23507 if(!this.sortType){
23510 this.sortType = st.asUCString;
23513 this.sortType = st.asDate;
23516 this.sortType = st.none;
23521 var stripRe = /[\$,%]/g;
23523 // prebuilt conversion function for this field, instead of
23524 // switching every time we're reading a value
23526 var cv, dateFormat = this.dateFormat;
23531 cv = function(v){ return v; };
23534 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23538 return v !== undefined && v !== null && v !== '' ?
23539 parseInt(String(v).replace(stripRe, ""), 10) : '';
23544 return v !== undefined && v !== null && v !== '' ?
23545 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23550 cv = function(v){ return v === true || v === "true" || v == 1; };
23557 if(v instanceof Date){
23561 if(dateFormat == "timestamp"){
23562 return new Date(v*1000);
23564 return Date.parseDate(v, dateFormat);
23566 var parsed = Date.parse(v);
23567 return parsed ? new Date(parsed) : null;
23576 Roo.data.Field.prototype = {
23584 * Ext JS Library 1.1.1
23585 * Copyright(c) 2006-2007, Ext JS, LLC.
23587 * Originally Released Under LGPL - original licence link has changed is not relivant.
23590 * <script type="text/javascript">
23593 // Base class for reading structured data from a data source. This class is intended to be
23594 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23597 * @class Roo.data.DataReader
23598 * Base class for reading structured data from a data source. This class is intended to be
23599 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23602 Roo.data.DataReader = function(meta, recordType){
23606 this.recordType = recordType instanceof Array ?
23607 Roo.data.Record.create(recordType) : recordType;
23610 Roo.data.DataReader.prototype = {
23612 * Create an empty record
23613 * @param {Object} data (optional) - overlay some values
23614 * @return {Roo.data.Record} record created.
23616 newRow : function(d) {
23618 this.recordType.prototype.fields.each(function(c) {
23620 case 'int' : da[c.name] = 0; break;
23621 case 'date' : da[c.name] = new Date(); break;
23622 case 'float' : da[c.name] = 0.0; break;
23623 case 'boolean' : da[c.name] = false; break;
23624 default : da[c.name] = ""; break;
23628 return new this.recordType(Roo.apply(da, d));
23633 * Ext JS Library 1.1.1
23634 * Copyright(c) 2006-2007, Ext JS, LLC.
23636 * Originally Released Under LGPL - original licence link has changed is not relivant.
23639 * <script type="text/javascript">
23643 * @class Roo.data.DataProxy
23644 * @extends Roo.data.Observable
23645 * This class is an abstract base class for implementations which provide retrieval of
23646 * unformatted data objects.<br>
23648 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23649 * (of the appropriate type which knows how to parse the data object) to provide a block of
23650 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23652 * Custom implementations must implement the load method as described in
23653 * {@link Roo.data.HttpProxy#load}.
23655 Roo.data.DataProxy = function(){
23658 * @event beforeload
23659 * Fires before a network request is made to retrieve a data object.
23660 * @param {Object} This DataProxy object.
23661 * @param {Object} params The params parameter to the load function.
23666 * Fires before the load method's callback is called.
23667 * @param {Object} This DataProxy object.
23668 * @param {Object} o The data object.
23669 * @param {Object} arg The callback argument object passed to the load function.
23673 * @event loadexception
23674 * Fires if an Exception occurs during data retrieval.
23675 * @param {Object} This DataProxy object.
23676 * @param {Object} o The data object.
23677 * @param {Object} arg The callback argument object passed to the load function.
23678 * @param {Object} e The Exception.
23680 loadexception : true
23682 Roo.data.DataProxy.superclass.constructor.call(this);
23685 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23688 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23692 * Ext JS Library 1.1.1
23693 * Copyright(c) 2006-2007, Ext JS, LLC.
23695 * Originally Released Under LGPL - original licence link has changed is not relivant.
23698 * <script type="text/javascript">
23701 * @class Roo.data.MemoryProxy
23702 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23703 * to the Reader when its load method is called.
23705 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23707 Roo.data.MemoryProxy = function(data){
23711 Roo.data.MemoryProxy.superclass.constructor.call(this);
23715 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23718 * Load data from the requested source (in this case an in-memory
23719 * data object passed to the constructor), read the data object into
23720 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23721 * process that block using the passed callback.
23722 * @param {Object} params This parameter is not used by the MemoryProxy class.
23723 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23724 * object into a block of Roo.data.Records.
23725 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23726 * The function must be passed <ul>
23727 * <li>The Record block object</li>
23728 * <li>The "arg" argument from the load function</li>
23729 * <li>A boolean success indicator</li>
23731 * @param {Object} scope The scope in which to call the callback
23732 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23734 load : function(params, reader, callback, scope, arg){
23735 params = params || {};
23738 result = reader.readRecords(this.data);
23740 this.fireEvent("loadexception", this, arg, null, e);
23741 callback.call(scope, null, arg, false);
23744 callback.call(scope, result, arg, true);
23748 update : function(params, records){
23753 * Ext JS Library 1.1.1
23754 * Copyright(c) 2006-2007, Ext JS, LLC.
23756 * Originally Released Under LGPL - original licence link has changed is not relivant.
23759 * <script type="text/javascript">
23762 * @class Roo.data.HttpProxy
23763 * @extends Roo.data.DataProxy
23764 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23765 * configured to reference a certain URL.<br><br>
23767 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23768 * from which the running page was served.<br><br>
23770 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23772 * Be aware that to enable the browser to parse an XML document, the server must set
23773 * the Content-Type header in the HTTP response to "text/xml".
23775 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23776 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23777 * will be used to make the request.
23779 Roo.data.HttpProxy = function(conn){
23780 Roo.data.HttpProxy.superclass.constructor.call(this);
23781 // is conn a conn config or a real conn?
23783 this.useAjax = !conn || !conn.events;
23787 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23788 // thse are take from connection...
23791 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23794 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23795 * extra parameters to each request made by this object. (defaults to undefined)
23798 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23799 * to each request made by this object. (defaults to undefined)
23802 * @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)
23805 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23808 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23814 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23818 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23819 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23820 * a finer-grained basis than the DataProxy events.
23822 getConnection : function(){
23823 return this.useAjax ? Roo.Ajax : this.conn;
23827 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23828 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23829 * process that block using the passed callback.
23830 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23831 * for the request to the remote server.
23832 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23833 * object into a block of Roo.data.Records.
23834 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23835 * The function must be passed <ul>
23836 * <li>The Record block object</li>
23837 * <li>The "arg" argument from the load function</li>
23838 * <li>A boolean success indicator</li>
23840 * @param {Object} scope The scope in which to call the callback
23841 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23843 load : function(params, reader, callback, scope, arg){
23844 if(this.fireEvent("beforeload", this, params) !== false){
23846 params : params || {},
23848 callback : callback,
23853 callback : this.loadResponse,
23857 Roo.applyIf(o, this.conn);
23858 if(this.activeRequest){
23859 Roo.Ajax.abort(this.activeRequest);
23861 this.activeRequest = Roo.Ajax.request(o);
23863 this.conn.request(o);
23866 callback.call(scope||this, null, arg, false);
23871 loadResponse : function(o, success, response){
23872 delete this.activeRequest;
23874 this.fireEvent("loadexception", this, o, response);
23875 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23880 result = o.reader.read(response);
23882 this.fireEvent("loadexception", this, o, response, e);
23883 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23887 this.fireEvent("load", this, o, o.request.arg);
23888 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23892 update : function(dataSet){
23897 updateResponse : function(dataSet){
23902 * Ext JS Library 1.1.1
23903 * Copyright(c) 2006-2007, Ext JS, LLC.
23905 * Originally Released Under LGPL - original licence link has changed is not relivant.
23908 * <script type="text/javascript">
23912 * @class Roo.data.ScriptTagProxy
23913 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23914 * other than the originating domain of the running page.<br><br>
23916 * <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
23917 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23919 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23920 * source code that is used as the source inside a <script> tag.<br><br>
23922 * In order for the browser to process the returned data, the server must wrap the data object
23923 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23924 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23925 * depending on whether the callback name was passed:
23928 boolean scriptTag = false;
23929 String cb = request.getParameter("callback");
23932 response.setContentType("text/javascript");
23934 response.setContentType("application/x-json");
23936 Writer out = response.getWriter();
23938 out.write(cb + "(");
23940 out.print(dataBlock.toJsonString());
23947 * @param {Object} config A configuration object.
23949 Roo.data.ScriptTagProxy = function(config){
23950 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23951 Roo.apply(this, config);
23952 this.head = document.getElementsByTagName("head")[0];
23955 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23957 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23959 * @cfg {String} url The URL from which to request the data object.
23962 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23966 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23967 * the server the name of the callback function set up by the load call to process the returned data object.
23968 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23969 * javascript output which calls this named function passing the data object as its only parameter.
23971 callbackParam : "callback",
23973 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23974 * name to the request.
23979 * Load data from the configured URL, read the data object into
23980 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23981 * process that block using the passed callback.
23982 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23983 * for the request to the remote server.
23984 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23985 * object into a block of Roo.data.Records.
23986 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23987 * The function must be passed <ul>
23988 * <li>The Record block object</li>
23989 * <li>The "arg" argument from the load function</li>
23990 * <li>A boolean success indicator</li>
23992 * @param {Object} scope The scope in which to call the callback
23993 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23995 load : function(params, reader, callback, scope, arg){
23996 if(this.fireEvent("beforeload", this, params) !== false){
23998 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24000 var url = this.url;
24001 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24003 url += "&_dc=" + (new Date().getTime());
24005 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24008 cb : "stcCallback"+transId,
24009 scriptId : "stcScript"+transId,
24013 callback : callback,
24019 window[trans.cb] = function(o){
24020 conn.handleResponse(o, trans);
24023 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24025 if(this.autoAbort !== false){
24029 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24031 var script = document.createElement("script");
24032 script.setAttribute("src", url);
24033 script.setAttribute("type", "text/javascript");
24034 script.setAttribute("id", trans.scriptId);
24035 this.head.appendChild(script);
24037 this.trans = trans;
24039 callback.call(scope||this, null, arg, false);
24044 isLoading : function(){
24045 return this.trans ? true : false;
24049 * Abort the current server request.
24051 abort : function(){
24052 if(this.isLoading()){
24053 this.destroyTrans(this.trans);
24058 destroyTrans : function(trans, isLoaded){
24059 this.head.removeChild(document.getElementById(trans.scriptId));
24060 clearTimeout(trans.timeoutId);
24062 window[trans.cb] = undefined;
24064 delete window[trans.cb];
24067 // if hasn't been loaded, wait for load to remove it to prevent script error
24068 window[trans.cb] = function(){
24069 window[trans.cb] = undefined;
24071 delete window[trans.cb];
24078 handleResponse : function(o, trans){
24079 this.trans = false;
24080 this.destroyTrans(trans, true);
24083 result = trans.reader.readRecords(o);
24085 this.fireEvent("loadexception", this, o, trans.arg, e);
24086 trans.callback.call(trans.scope||window, null, trans.arg, false);
24089 this.fireEvent("load", this, o, trans.arg);
24090 trans.callback.call(trans.scope||window, result, trans.arg, true);
24094 handleFailure : function(trans){
24095 this.trans = false;
24096 this.destroyTrans(trans, false);
24097 this.fireEvent("loadexception", this, null, trans.arg);
24098 trans.callback.call(trans.scope||window, null, trans.arg, false);
24102 * Ext JS Library 1.1.1
24103 * Copyright(c) 2006-2007, Ext JS, LLC.
24105 * Originally Released Under LGPL - original licence link has changed is not relivant.
24108 * <script type="text/javascript">
24112 * @class Roo.data.JsonReader
24113 * @extends Roo.data.DataReader
24114 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24115 * based on mappings in a provided Roo.data.Record constructor.
24117 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24118 * in the reply previously.
24123 var RecordDef = Roo.data.Record.create([
24124 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24125 {name: 'occupation'} // This field will use "occupation" as the mapping.
24127 var myReader = new Roo.data.JsonReader({
24128 totalProperty: "results", // The property which contains the total dataset size (optional)
24129 root: "rows", // The property which contains an Array of row objects
24130 id: "id" // The property within each row object that provides an ID for the record (optional)
24134 * This would consume a JSON file like this:
24136 { 'results': 2, 'rows': [
24137 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24138 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24141 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24142 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24143 * paged from the remote server.
24144 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24145 * @cfg {String} root name of the property which contains the Array of row objects.
24146 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24147 * @cfg {Array} fields Array of field definition objects
24149 * Create a new JsonReader
24150 * @param {Object} meta Metadata configuration options
24151 * @param {Object} recordType Either an Array of field definition objects,
24152 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24154 Roo.data.JsonReader = function(meta, recordType){
24157 // set some defaults:
24158 Roo.applyIf(meta, {
24159 totalProperty: 'total',
24160 successProperty : 'success',
24165 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24167 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24170 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24171 * Used by Store query builder to append _requestMeta to params.
24174 metaFromRemote : false,
24176 * This method is only used by a DataProxy which has retrieved data from a remote server.
24177 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24178 * @return {Object} data A data block which is used by an Roo.data.Store object as
24179 * a cache of Roo.data.Records.
24181 read : function(response){
24182 var json = response.responseText;
24184 var o = /* eval:var:o */ eval("("+json+")");
24186 throw {message: "JsonReader.read: Json object not found"};
24192 this.metaFromRemote = true;
24193 this.meta = o.metaData;
24194 this.recordType = Roo.data.Record.create(o.metaData.fields);
24195 this.onMetaChange(this.meta, this.recordType, o);
24197 return this.readRecords(o);
24200 // private function a store will implement
24201 onMetaChange : function(meta, recordType, o){
24208 simpleAccess: function(obj, subsc) {
24215 getJsonAccessor: function(){
24217 return function(expr) {
24219 return(re.test(expr))
24220 ? new Function("obj", "return obj." + expr)
24225 return Roo.emptyFn;
24230 * Create a data block containing Roo.data.Records from an XML document.
24231 * @param {Object} o An object which contains an Array of row objects in the property specified
24232 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24233 * which contains the total size of the dataset.
24234 * @return {Object} data A data block which is used by an Roo.data.Store object as
24235 * a cache of Roo.data.Records.
24237 readRecords : function(o){
24239 * After any data loads, the raw JSON data is available for further custom processing.
24243 var s = this.meta, Record = this.recordType,
24244 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24246 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24248 if(s.totalProperty) {
24249 this.getTotal = this.getJsonAccessor(s.totalProperty);
24251 if(s.successProperty) {
24252 this.getSuccess = this.getJsonAccessor(s.successProperty);
24254 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24256 var g = this.getJsonAccessor(s.id);
24257 this.getId = function(rec) {
24259 return (r === undefined || r === "") ? null : r;
24262 this.getId = function(){return null;};
24265 for(var jj = 0; jj < fl; jj++){
24267 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24268 this.ef[jj] = this.getJsonAccessor(map);
24272 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24273 if(s.totalProperty){
24274 var vt = parseInt(this.getTotal(o), 10);
24279 if(s.successProperty){
24280 var vs = this.getSuccess(o);
24281 if(vs === false || vs === 'false'){
24286 for(var i = 0; i < c; i++){
24289 var id = this.getId(n);
24290 for(var j = 0; j < fl; j++){
24292 var v = this.ef[j](n);
24294 Roo.log('missing convert for ' + f.name);
24298 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24300 var record = new Record(values, id);
24302 records[i] = record;
24308 totalRecords : totalRecords
24313 * Ext JS Library 1.1.1
24314 * Copyright(c) 2006-2007, Ext JS, LLC.
24316 * Originally Released Under LGPL - original licence link has changed is not relivant.
24319 * <script type="text/javascript">
24323 * @class Roo.data.XmlReader
24324 * @extends Roo.data.DataReader
24325 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24326 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24328 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24329 * header in the HTTP response must be set to "text/xml".</em>
24333 var RecordDef = Roo.data.Record.create([
24334 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24335 {name: 'occupation'} // This field will use "occupation" as the mapping.
24337 var myReader = new Roo.data.XmlReader({
24338 totalRecords: "results", // The element which contains the total dataset size (optional)
24339 record: "row", // The repeated element which contains row information
24340 id: "id" // The element within the row that provides an ID for the record (optional)
24344 * This would consume an XML file like this:
24348 <results>2</results>
24351 <name>Bill</name>
24352 <occupation>Gardener</occupation>
24356 <name>Ben</name>
24357 <occupation>Horticulturalist</occupation>
24361 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24362 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24363 * paged from the remote server.
24364 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24365 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24366 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24367 * a record identifier value.
24369 * Create a new XmlReader
24370 * @param {Object} meta Metadata configuration options
24371 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24372 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24373 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24375 Roo.data.XmlReader = function(meta, recordType){
24377 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24379 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24381 * This method is only used by a DataProxy which has retrieved data from a remote server.
24382 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24383 * to contain a method called 'responseXML' that returns an XML document object.
24384 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24385 * a cache of Roo.data.Records.
24387 read : function(response){
24388 var doc = response.responseXML;
24390 throw {message: "XmlReader.read: XML Document not available"};
24392 return this.readRecords(doc);
24396 * Create a data block containing Roo.data.Records from an XML document.
24397 * @param {Object} doc A parsed XML document.
24398 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24399 * a cache of Roo.data.Records.
24401 readRecords : function(doc){
24403 * After any data loads/reads, the raw XML Document is available for further custom processing.
24404 * @type XMLDocument
24406 this.xmlData = doc;
24407 var root = doc.documentElement || doc;
24408 var q = Roo.DomQuery;
24409 var recordType = this.recordType, fields = recordType.prototype.fields;
24410 var sid = this.meta.id;
24411 var totalRecords = 0, success = true;
24412 if(this.meta.totalRecords){
24413 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24416 if(this.meta.success){
24417 var sv = q.selectValue(this.meta.success, root, true);
24418 success = sv !== false && sv !== 'false';
24421 var ns = q.select(this.meta.record, root);
24422 for(var i = 0, len = ns.length; i < len; i++) {
24425 var id = sid ? q.selectValue(sid, n) : undefined;
24426 for(var j = 0, jlen = fields.length; j < jlen; j++){
24427 var f = fields.items[j];
24428 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24430 values[f.name] = v;
24432 var record = new recordType(values, id);
24434 records[records.length] = record;
24440 totalRecords : totalRecords || records.length
24445 * Ext JS Library 1.1.1
24446 * Copyright(c) 2006-2007, Ext JS, LLC.
24448 * Originally Released Under LGPL - original licence link has changed is not relivant.
24451 * <script type="text/javascript">
24455 * @class Roo.data.ArrayReader
24456 * @extends Roo.data.DataReader
24457 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24458 * Each element of that Array represents a row of data fields. The
24459 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24460 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24464 var RecordDef = Roo.data.Record.create([
24465 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24466 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24468 var myReader = new Roo.data.ArrayReader({
24469 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24473 * This would consume an Array like this:
24475 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24477 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24479 * Create a new JsonReader
24480 * @param {Object} meta Metadata configuration options.
24481 * @param {Object} recordType Either an Array of field definition objects
24482 * as specified to {@link Roo.data.Record#create},
24483 * or an {@link Roo.data.Record} object
24484 * created using {@link Roo.data.Record#create}.
24486 Roo.data.ArrayReader = function(meta, recordType){
24487 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24490 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24492 * Create a data block containing Roo.data.Records from an XML document.
24493 * @param {Object} o An Array of row objects which represents the dataset.
24494 * @return {Object} data A data block which is used by an Roo.data.Store object as
24495 * a cache of Roo.data.Records.
24497 readRecords : function(o){
24498 var sid = this.meta ? this.meta.id : null;
24499 var recordType = this.recordType, fields = recordType.prototype.fields;
24502 for(var i = 0; i < root.length; i++){
24505 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24506 for(var j = 0, jlen = fields.length; j < jlen; j++){
24507 var f = fields.items[j];
24508 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24509 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24511 values[f.name] = v;
24513 var record = new recordType(values, id);
24515 records[records.length] = record;
24519 totalRecords : records.length
24524 * Ext JS Library 1.1.1
24525 * Copyright(c) 2006-2007, Ext JS, LLC.
24527 * Originally Released Under LGPL - original licence link has changed is not relivant.
24530 * <script type="text/javascript">
24535 * @class Roo.data.Tree
24536 * @extends Roo.util.Observable
24537 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24538 * in the tree have most standard DOM functionality.
24540 * @param {Node} root (optional) The root node
24542 Roo.data.Tree = function(root){
24543 this.nodeHash = {};
24545 * The root node for this tree
24550 this.setRootNode(root);
24555 * Fires when a new child node is appended to a node in this tree.
24556 * @param {Tree} tree The owner tree
24557 * @param {Node} parent The parent node
24558 * @param {Node} node The newly appended node
24559 * @param {Number} index The index of the newly appended node
24564 * Fires when a child node is removed from a node in this tree.
24565 * @param {Tree} tree The owner tree
24566 * @param {Node} parent The parent node
24567 * @param {Node} node The child node removed
24572 * Fires when a node is moved to a new location in the tree
24573 * @param {Tree} tree The owner tree
24574 * @param {Node} node The node moved
24575 * @param {Node} oldParent The old parent of this node
24576 * @param {Node} newParent The new parent of this node
24577 * @param {Number} index The index it was moved to
24582 * Fires when a new child node is inserted in a node in this tree.
24583 * @param {Tree} tree The owner tree
24584 * @param {Node} parent The parent node
24585 * @param {Node} node The child node inserted
24586 * @param {Node} refNode The child node the node was inserted before
24590 * @event beforeappend
24591 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24592 * @param {Tree} tree The owner tree
24593 * @param {Node} parent The parent node
24594 * @param {Node} node The child node to be appended
24596 "beforeappend" : true,
24598 * @event beforeremove
24599 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24600 * @param {Tree} tree The owner tree
24601 * @param {Node} parent The parent node
24602 * @param {Node} node The child node to be removed
24604 "beforeremove" : true,
24606 * @event beforemove
24607 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24608 * @param {Tree} tree The owner tree
24609 * @param {Node} node The node being moved
24610 * @param {Node} oldParent The parent of the node
24611 * @param {Node} newParent The new parent the node is moving to
24612 * @param {Number} index The index it is being moved to
24614 "beforemove" : true,
24616 * @event beforeinsert
24617 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24618 * @param {Tree} tree The owner tree
24619 * @param {Node} parent The parent node
24620 * @param {Node} node The child node to be inserted
24621 * @param {Node} refNode The child node the node is being inserted before
24623 "beforeinsert" : true
24626 Roo.data.Tree.superclass.constructor.call(this);
24629 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24630 pathSeparator: "/",
24632 proxyNodeEvent : function(){
24633 return this.fireEvent.apply(this, arguments);
24637 * Returns the root node for this tree.
24640 getRootNode : function(){
24645 * Sets the root node for this tree.
24646 * @param {Node} node
24649 setRootNode : function(node){
24651 node.ownerTree = this;
24652 node.isRoot = true;
24653 this.registerNode(node);
24658 * Gets a node in this tree by its id.
24659 * @param {String} id
24662 getNodeById : function(id){
24663 return this.nodeHash[id];
24666 registerNode : function(node){
24667 this.nodeHash[node.id] = node;
24670 unregisterNode : function(node){
24671 delete this.nodeHash[node.id];
24674 toString : function(){
24675 return "[Tree"+(this.id?" "+this.id:"")+"]";
24680 * @class Roo.data.Node
24681 * @extends Roo.util.Observable
24682 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24683 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24685 * @param {Object} attributes The attributes/config for the node
24687 Roo.data.Node = function(attributes){
24689 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24692 this.attributes = attributes || {};
24693 this.leaf = this.attributes.leaf;
24695 * The node id. @type String
24697 this.id = this.attributes.id;
24699 this.id = Roo.id(null, "ynode-");
24700 this.attributes.id = this.id;
24705 * All child nodes of this node. @type Array
24707 this.childNodes = [];
24708 if(!this.childNodes.indexOf){ // indexOf is a must
24709 this.childNodes.indexOf = function(o){
24710 for(var i = 0, len = this.length; i < len; i++){
24719 * The parent node for this node. @type Node
24721 this.parentNode = null;
24723 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24725 this.firstChild = null;
24727 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24729 this.lastChild = null;
24731 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24733 this.previousSibling = null;
24735 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24737 this.nextSibling = null;
24742 * Fires when a new child node is appended
24743 * @param {Tree} tree The owner tree
24744 * @param {Node} this This node
24745 * @param {Node} node The newly appended node
24746 * @param {Number} index The index of the newly appended node
24751 * Fires when a child node is removed
24752 * @param {Tree} tree The owner tree
24753 * @param {Node} this This node
24754 * @param {Node} node The removed node
24759 * Fires when this node is moved to a new location in the tree
24760 * @param {Tree} tree The owner tree
24761 * @param {Node} this This node
24762 * @param {Node} oldParent The old parent of this node
24763 * @param {Node} newParent The new parent of this node
24764 * @param {Number} index The index it was moved to
24769 * Fires when a new child node is inserted.
24770 * @param {Tree} tree The owner tree
24771 * @param {Node} this This node
24772 * @param {Node} node The child node inserted
24773 * @param {Node} refNode The child node the node was inserted before
24777 * @event beforeappend
24778 * Fires before a new child is appended, return false to cancel the append.
24779 * @param {Tree} tree The owner tree
24780 * @param {Node} this This node
24781 * @param {Node} node The child node to be appended
24783 "beforeappend" : true,
24785 * @event beforeremove
24786 * Fires before a child is removed, return false to cancel the remove.
24787 * @param {Tree} tree The owner tree
24788 * @param {Node} this This node
24789 * @param {Node} node The child node to be removed
24791 "beforeremove" : true,
24793 * @event beforemove
24794 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24795 * @param {Tree} tree The owner tree
24796 * @param {Node} this This node
24797 * @param {Node} oldParent The parent of this node
24798 * @param {Node} newParent The new parent this node is moving to
24799 * @param {Number} index The index it is being moved to
24801 "beforemove" : true,
24803 * @event beforeinsert
24804 * Fires before a new child is inserted, return false to cancel the insert.
24805 * @param {Tree} tree The owner tree
24806 * @param {Node} this This node
24807 * @param {Node} node The child node to be inserted
24808 * @param {Node} refNode The child node the node is being inserted before
24810 "beforeinsert" : true
24812 this.listeners = this.attributes.listeners;
24813 Roo.data.Node.superclass.constructor.call(this);
24816 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24817 fireEvent : function(evtName){
24818 // first do standard event for this node
24819 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24822 // then bubble it up to the tree if the event wasn't cancelled
24823 var ot = this.getOwnerTree();
24825 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24833 * Returns true if this node is a leaf
24834 * @return {Boolean}
24836 isLeaf : function(){
24837 return this.leaf === true;
24841 setFirstChild : function(node){
24842 this.firstChild = node;
24846 setLastChild : function(node){
24847 this.lastChild = node;
24852 * Returns true if this node is the last child of its parent
24853 * @return {Boolean}
24855 isLast : function(){
24856 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24860 * Returns true if this node is the first child of its parent
24861 * @return {Boolean}
24863 isFirst : function(){
24864 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24867 hasChildNodes : function(){
24868 return !this.isLeaf() && this.childNodes.length > 0;
24872 * Insert node(s) as the last child node of this node.
24873 * @param {Node/Array} node The node or Array of nodes to append
24874 * @return {Node} The appended node if single append, or null if an array was passed
24876 appendChild : function(node){
24878 if(node instanceof Array){
24880 }else if(arguments.length > 1){
24883 // if passed an array or multiple args do them one by one
24885 for(var i = 0, len = multi.length; i < len; i++) {
24886 this.appendChild(multi[i]);
24889 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24892 var index = this.childNodes.length;
24893 var oldParent = node.parentNode;
24894 // it's a move, make sure we move it cleanly
24896 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24899 oldParent.removeChild(node);
24901 index = this.childNodes.length;
24903 this.setFirstChild(node);
24905 this.childNodes.push(node);
24906 node.parentNode = this;
24907 var ps = this.childNodes[index-1];
24909 node.previousSibling = ps;
24910 ps.nextSibling = node;
24912 node.previousSibling = null;
24914 node.nextSibling = null;
24915 this.setLastChild(node);
24916 node.setOwnerTree(this.getOwnerTree());
24917 this.fireEvent("append", this.ownerTree, this, node, index);
24919 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24926 * Removes a child node from this node.
24927 * @param {Node} node The node to remove
24928 * @return {Node} The removed node
24930 removeChild : function(node){
24931 var index = this.childNodes.indexOf(node);
24935 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24939 // remove it from childNodes collection
24940 this.childNodes.splice(index, 1);
24943 if(node.previousSibling){
24944 node.previousSibling.nextSibling = node.nextSibling;
24946 if(node.nextSibling){
24947 node.nextSibling.previousSibling = node.previousSibling;
24950 // update child refs
24951 if(this.firstChild == node){
24952 this.setFirstChild(node.nextSibling);
24954 if(this.lastChild == node){
24955 this.setLastChild(node.previousSibling);
24958 node.setOwnerTree(null);
24959 // clear any references from the node
24960 node.parentNode = null;
24961 node.previousSibling = null;
24962 node.nextSibling = null;
24963 this.fireEvent("remove", this.ownerTree, this, node);
24968 * Inserts the first node before the second node in this nodes childNodes collection.
24969 * @param {Node} node The node to insert
24970 * @param {Node} refNode The node to insert before (if null the node is appended)
24971 * @return {Node} The inserted node
24973 insertBefore : function(node, refNode){
24974 if(!refNode){ // like standard Dom, refNode can be null for append
24975 return this.appendChild(node);
24978 if(node == refNode){
24982 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24985 var index = this.childNodes.indexOf(refNode);
24986 var oldParent = node.parentNode;
24987 var refIndex = index;
24989 // when moving internally, indexes will change after remove
24990 if(oldParent == this && this.childNodes.indexOf(node) < index){
24994 // it's a move, make sure we move it cleanly
24996 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24999 oldParent.removeChild(node);
25002 this.setFirstChild(node);
25004 this.childNodes.splice(refIndex, 0, node);
25005 node.parentNode = this;
25006 var ps = this.childNodes[refIndex-1];
25008 node.previousSibling = ps;
25009 ps.nextSibling = node;
25011 node.previousSibling = null;
25013 node.nextSibling = refNode;
25014 refNode.previousSibling = node;
25015 node.setOwnerTree(this.getOwnerTree());
25016 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25018 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25024 * Returns the child node at the specified index.
25025 * @param {Number} index
25028 item : function(index){
25029 return this.childNodes[index];
25033 * Replaces one child node in this node with another.
25034 * @param {Node} newChild The replacement node
25035 * @param {Node} oldChild The node to replace
25036 * @return {Node} The replaced node
25038 replaceChild : function(newChild, oldChild){
25039 this.insertBefore(newChild, oldChild);
25040 this.removeChild(oldChild);
25045 * Returns the index of a child node
25046 * @param {Node} node
25047 * @return {Number} The index of the node or -1 if it was not found
25049 indexOf : function(child){
25050 return this.childNodes.indexOf(child);
25054 * Returns the tree this node is in.
25057 getOwnerTree : function(){
25058 // if it doesn't have one, look for one
25059 if(!this.ownerTree){
25063 this.ownerTree = p.ownerTree;
25069 return this.ownerTree;
25073 * Returns depth of this node (the root node has a depth of 0)
25076 getDepth : function(){
25079 while(p.parentNode){
25087 setOwnerTree : function(tree){
25088 // if it's move, we need to update everyone
25089 if(tree != this.ownerTree){
25090 if(this.ownerTree){
25091 this.ownerTree.unregisterNode(this);
25093 this.ownerTree = tree;
25094 var cs = this.childNodes;
25095 for(var i = 0, len = cs.length; i < len; i++) {
25096 cs[i].setOwnerTree(tree);
25099 tree.registerNode(this);
25105 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25106 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25107 * @return {String} The path
25109 getPath : function(attr){
25110 attr = attr || "id";
25111 var p = this.parentNode;
25112 var b = [this.attributes[attr]];
25114 b.unshift(p.attributes[attr]);
25117 var sep = this.getOwnerTree().pathSeparator;
25118 return sep + b.join(sep);
25122 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25123 * function call will be the scope provided or the current node. The arguments to the function
25124 * will be the args provided or the current node. If the function returns false at any point,
25125 * the bubble is stopped.
25126 * @param {Function} fn The function to call
25127 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25128 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25130 bubble : function(fn, scope, args){
25133 if(fn.call(scope || p, args || p) === false){
25141 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25142 * function call will be the scope provided or the current node. The arguments to the function
25143 * will be the args provided or the current node. If the function returns false at any point,
25144 * the cascade is stopped on that branch.
25145 * @param {Function} fn The function to call
25146 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25147 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25149 cascade : function(fn, scope, args){
25150 if(fn.call(scope || this, args || this) !== false){
25151 var cs = this.childNodes;
25152 for(var i = 0, len = cs.length; i < len; i++) {
25153 cs[i].cascade(fn, scope, args);
25159 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25160 * function call will be the scope provided or the current node. The arguments to the function
25161 * will be the args provided or the current node. If the function returns false at any point,
25162 * the iteration stops.
25163 * @param {Function} fn The function to call
25164 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25165 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25167 eachChild : function(fn, scope, args){
25168 var cs = this.childNodes;
25169 for(var i = 0, len = cs.length; i < len; i++) {
25170 if(fn.call(scope || this, args || cs[i]) === false){
25177 * Finds the first child that has the attribute with the specified value.
25178 * @param {String} attribute The attribute name
25179 * @param {Mixed} value The value to search for
25180 * @return {Node} The found child or null if none was found
25182 findChild : function(attribute, value){
25183 var cs = this.childNodes;
25184 for(var i = 0, len = cs.length; i < len; i++) {
25185 if(cs[i].attributes[attribute] == value){
25193 * Finds the first child by a custom function. The child matches if the function passed
25195 * @param {Function} fn
25196 * @param {Object} scope (optional)
25197 * @return {Node} The found child or null if none was found
25199 findChildBy : function(fn, scope){
25200 var cs = this.childNodes;
25201 for(var i = 0, len = cs.length; i < len; i++) {
25202 if(fn.call(scope||cs[i], cs[i]) === true){
25210 * Sorts this nodes children using the supplied sort function
25211 * @param {Function} fn
25212 * @param {Object} scope (optional)
25214 sort : function(fn, scope){
25215 var cs = this.childNodes;
25216 var len = cs.length;
25218 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25220 for(var i = 0; i < len; i++){
25222 n.previousSibling = cs[i-1];
25223 n.nextSibling = cs[i+1];
25225 this.setFirstChild(n);
25228 this.setLastChild(n);
25235 * Returns true if this node is an ancestor (at any point) of the passed node.
25236 * @param {Node} node
25237 * @return {Boolean}
25239 contains : function(node){
25240 return node.isAncestor(this);
25244 * Returns true if the passed node is an ancestor (at any point) of this node.
25245 * @param {Node} node
25246 * @return {Boolean}
25248 isAncestor : function(node){
25249 var p = this.parentNode;
25259 toString : function(){
25260 return "[Node"+(this.id?" "+this.id:"")+"]";
25264 * Ext JS Library 1.1.1
25265 * Copyright(c) 2006-2007, Ext JS, LLC.
25267 * Originally Released Under LGPL - original licence link has changed is not relivant.
25270 * <script type="text/javascript">
25275 * @extends Roo.Element
25276 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25277 * automatic maintaining of shadow/shim positions.
25278 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25279 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25280 * you can pass a string with a CSS class name. False turns off the shadow.
25281 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25282 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25283 * @cfg {String} cls CSS class to add to the element
25284 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25285 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25287 * @param {Object} config An object with config options.
25288 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25291 Roo.Layer = function(config, existingEl){
25292 config = config || {};
25293 var dh = Roo.DomHelper;
25294 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25296 this.dom = Roo.getDom(existingEl);
25299 var o = config.dh || {tag: "div", cls: "x-layer"};
25300 this.dom = dh.append(pel, o);
25303 this.addClass(config.cls);
25305 this.constrain = config.constrain !== false;
25306 this.visibilityMode = Roo.Element.VISIBILITY;
25308 this.id = this.dom.id = config.id;
25310 this.id = Roo.id(this.dom);
25312 this.zindex = config.zindex || this.getZIndex();
25313 this.position("absolute", this.zindex);
25315 this.shadowOffset = config.shadowOffset || 4;
25316 this.shadow = new Roo.Shadow({
25317 offset : this.shadowOffset,
25318 mode : config.shadow
25321 this.shadowOffset = 0;
25323 this.useShim = config.shim !== false && Roo.useShims;
25324 this.useDisplay = config.useDisplay;
25328 var supr = Roo.Element.prototype;
25330 // shims are shared among layer to keep from having 100 iframes
25333 Roo.extend(Roo.Layer, Roo.Element, {
25335 getZIndex : function(){
25336 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25339 getShim : function(){
25346 var shim = shims.shift();
25348 shim = this.createShim();
25349 shim.enableDisplayMode('block');
25350 shim.dom.style.display = 'none';
25351 shim.dom.style.visibility = 'visible';
25353 var pn = this.dom.parentNode;
25354 if(shim.dom.parentNode != pn){
25355 pn.insertBefore(shim.dom, this.dom);
25357 shim.setStyle('z-index', this.getZIndex()-2);
25362 hideShim : function(){
25364 this.shim.setDisplayed(false);
25365 shims.push(this.shim);
25370 disableShadow : function(){
25372 this.shadowDisabled = true;
25373 this.shadow.hide();
25374 this.lastShadowOffset = this.shadowOffset;
25375 this.shadowOffset = 0;
25379 enableShadow : function(show){
25381 this.shadowDisabled = false;
25382 this.shadowOffset = this.lastShadowOffset;
25383 delete this.lastShadowOffset;
25391 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25392 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25393 sync : function(doShow){
25394 var sw = this.shadow;
25395 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25396 var sh = this.getShim();
25398 var w = this.getWidth(),
25399 h = this.getHeight();
25401 var l = this.getLeft(true),
25402 t = this.getTop(true);
25404 if(sw && !this.shadowDisabled){
25405 if(doShow && !sw.isVisible()){
25408 sw.realign(l, t, w, h);
25414 // fit the shim behind the shadow, so it is shimmed too
25415 var a = sw.adjusts, s = sh.dom.style;
25416 s.left = (Math.min(l, l+a.l))+"px";
25417 s.top = (Math.min(t, t+a.t))+"px";
25418 s.width = (w+a.w)+"px";
25419 s.height = (h+a.h)+"px";
25426 sh.setLeftTop(l, t);
25433 destroy : function(){
25436 this.shadow.hide();
25438 this.removeAllListeners();
25439 var pn = this.dom.parentNode;
25441 pn.removeChild(this.dom);
25443 Roo.Element.uncache(this.id);
25446 remove : function(){
25451 beginUpdate : function(){
25452 this.updating = true;
25456 endUpdate : function(){
25457 this.updating = false;
25462 hideUnders : function(negOffset){
25464 this.shadow.hide();
25470 constrainXY : function(){
25471 if(this.constrain){
25472 var vw = Roo.lib.Dom.getViewWidth(),
25473 vh = Roo.lib.Dom.getViewHeight();
25474 var s = Roo.get(document).getScroll();
25476 var xy = this.getXY();
25477 var x = xy[0], y = xy[1];
25478 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25479 // only move it if it needs it
25481 // first validate right/bottom
25482 if((x + w) > vw+s.left){
25483 x = vw - w - this.shadowOffset;
25486 if((y + h) > vh+s.top){
25487 y = vh - h - this.shadowOffset;
25490 // then make sure top/left isn't negative
25501 var ay = this.avoidY;
25502 if(y <= ay && (y+h) >= ay){
25508 supr.setXY.call(this, xy);
25514 isVisible : function(){
25515 return this.visible;
25519 showAction : function(){
25520 this.visible = true; // track visibility to prevent getStyle calls
25521 if(this.useDisplay === true){
25522 this.setDisplayed("");
25523 }else if(this.lastXY){
25524 supr.setXY.call(this, this.lastXY);
25525 }else if(this.lastLT){
25526 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25531 hideAction : function(){
25532 this.visible = false;
25533 if(this.useDisplay === true){
25534 this.setDisplayed(false);
25536 this.setLeftTop(-10000,-10000);
25540 // overridden Element method
25541 setVisible : function(v, a, d, c, e){
25546 var cb = function(){
25551 }.createDelegate(this);
25552 supr.setVisible.call(this, true, true, d, cb, e);
25555 this.hideUnders(true);
25564 }.createDelegate(this);
25566 supr.setVisible.call(this, v, a, d, cb, e);
25575 storeXY : function(xy){
25576 delete this.lastLT;
25580 storeLeftTop : function(left, top){
25581 delete this.lastXY;
25582 this.lastLT = [left, top];
25586 beforeFx : function(){
25587 this.beforeAction();
25588 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25592 afterFx : function(){
25593 Roo.Layer.superclass.afterFx.apply(this, arguments);
25594 this.sync(this.isVisible());
25598 beforeAction : function(){
25599 if(!this.updating && this.shadow){
25600 this.shadow.hide();
25604 // overridden Element method
25605 setLeft : function(left){
25606 this.storeLeftTop(left, this.getTop(true));
25607 supr.setLeft.apply(this, arguments);
25611 setTop : function(top){
25612 this.storeLeftTop(this.getLeft(true), top);
25613 supr.setTop.apply(this, arguments);
25617 setLeftTop : function(left, top){
25618 this.storeLeftTop(left, top);
25619 supr.setLeftTop.apply(this, arguments);
25623 setXY : function(xy, a, d, c, e){
25625 this.beforeAction();
25627 var cb = this.createCB(c);
25628 supr.setXY.call(this, xy, a, d, cb, e);
25635 createCB : function(c){
25646 // overridden Element method
25647 setX : function(x, a, d, c, e){
25648 this.setXY([x, this.getY()], a, d, c, e);
25651 // overridden Element method
25652 setY : function(y, a, d, c, e){
25653 this.setXY([this.getX(), y], a, d, c, e);
25656 // overridden Element method
25657 setSize : function(w, h, a, d, c, e){
25658 this.beforeAction();
25659 var cb = this.createCB(c);
25660 supr.setSize.call(this, w, h, a, d, cb, e);
25666 // overridden Element method
25667 setWidth : function(w, a, d, c, e){
25668 this.beforeAction();
25669 var cb = this.createCB(c);
25670 supr.setWidth.call(this, w, a, d, cb, e);
25676 // overridden Element method
25677 setHeight : function(h, a, d, c, e){
25678 this.beforeAction();
25679 var cb = this.createCB(c);
25680 supr.setHeight.call(this, h, a, d, cb, e);
25686 // overridden Element method
25687 setBounds : function(x, y, w, h, a, d, c, e){
25688 this.beforeAction();
25689 var cb = this.createCB(c);
25691 this.storeXY([x, y]);
25692 supr.setXY.call(this, [x, y]);
25693 supr.setSize.call(this, w, h, a, d, cb, e);
25696 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25702 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25703 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25704 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25705 * @param {Number} zindex The new z-index to set
25706 * @return {this} The Layer
25708 setZIndex : function(zindex){
25709 this.zindex = zindex;
25710 this.setStyle("z-index", zindex + 2);
25712 this.shadow.setZIndex(zindex + 1);
25715 this.shim.setStyle("z-index", zindex);
25721 * Ext JS Library 1.1.1
25722 * Copyright(c) 2006-2007, Ext JS, LLC.
25724 * Originally Released Under LGPL - original licence link has changed is not relivant.
25727 * <script type="text/javascript">
25732 * @class Roo.Shadow
25733 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25734 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25735 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25737 * Create a new Shadow
25738 * @param {Object} config The config object
25740 Roo.Shadow = function(config){
25741 Roo.apply(this, config);
25742 if(typeof this.mode != "string"){
25743 this.mode = this.defaultMode;
25745 var o = this.offset, a = {h: 0};
25746 var rad = Math.floor(this.offset/2);
25747 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25753 a.l -= this.offset + rad;
25754 a.t -= this.offset + rad;
25765 a.l -= (this.offset - rad);
25766 a.t -= this.offset + rad;
25768 a.w -= (this.offset - rad)*2;
25779 a.l -= (this.offset - rad);
25780 a.t -= (this.offset - rad);
25782 a.w -= (this.offset + rad + 1);
25783 a.h -= (this.offset + rad);
25792 Roo.Shadow.prototype = {
25794 * @cfg {String} mode
25795 * The shadow display mode. Supports the following options:<br />
25796 * sides: Shadow displays on both sides and bottom only<br />
25797 * frame: Shadow displays equally on all four sides<br />
25798 * drop: Traditional bottom-right drop shadow (default)
25801 * @cfg {String} offset
25802 * The number of pixels to offset the shadow from the element (defaults to 4)
25807 defaultMode: "drop",
25810 * Displays the shadow under the target element
25811 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25813 show : function(target){
25814 target = Roo.get(target);
25816 this.el = Roo.Shadow.Pool.pull();
25817 if(this.el.dom.nextSibling != target.dom){
25818 this.el.insertBefore(target);
25821 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25823 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25826 target.getLeft(true),
25827 target.getTop(true),
25831 this.el.dom.style.display = "block";
25835 * Returns true if the shadow is visible, else false
25837 isVisible : function(){
25838 return this.el ? true : false;
25842 * Direct alignment when values are already available. Show must be called at least once before
25843 * calling this method to ensure it is initialized.
25844 * @param {Number} left The target element left position
25845 * @param {Number} top The target element top position
25846 * @param {Number} width The target element width
25847 * @param {Number} height The target element height
25849 realign : function(l, t, w, h){
25853 var a = this.adjusts, d = this.el.dom, s = d.style;
25855 s.left = (l+a.l)+"px";
25856 s.top = (t+a.t)+"px";
25857 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25859 if(s.width != sws || s.height != shs){
25863 var cn = d.childNodes;
25864 var sww = Math.max(0, (sw-12))+"px";
25865 cn[0].childNodes[1].style.width = sww;
25866 cn[1].childNodes[1].style.width = sww;
25867 cn[2].childNodes[1].style.width = sww;
25868 cn[1].style.height = Math.max(0, (sh-12))+"px";
25874 * Hides this shadow
25878 this.el.dom.style.display = "none";
25879 Roo.Shadow.Pool.push(this.el);
25885 * Adjust the z-index of this shadow
25886 * @param {Number} zindex The new z-index
25888 setZIndex : function(z){
25891 this.el.setStyle("z-index", z);
25896 // Private utility class that manages the internal Shadow cache
25897 Roo.Shadow.Pool = function(){
25899 var markup = Roo.isIE ?
25900 '<div class="x-ie-shadow"></div>' :
25901 '<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>';
25904 var sh = p.shift();
25906 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25907 sh.autoBoxAdjust = false;
25912 push : function(sh){
25918 * Ext JS Library 1.1.1
25919 * Copyright(c) 2006-2007, Ext JS, LLC.
25921 * Originally Released Under LGPL - original licence link has changed is not relivant.
25924 * <script type="text/javascript">
25929 * @class Roo.SplitBar
25930 * @extends Roo.util.Observable
25931 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25935 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25936 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25937 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25938 split.minSize = 100;
25939 split.maxSize = 600;
25940 split.animate = true;
25941 split.on('moved', splitterMoved);
25944 * Create a new SplitBar
25945 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25946 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25947 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25948 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25949 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25950 position of the SplitBar).
25952 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25955 this.el = Roo.get(dragElement, true);
25956 this.el.dom.unselectable = "on";
25958 this.resizingEl = Roo.get(resizingElement, true);
25962 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25963 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25966 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25969 * The minimum size of the resizing element. (Defaults to 0)
25975 * The maximum size of the resizing element. (Defaults to 2000)
25978 this.maxSize = 2000;
25981 * Whether to animate the transition to the new size
25984 this.animate = false;
25987 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25990 this.useShim = false;
25995 if(!existingProxy){
25997 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25999 this.proxy = Roo.get(existingProxy).dom;
26002 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26005 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26008 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26011 this.dragSpecs = {};
26014 * @private The adapter to use to positon and resize elements
26016 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26017 this.adapter.init(this);
26019 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26021 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26022 this.el.addClass("x-splitbar-h");
26025 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26026 this.el.addClass("x-splitbar-v");
26032 * Fires when the splitter is moved (alias for {@link #event-moved})
26033 * @param {Roo.SplitBar} this
26034 * @param {Number} newSize the new width or height
26039 * Fires when the splitter is moved
26040 * @param {Roo.SplitBar} this
26041 * @param {Number} newSize the new width or height
26045 * @event beforeresize
26046 * Fires before the splitter is dragged
26047 * @param {Roo.SplitBar} this
26049 "beforeresize" : true,
26051 "beforeapply" : true
26054 Roo.util.Observable.call(this);
26057 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26058 onStartProxyDrag : function(x, y){
26059 this.fireEvent("beforeresize", this);
26061 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26063 o.enableDisplayMode("block");
26064 // all splitbars share the same overlay
26065 Roo.SplitBar.prototype.overlay = o;
26067 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26068 this.overlay.show();
26069 Roo.get(this.proxy).setDisplayed("block");
26070 var size = this.adapter.getElementSize(this);
26071 this.activeMinSize = this.getMinimumSize();;
26072 this.activeMaxSize = this.getMaximumSize();;
26073 var c1 = size - this.activeMinSize;
26074 var c2 = Math.max(this.activeMaxSize - size, 0);
26075 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26076 this.dd.resetConstraints();
26077 this.dd.setXConstraint(
26078 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26079 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26081 this.dd.setYConstraint(0, 0);
26083 this.dd.resetConstraints();
26084 this.dd.setXConstraint(0, 0);
26085 this.dd.setYConstraint(
26086 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26087 this.placement == Roo.SplitBar.TOP ? c2 : c1
26090 this.dragSpecs.startSize = size;
26091 this.dragSpecs.startPoint = [x, y];
26092 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26096 * @private Called after the drag operation by the DDProxy
26098 onEndProxyDrag : function(e){
26099 Roo.get(this.proxy).setDisplayed(false);
26100 var endPoint = Roo.lib.Event.getXY(e);
26102 this.overlay.hide();
26105 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26106 newSize = this.dragSpecs.startSize +
26107 (this.placement == Roo.SplitBar.LEFT ?
26108 endPoint[0] - this.dragSpecs.startPoint[0] :
26109 this.dragSpecs.startPoint[0] - endPoint[0]
26112 newSize = this.dragSpecs.startSize +
26113 (this.placement == Roo.SplitBar.TOP ?
26114 endPoint[1] - this.dragSpecs.startPoint[1] :
26115 this.dragSpecs.startPoint[1] - endPoint[1]
26118 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26119 if(newSize != this.dragSpecs.startSize){
26120 if(this.fireEvent('beforeapply', this, newSize) !== false){
26121 this.adapter.setElementSize(this, newSize);
26122 this.fireEvent("moved", this, newSize);
26123 this.fireEvent("resize", this, newSize);
26129 * Get the adapter this SplitBar uses
26130 * @return The adapter object
26132 getAdapter : function(){
26133 return this.adapter;
26137 * Set the adapter this SplitBar uses
26138 * @param {Object} adapter A SplitBar adapter object
26140 setAdapter : function(adapter){
26141 this.adapter = adapter;
26142 this.adapter.init(this);
26146 * Gets the minimum size for the resizing element
26147 * @return {Number} The minimum size
26149 getMinimumSize : function(){
26150 return this.minSize;
26154 * Sets the minimum size for the resizing element
26155 * @param {Number} minSize The minimum size
26157 setMinimumSize : function(minSize){
26158 this.minSize = minSize;
26162 * Gets the maximum size for the resizing element
26163 * @return {Number} The maximum size
26165 getMaximumSize : function(){
26166 return this.maxSize;
26170 * Sets the maximum size for the resizing element
26171 * @param {Number} maxSize The maximum size
26173 setMaximumSize : function(maxSize){
26174 this.maxSize = maxSize;
26178 * Sets the initialize size for the resizing element
26179 * @param {Number} size The initial size
26181 setCurrentSize : function(size){
26182 var oldAnimate = this.animate;
26183 this.animate = false;
26184 this.adapter.setElementSize(this, size);
26185 this.animate = oldAnimate;
26189 * Destroy this splitbar.
26190 * @param {Boolean} removeEl True to remove the element
26192 destroy : function(removeEl){
26194 this.shim.remove();
26197 this.proxy.parentNode.removeChild(this.proxy);
26205 * @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.
26207 Roo.SplitBar.createProxy = function(dir){
26208 var proxy = new Roo.Element(document.createElement("div"));
26209 proxy.unselectable();
26210 var cls = 'x-splitbar-proxy';
26211 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26212 document.body.appendChild(proxy.dom);
26217 * @class Roo.SplitBar.BasicLayoutAdapter
26218 * Default Adapter. It assumes the splitter and resizing element are not positioned
26219 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26221 Roo.SplitBar.BasicLayoutAdapter = function(){
26224 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26225 // do nothing for now
26226 init : function(s){
26230 * Called before drag operations to get the current size of the resizing element.
26231 * @param {Roo.SplitBar} s The SplitBar using this adapter
26233 getElementSize : function(s){
26234 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26235 return s.resizingEl.getWidth();
26237 return s.resizingEl.getHeight();
26242 * Called after drag operations to set the size of the resizing element.
26243 * @param {Roo.SplitBar} s The SplitBar using this adapter
26244 * @param {Number} newSize The new size to set
26245 * @param {Function} onComplete A function to be invoked when resizing is complete
26247 setElementSize : function(s, newSize, onComplete){
26248 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26250 s.resizingEl.setWidth(newSize);
26252 onComplete(s, newSize);
26255 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26260 s.resizingEl.setHeight(newSize);
26262 onComplete(s, newSize);
26265 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26272 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26273 * @extends Roo.SplitBar.BasicLayoutAdapter
26274 * Adapter that moves the splitter element to align with the resized sizing element.
26275 * Used with an absolute positioned SplitBar.
26276 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26277 * document.body, make sure you assign an id to the body element.
26279 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26280 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26281 this.container = Roo.get(container);
26284 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26285 init : function(s){
26286 this.basic.init(s);
26289 getElementSize : function(s){
26290 return this.basic.getElementSize(s);
26293 setElementSize : function(s, newSize, onComplete){
26294 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26297 moveSplitter : function(s){
26298 var yes = Roo.SplitBar;
26299 switch(s.placement){
26301 s.el.setX(s.resizingEl.getRight());
26304 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26307 s.el.setY(s.resizingEl.getBottom());
26310 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26317 * Orientation constant - Create a vertical SplitBar
26321 Roo.SplitBar.VERTICAL = 1;
26324 * Orientation constant - Create a horizontal SplitBar
26328 Roo.SplitBar.HORIZONTAL = 2;
26331 * Placement constant - The resizing element is to the left of the splitter element
26335 Roo.SplitBar.LEFT = 1;
26338 * Placement constant - The resizing element is to the right of the splitter element
26342 Roo.SplitBar.RIGHT = 2;
26345 * Placement constant - The resizing element is positioned above the splitter element
26349 Roo.SplitBar.TOP = 3;
26352 * Placement constant - The resizing element is positioned under splitter element
26356 Roo.SplitBar.BOTTOM = 4;
26359 * Ext JS Library 1.1.1
26360 * Copyright(c) 2006-2007, Ext JS, LLC.
26362 * Originally Released Under LGPL - original licence link has changed is not relivant.
26365 * <script type="text/javascript">
26370 * @extends Roo.util.Observable
26371 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26372 * This class also supports single and multi selection modes. <br>
26373 * Create a data model bound view:
26375 var store = new Roo.data.Store(...);
26377 var view = new Roo.View({
26379 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26381 singleSelect: true,
26382 selectedClass: "ydataview-selected",
26386 // listen for node click?
26387 view.on("click", function(vw, index, node, e){
26388 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26392 dataModel.load("foobar.xml");
26394 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26396 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26397 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26399 * Note: old style constructor is still suported (container, template, config)
26402 * Create a new View
26403 * @param {Object} config The config object
26406 Roo.View = function(config, depreciated_tpl, depreciated_config){
26408 this.parent = false;
26410 if (typeof(depreciated_tpl) == 'undefined') {
26411 // new way.. - universal constructor.
26412 Roo.apply(this, config);
26413 this.el = Roo.get(this.el);
26416 this.el = Roo.get(config);
26417 this.tpl = depreciated_tpl;
26418 Roo.apply(this, depreciated_config);
26420 this.wrapEl = this.el.wrap().wrap();
26421 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26424 if(typeof(this.tpl) == "string"){
26425 this.tpl = new Roo.Template(this.tpl);
26427 // support xtype ctors..
26428 this.tpl = new Roo.factory(this.tpl, Roo);
26432 this.tpl.compile();
26437 * @event beforeclick
26438 * Fires before a click is processed. Returns false to cancel the default action.
26439 * @param {Roo.View} this
26440 * @param {Number} index The index of the target node
26441 * @param {HTMLElement} node The target node
26442 * @param {Roo.EventObject} e The raw event object
26444 "beforeclick" : true,
26447 * Fires when a template node is clicked.
26448 * @param {Roo.View} this
26449 * @param {Number} index The index of the target node
26450 * @param {HTMLElement} node The target node
26451 * @param {Roo.EventObject} e The raw event object
26456 * Fires when a template node is double clicked.
26457 * @param {Roo.View} this
26458 * @param {Number} index The index of the target node
26459 * @param {HTMLElement} node The target node
26460 * @param {Roo.EventObject} e The raw event object
26464 * @event contextmenu
26465 * Fires when a template node is right clicked.
26466 * @param {Roo.View} this
26467 * @param {Number} index The index of the target node
26468 * @param {HTMLElement} node The target node
26469 * @param {Roo.EventObject} e The raw event object
26471 "contextmenu" : true,
26473 * @event selectionchange
26474 * Fires when the selected nodes change.
26475 * @param {Roo.View} this
26476 * @param {Array} selections Array of the selected nodes
26478 "selectionchange" : true,
26481 * @event beforeselect
26482 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26483 * @param {Roo.View} this
26484 * @param {HTMLElement} node The node to be selected
26485 * @param {Array} selections Array of currently selected nodes
26487 "beforeselect" : true,
26489 * @event preparedata
26490 * Fires on every row to render, to allow you to change the data.
26491 * @param {Roo.View} this
26492 * @param {Object} data to be rendered (change this)
26494 "preparedata" : true
26502 "click": this.onClick,
26503 "dblclick": this.onDblClick,
26504 "contextmenu": this.onContextMenu,
26508 this.selections = [];
26510 this.cmp = new Roo.CompositeElementLite([]);
26512 this.store = Roo.factory(this.store, Roo.data);
26513 this.setStore(this.store, true);
26516 if ( this.footer && this.footer.xtype) {
26518 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26520 this.footer.dataSource = this.store;
26521 this.footer.container = fctr;
26522 this.footer = Roo.factory(this.footer, Roo);
26523 fctr.insertFirst(this.el);
26525 // this is a bit insane - as the paging toolbar seems to detach the el..
26526 // dom.parentNode.parentNode.parentNode
26527 // they get detached?
26531 Roo.View.superclass.constructor.call(this);
26536 Roo.extend(Roo.View, Roo.util.Observable, {
26539 * @cfg {Roo.data.Store} store Data store to load data from.
26544 * @cfg {String|Roo.Element} el The container element.
26549 * @cfg {String|Roo.Template} tpl The template used by this View
26553 * @cfg {String} dataName the named area of the template to use as the data area
26554 * Works with domtemplates roo-name="name"
26558 * @cfg {String} selectedClass The css class to add to selected nodes
26560 selectedClass : "x-view-selected",
26562 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26567 * @cfg {String} text to display on mask (default Loading)
26571 * @cfg {Boolean} multiSelect Allow multiple selection
26573 multiSelect : false,
26575 * @cfg {Boolean} singleSelect Allow single selection
26577 singleSelect: false,
26580 * @cfg {Boolean} toggleSelect - selecting
26582 toggleSelect : false,
26585 * @cfg {Boolean} tickable - selecting
26590 * Returns the element this view is bound to.
26591 * @return {Roo.Element}
26593 getEl : function(){
26594 return this.wrapEl;
26600 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26602 refresh : function(){
26603 //Roo.log('refresh');
26606 // if we are using something like 'domtemplate', then
26607 // the what gets used is:
26608 // t.applySubtemplate(NAME, data, wrapping data..)
26609 // the outer template then get' applied with
26610 // the store 'extra data'
26611 // and the body get's added to the
26612 // roo-name="data" node?
26613 // <span class='roo-tpl-{name}'></span> ?????
26617 this.clearSelections();
26618 this.el.update("");
26620 var records = this.store.getRange();
26621 if(records.length < 1) {
26623 // is this valid?? = should it render a template??
26625 this.el.update(this.emptyText);
26629 if (this.dataName) {
26630 this.el.update(t.apply(this.store.meta)); //????
26631 el = this.el.child('.roo-tpl-' + this.dataName);
26634 for(var i = 0, len = records.length; i < len; i++){
26635 var data = this.prepareData(records[i].data, i, records[i]);
26636 this.fireEvent("preparedata", this, data, i, records[i]);
26638 var d = Roo.apply({}, data);
26641 Roo.apply(d, {'roo-id' : Roo.id()});
26645 Roo.each(this.parent.item, function(item){
26646 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26649 Roo.apply(d, {'roo-data-checked' : 'checked'});
26653 html[html.length] = Roo.util.Format.trim(
26655 t.applySubtemplate(this.dataName, d, this.store.meta) :
26662 el.update(html.join(""));
26663 this.nodes = el.dom.childNodes;
26664 this.updateIndexes(0);
26669 * Function to override to reformat the data that is sent to
26670 * the template for each node.
26671 * DEPRICATED - use the preparedata event handler.
26672 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26673 * a JSON object for an UpdateManager bound view).
26675 prepareData : function(data, index, record)
26677 this.fireEvent("preparedata", this, data, index, record);
26681 onUpdate : function(ds, record){
26682 // Roo.log('on update');
26683 this.clearSelections();
26684 var index = this.store.indexOf(record);
26685 var n = this.nodes[index];
26686 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26687 n.parentNode.removeChild(n);
26688 this.updateIndexes(index, index);
26694 onAdd : function(ds, records, index)
26696 //Roo.log(['on Add', ds, records, index] );
26697 this.clearSelections();
26698 if(this.nodes.length == 0){
26702 var n = this.nodes[index];
26703 for(var i = 0, len = records.length; i < len; i++){
26704 var d = this.prepareData(records[i].data, i, records[i]);
26706 this.tpl.insertBefore(n, d);
26709 this.tpl.append(this.el, d);
26712 this.updateIndexes(index);
26715 onRemove : function(ds, record, index){
26716 // Roo.log('onRemove');
26717 this.clearSelections();
26718 var el = this.dataName ?
26719 this.el.child('.roo-tpl-' + this.dataName) :
26722 el.dom.removeChild(this.nodes[index]);
26723 this.updateIndexes(index);
26727 * Refresh an individual node.
26728 * @param {Number} index
26730 refreshNode : function(index){
26731 this.onUpdate(this.store, this.store.getAt(index));
26734 updateIndexes : function(startIndex, endIndex){
26735 var ns = this.nodes;
26736 startIndex = startIndex || 0;
26737 endIndex = endIndex || ns.length - 1;
26738 for(var i = startIndex; i <= endIndex; i++){
26739 ns[i].nodeIndex = i;
26744 * Changes the data store this view uses and refresh the view.
26745 * @param {Store} store
26747 setStore : function(store, initial){
26748 if(!initial && this.store){
26749 this.store.un("datachanged", this.refresh);
26750 this.store.un("add", this.onAdd);
26751 this.store.un("remove", this.onRemove);
26752 this.store.un("update", this.onUpdate);
26753 this.store.un("clear", this.refresh);
26754 this.store.un("beforeload", this.onBeforeLoad);
26755 this.store.un("load", this.onLoad);
26756 this.store.un("loadexception", this.onLoad);
26760 store.on("datachanged", this.refresh, this);
26761 store.on("add", this.onAdd, this);
26762 store.on("remove", this.onRemove, this);
26763 store.on("update", this.onUpdate, this);
26764 store.on("clear", this.refresh, this);
26765 store.on("beforeload", this.onBeforeLoad, this);
26766 store.on("load", this.onLoad, this);
26767 store.on("loadexception", this.onLoad, this);
26775 * onbeforeLoad - masks the loading area.
26778 onBeforeLoad : function(store,opts)
26780 //Roo.log('onBeforeLoad');
26782 this.el.update("");
26784 this.el.mask(this.mask ? this.mask : "Loading" );
26786 onLoad : function ()
26793 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26794 * @param {HTMLElement} node
26795 * @return {HTMLElement} The template node
26797 findItemFromChild : function(node){
26798 var el = this.dataName ?
26799 this.el.child('.roo-tpl-' + this.dataName,true) :
26802 if(!node || node.parentNode == el){
26805 var p = node.parentNode;
26806 while(p && p != el){
26807 if(p.parentNode == el){
26816 onClick : function(e){
26817 var item = this.findItemFromChild(e.getTarget());
26819 var index = this.indexOf(item);
26820 if(this.onItemClick(item, index, e) !== false){
26821 this.fireEvent("click", this, index, item, e);
26824 this.clearSelections();
26829 onContextMenu : function(e){
26830 var item = this.findItemFromChild(e.getTarget());
26832 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26837 onDblClick : function(e){
26838 var item = this.findItemFromChild(e.getTarget());
26840 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26844 onItemClick : function(item, index, e)
26846 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26849 if (this.toggleSelect) {
26850 var m = this.isSelected(item) ? 'unselect' : 'select';
26853 _t[m](item, true, false);
26856 if(this.multiSelect || this.singleSelect){
26857 if(this.multiSelect && e.shiftKey && this.lastSelection){
26858 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26860 this.select(item, this.multiSelect && e.ctrlKey);
26861 this.lastSelection = item;
26864 if(!this.tickable){
26865 e.preventDefault();
26873 * Get the number of selected nodes.
26876 getSelectionCount : function(){
26877 return this.selections.length;
26881 * Get the currently selected nodes.
26882 * @return {Array} An array of HTMLElements
26884 getSelectedNodes : function(){
26885 return this.selections;
26889 * Get the indexes of the selected nodes.
26892 getSelectedIndexes : function(){
26893 var indexes = [], s = this.selections;
26894 for(var i = 0, len = s.length; i < len; i++){
26895 indexes.push(s[i].nodeIndex);
26901 * Clear all selections
26902 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26904 clearSelections : function(suppressEvent){
26905 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26906 this.cmp.elements = this.selections;
26907 this.cmp.removeClass(this.selectedClass);
26908 this.selections = [];
26909 if(!suppressEvent){
26910 this.fireEvent("selectionchange", this, this.selections);
26916 * Returns true if the passed node is selected
26917 * @param {HTMLElement/Number} node The node or node index
26918 * @return {Boolean}
26920 isSelected : function(node){
26921 var s = this.selections;
26925 node = this.getNode(node);
26926 return s.indexOf(node) !== -1;
26931 * @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
26932 * @param {Boolean} keepExisting (optional) true to keep existing selections
26933 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26935 select : function(nodeInfo, keepExisting, suppressEvent){
26936 if(nodeInfo instanceof Array){
26938 this.clearSelections(true);
26940 for(var i = 0, len = nodeInfo.length; i < len; i++){
26941 this.select(nodeInfo[i], true, true);
26945 var node = this.getNode(nodeInfo);
26946 if(!node || this.isSelected(node)){
26947 return; // already selected.
26950 this.clearSelections(true);
26953 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26954 Roo.fly(node).addClass(this.selectedClass);
26955 this.selections.push(node);
26956 if(!suppressEvent){
26957 this.fireEvent("selectionchange", this, this.selections);
26965 * @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
26966 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26967 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26969 unselect : function(nodeInfo, keepExisting, suppressEvent)
26971 if(nodeInfo instanceof Array){
26972 Roo.each(this.selections, function(s) {
26973 this.unselect(s, nodeInfo);
26977 var node = this.getNode(nodeInfo);
26978 if(!node || !this.isSelected(node)){
26979 //Roo.log("not selected");
26980 return; // not selected.
26984 Roo.each(this.selections, function(s) {
26986 Roo.fly(node).removeClass(this.selectedClass);
26993 this.selections= ns;
26994 this.fireEvent("selectionchange", this, this.selections);
26998 * Gets a template node.
26999 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27000 * @return {HTMLElement} The node or null if it wasn't found
27002 getNode : function(nodeInfo){
27003 if(typeof nodeInfo == "string"){
27004 return document.getElementById(nodeInfo);
27005 }else if(typeof nodeInfo == "number"){
27006 return this.nodes[nodeInfo];
27012 * Gets a range template nodes.
27013 * @param {Number} startIndex
27014 * @param {Number} endIndex
27015 * @return {Array} An array of nodes
27017 getNodes : function(start, end){
27018 var ns = this.nodes;
27019 start = start || 0;
27020 end = typeof end == "undefined" ? ns.length - 1 : end;
27023 for(var i = start; i <= end; i++){
27027 for(var i = start; i >= end; i--){
27035 * Finds the index of the passed node
27036 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27037 * @return {Number} The index of the node or -1
27039 indexOf : function(node){
27040 node = this.getNode(node);
27041 if(typeof node.nodeIndex == "number"){
27042 return node.nodeIndex;
27044 var ns = this.nodes;
27045 for(var i = 0, len = ns.length; i < len; i++){
27055 * Ext JS Library 1.1.1
27056 * Copyright(c) 2006-2007, Ext JS, LLC.
27058 * Originally Released Under LGPL - original licence link has changed is not relivant.
27061 * <script type="text/javascript">
27065 * @class Roo.JsonView
27066 * @extends Roo.View
27067 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27069 var view = new Roo.JsonView({
27070 container: "my-element",
27071 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27076 // listen for node click?
27077 view.on("click", function(vw, index, node, e){
27078 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27081 // direct load of JSON data
27082 view.load("foobar.php");
27084 // Example from my blog list
27085 var tpl = new Roo.Template(
27086 '<div class="entry">' +
27087 '<a class="entry-title" href="{link}">{title}</a>' +
27088 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27089 "</div><hr />"
27092 var moreView = new Roo.JsonView({
27093 container : "entry-list",
27097 moreView.on("beforerender", this.sortEntries, this);
27099 url: "/blog/get-posts.php",
27100 params: "allposts=true",
27101 text: "Loading Blog Entries..."
27105 * Note: old code is supported with arguments : (container, template, config)
27109 * Create a new JsonView
27111 * @param {Object} config The config object
27114 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27117 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27119 var um = this.el.getUpdateManager();
27120 um.setRenderer(this);
27121 um.on("update", this.onLoad, this);
27122 um.on("failure", this.onLoadException, this);
27125 * @event beforerender
27126 * Fires before rendering of the downloaded JSON data.
27127 * @param {Roo.JsonView} this
27128 * @param {Object} data The JSON data loaded
27132 * Fires when data is loaded.
27133 * @param {Roo.JsonView} this
27134 * @param {Object} data The JSON data loaded
27135 * @param {Object} response The raw Connect response object
27138 * @event loadexception
27139 * Fires when loading fails.
27140 * @param {Roo.JsonView} this
27141 * @param {Object} response The raw Connect response object
27144 'beforerender' : true,
27146 'loadexception' : true
27149 Roo.extend(Roo.JsonView, Roo.View, {
27151 * @type {String} The root property in the loaded JSON object that contains the data
27156 * Refreshes the view.
27158 refresh : function(){
27159 this.clearSelections();
27160 this.el.update("");
27162 var o = this.jsonData;
27163 if(o && o.length > 0){
27164 for(var i = 0, len = o.length; i < len; i++){
27165 var data = this.prepareData(o[i], i, o);
27166 html[html.length] = this.tpl.apply(data);
27169 html.push(this.emptyText);
27171 this.el.update(html.join(""));
27172 this.nodes = this.el.dom.childNodes;
27173 this.updateIndexes(0);
27177 * 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.
27178 * @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:
27181 url: "your-url.php",
27182 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27183 callback: yourFunction,
27184 scope: yourObject, //(optional scope)
27187 text: "Loading...",
27192 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27193 * 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.
27194 * @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}
27195 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27196 * @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.
27199 var um = this.el.getUpdateManager();
27200 um.update.apply(um, arguments);
27203 // note - render is a standard framework call...
27204 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27205 render : function(el, response){
27207 this.clearSelections();
27208 this.el.update("");
27211 if (response != '') {
27212 o = Roo.util.JSON.decode(response.responseText);
27215 o = o[this.jsonRoot];
27221 * The current JSON data or null
27224 this.beforeRender();
27229 * Get the number of records in the current JSON dataset
27232 getCount : function(){
27233 return this.jsonData ? this.jsonData.length : 0;
27237 * Returns the JSON object for the specified node(s)
27238 * @param {HTMLElement/Array} node The node or an array of nodes
27239 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27240 * you get the JSON object for the node
27242 getNodeData : function(node){
27243 if(node instanceof Array){
27245 for(var i = 0, len = node.length; i < len; i++){
27246 data.push(this.getNodeData(node[i]));
27250 return this.jsonData[this.indexOf(node)] || null;
27253 beforeRender : function(){
27254 this.snapshot = this.jsonData;
27256 this.sort.apply(this, this.sortInfo);
27258 this.fireEvent("beforerender", this, this.jsonData);
27261 onLoad : function(el, o){
27262 this.fireEvent("load", this, this.jsonData, o);
27265 onLoadException : function(el, o){
27266 this.fireEvent("loadexception", this, o);
27270 * Filter the data by a specific property.
27271 * @param {String} property A property on your JSON objects
27272 * @param {String/RegExp} value Either string that the property values
27273 * should start with, or a RegExp to test against the property
27275 filter : function(property, value){
27278 var ss = this.snapshot;
27279 if(typeof value == "string"){
27280 var vlen = value.length;
27282 this.clearFilter();
27285 value = value.toLowerCase();
27286 for(var i = 0, len = ss.length; i < len; i++){
27288 if(o[property].substr(0, vlen).toLowerCase() == value){
27292 } else if(value.exec){ // regex?
27293 for(var i = 0, len = ss.length; i < len; i++){
27295 if(value.test(o[property])){
27302 this.jsonData = data;
27308 * Filter by a function. The passed function will be called with each
27309 * object in the current dataset. If the function returns true the value is kept,
27310 * otherwise it is filtered.
27311 * @param {Function} fn
27312 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27314 filterBy : function(fn, scope){
27317 var ss = this.snapshot;
27318 for(var i = 0, len = ss.length; i < len; i++){
27320 if(fn.call(scope || this, o)){
27324 this.jsonData = data;
27330 * Clears the current filter.
27332 clearFilter : function(){
27333 if(this.snapshot && this.jsonData != this.snapshot){
27334 this.jsonData = this.snapshot;
27341 * Sorts the data for this view and refreshes it.
27342 * @param {String} property A property on your JSON objects to sort on
27343 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27344 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27346 sort : function(property, dir, sortType){
27347 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27350 var dsc = dir && dir.toLowerCase() == "desc";
27351 var f = function(o1, o2){
27352 var v1 = sortType ? sortType(o1[p]) : o1[p];
27353 var v2 = sortType ? sortType(o2[p]) : o2[p];
27356 return dsc ? +1 : -1;
27357 } else if(v1 > v2){
27358 return dsc ? -1 : +1;
27363 this.jsonData.sort(f);
27365 if(this.jsonData != this.snapshot){
27366 this.snapshot.sort(f);
27372 * Ext JS Library 1.1.1
27373 * Copyright(c) 2006-2007, Ext JS, LLC.
27375 * Originally Released Under LGPL - original licence link has changed is not relivant.
27378 * <script type="text/javascript">
27383 * @class Roo.ColorPalette
27384 * @extends Roo.Component
27385 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27386 * Here's an example of typical usage:
27388 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27389 cp.render('my-div');
27391 cp.on('select', function(palette, selColor){
27392 // do something with selColor
27396 * Create a new ColorPalette
27397 * @param {Object} config The config object
27399 Roo.ColorPalette = function(config){
27400 Roo.ColorPalette.superclass.constructor.call(this, config);
27404 * Fires when a color is selected
27405 * @param {ColorPalette} this
27406 * @param {String} color The 6-digit color hex code (without the # symbol)
27412 this.on("select", this.handler, this.scope, true);
27415 Roo.extend(Roo.ColorPalette, Roo.Component, {
27417 * @cfg {String} itemCls
27418 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27420 itemCls : "x-color-palette",
27422 * @cfg {String} value
27423 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27424 * the hex codes are case-sensitive.
27427 clickEvent:'click',
27429 ctype: "Roo.ColorPalette",
27432 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27434 allowReselect : false,
27437 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27438 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27439 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27440 * of colors with the width setting until the box is symmetrical.</p>
27441 * <p>You can override individual colors if needed:</p>
27443 var cp = new Roo.ColorPalette();
27444 cp.colors[0] = "FF0000"; // change the first box to red
27447 Or you can provide a custom array of your own for complete control:
27449 var cp = new Roo.ColorPalette();
27450 cp.colors = ["000000", "993300", "333300"];
27455 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27456 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27457 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27458 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27459 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27463 onRender : function(container, position){
27464 var t = new Roo.MasterTemplate(
27465 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27467 var c = this.colors;
27468 for(var i = 0, len = c.length; i < len; i++){
27471 var el = document.createElement("div");
27472 el.className = this.itemCls;
27474 container.dom.insertBefore(el, position);
27475 this.el = Roo.get(el);
27476 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27477 if(this.clickEvent != 'click'){
27478 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27483 afterRender : function(){
27484 Roo.ColorPalette.superclass.afterRender.call(this);
27486 var s = this.value;
27493 handleClick : function(e, t){
27494 e.preventDefault();
27495 if(!this.disabled){
27496 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27497 this.select(c.toUpperCase());
27502 * Selects the specified color in the palette (fires the select event)
27503 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27505 select : function(color){
27506 color = color.replace("#", "");
27507 if(color != this.value || this.allowReselect){
27510 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27512 el.child("a.color-"+color).addClass("x-color-palette-sel");
27513 this.value = color;
27514 this.fireEvent("select", this, color);
27519 * Ext JS Library 1.1.1
27520 * Copyright(c) 2006-2007, Ext JS, LLC.
27522 * Originally Released Under LGPL - original licence link has changed is not relivant.
27525 * <script type="text/javascript">
27529 * @class Roo.DatePicker
27530 * @extends Roo.Component
27531 * Simple date picker class.
27533 * Create a new DatePicker
27534 * @param {Object} config The config object
27536 Roo.DatePicker = function(config){
27537 Roo.DatePicker.superclass.constructor.call(this, config);
27539 this.value = config && config.value ?
27540 config.value.clearTime() : new Date().clearTime();
27545 * Fires when a date is selected
27546 * @param {DatePicker} this
27547 * @param {Date} date The selected date
27551 * @event monthchange
27552 * Fires when the displayed month changes
27553 * @param {DatePicker} this
27554 * @param {Date} date The selected month
27556 'monthchange': true
27560 this.on("select", this.handler, this.scope || this);
27562 // build the disabledDatesRE
27563 if(!this.disabledDatesRE && this.disabledDates){
27564 var dd = this.disabledDates;
27566 for(var i = 0; i < dd.length; i++){
27568 if(i != dd.length-1) {
27572 this.disabledDatesRE = new RegExp(re + ")");
27576 Roo.extend(Roo.DatePicker, Roo.Component, {
27578 * @cfg {String} todayText
27579 * The text to display on the button that selects the current date (defaults to "Today")
27581 todayText : "Today",
27583 * @cfg {String} okText
27584 * The text to display on the ok button
27586 okText : " OK ", //   to give the user extra clicking room
27588 * @cfg {String} cancelText
27589 * The text to display on the cancel button
27591 cancelText : "Cancel",
27593 * @cfg {String} todayTip
27594 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27596 todayTip : "{0} (Spacebar)",
27598 * @cfg {Date} minDate
27599 * Minimum allowable date (JavaScript date object, defaults to null)
27603 * @cfg {Date} maxDate
27604 * Maximum allowable date (JavaScript date object, defaults to null)
27608 * @cfg {String} minText
27609 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27611 minText : "This date is before the minimum date",
27613 * @cfg {String} maxText
27614 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27616 maxText : "This date is after the maximum date",
27618 * @cfg {String} format
27619 * The default date format string which can be overriden for localization support. The format must be
27620 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27624 * @cfg {Array} disabledDays
27625 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27627 disabledDays : null,
27629 * @cfg {String} disabledDaysText
27630 * The tooltip to display when the date falls on a disabled day (defaults to "")
27632 disabledDaysText : "",
27634 * @cfg {RegExp} disabledDatesRE
27635 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27637 disabledDatesRE : null,
27639 * @cfg {String} disabledDatesText
27640 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27642 disabledDatesText : "",
27644 * @cfg {Boolean} constrainToViewport
27645 * True to constrain the date picker to the viewport (defaults to true)
27647 constrainToViewport : true,
27649 * @cfg {Array} monthNames
27650 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27652 monthNames : Date.monthNames,
27654 * @cfg {Array} dayNames
27655 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27657 dayNames : Date.dayNames,
27659 * @cfg {String} nextText
27660 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27662 nextText: 'Next Month (Control+Right)',
27664 * @cfg {String} prevText
27665 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27667 prevText: 'Previous Month (Control+Left)',
27669 * @cfg {String} monthYearText
27670 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27672 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27674 * @cfg {Number} startDay
27675 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27679 * @cfg {Bool} showClear
27680 * Show a clear button (usefull for date form elements that can be blank.)
27686 * Sets the value of the date field
27687 * @param {Date} value The date to set
27689 setValue : function(value){
27690 var old = this.value;
27692 if (typeof(value) == 'string') {
27694 value = Date.parseDate(value, this.format);
27697 value = new Date();
27700 this.value = value.clearTime(true);
27702 this.update(this.value);
27707 * Gets the current selected value of the date field
27708 * @return {Date} The selected date
27710 getValue : function(){
27715 focus : function(){
27717 this.update(this.activeDate);
27722 onRender : function(container, position){
27725 '<table cellspacing="0">',
27726 '<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>',
27727 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27728 var dn = this.dayNames;
27729 for(var i = 0; i < 7; i++){
27730 var d = this.startDay+i;
27734 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27736 m[m.length] = "</tr></thead><tbody><tr>";
27737 for(var i = 0; i < 42; i++) {
27738 if(i % 7 == 0 && i != 0){
27739 m[m.length] = "</tr><tr>";
27741 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27743 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27744 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27746 var el = document.createElement("div");
27747 el.className = "x-date-picker";
27748 el.innerHTML = m.join("");
27750 container.dom.insertBefore(el, position);
27752 this.el = Roo.get(el);
27753 this.eventEl = Roo.get(el.firstChild);
27755 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27756 handler: this.showPrevMonth,
27758 preventDefault:true,
27762 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27763 handler: this.showNextMonth,
27765 preventDefault:true,
27769 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27771 this.monthPicker = this.el.down('div.x-date-mp');
27772 this.monthPicker.enableDisplayMode('block');
27774 var kn = new Roo.KeyNav(this.eventEl, {
27775 "left" : function(e){
27777 this.showPrevMonth() :
27778 this.update(this.activeDate.add("d", -1));
27781 "right" : function(e){
27783 this.showNextMonth() :
27784 this.update(this.activeDate.add("d", 1));
27787 "up" : function(e){
27789 this.showNextYear() :
27790 this.update(this.activeDate.add("d", -7));
27793 "down" : function(e){
27795 this.showPrevYear() :
27796 this.update(this.activeDate.add("d", 7));
27799 "pageUp" : function(e){
27800 this.showNextMonth();
27803 "pageDown" : function(e){
27804 this.showPrevMonth();
27807 "enter" : function(e){
27808 e.stopPropagation();
27815 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27817 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27819 this.el.unselectable();
27821 this.cells = this.el.select("table.x-date-inner tbody td");
27822 this.textNodes = this.el.query("table.x-date-inner tbody span");
27824 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27826 tooltip: this.monthYearText
27829 this.mbtn.on('click', this.showMonthPicker, this);
27830 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27833 var today = (new Date()).dateFormat(this.format);
27835 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27836 if (this.showClear) {
27837 baseTb.add( new Roo.Toolbar.Fill());
27840 text: String.format(this.todayText, today),
27841 tooltip: String.format(this.todayTip, today),
27842 handler: this.selectToday,
27846 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27849 if (this.showClear) {
27851 baseTb.add( new Roo.Toolbar.Fill());
27854 cls: 'x-btn-icon x-btn-clear',
27855 handler: function() {
27857 this.fireEvent("select", this, '');
27867 this.update(this.value);
27870 createMonthPicker : function(){
27871 if(!this.monthPicker.dom.firstChild){
27872 var buf = ['<table border="0" cellspacing="0">'];
27873 for(var i = 0; i < 6; i++){
27875 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27876 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27878 '<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>' :
27879 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27883 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27885 '</button><button type="button" class="x-date-mp-cancel">',
27887 '</button></td></tr>',
27890 this.monthPicker.update(buf.join(''));
27891 this.monthPicker.on('click', this.onMonthClick, this);
27892 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27894 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27895 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27897 this.mpMonths.each(function(m, a, i){
27900 m.dom.xmonth = 5 + Math.round(i * .5);
27902 m.dom.xmonth = Math.round((i-1) * .5);
27908 showMonthPicker : function(){
27909 this.createMonthPicker();
27910 var size = this.el.getSize();
27911 this.monthPicker.setSize(size);
27912 this.monthPicker.child('table').setSize(size);
27914 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27915 this.updateMPMonth(this.mpSelMonth);
27916 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27917 this.updateMPYear(this.mpSelYear);
27919 this.monthPicker.slideIn('t', {duration:.2});
27922 updateMPYear : function(y){
27924 var ys = this.mpYears.elements;
27925 for(var i = 1; i <= 10; i++){
27926 var td = ys[i-1], y2;
27928 y2 = y + Math.round(i * .5);
27929 td.firstChild.innerHTML = y2;
27932 y2 = y - (5-Math.round(i * .5));
27933 td.firstChild.innerHTML = y2;
27936 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27940 updateMPMonth : function(sm){
27941 this.mpMonths.each(function(m, a, i){
27942 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27946 selectMPMonth: function(m){
27950 onMonthClick : function(e, t){
27952 var el = new Roo.Element(t), pn;
27953 if(el.is('button.x-date-mp-cancel')){
27954 this.hideMonthPicker();
27956 else if(el.is('button.x-date-mp-ok')){
27957 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27958 this.hideMonthPicker();
27960 else if(pn = el.up('td.x-date-mp-month', 2)){
27961 this.mpMonths.removeClass('x-date-mp-sel');
27962 pn.addClass('x-date-mp-sel');
27963 this.mpSelMonth = pn.dom.xmonth;
27965 else if(pn = el.up('td.x-date-mp-year', 2)){
27966 this.mpYears.removeClass('x-date-mp-sel');
27967 pn.addClass('x-date-mp-sel');
27968 this.mpSelYear = pn.dom.xyear;
27970 else if(el.is('a.x-date-mp-prev')){
27971 this.updateMPYear(this.mpyear-10);
27973 else if(el.is('a.x-date-mp-next')){
27974 this.updateMPYear(this.mpyear+10);
27978 onMonthDblClick : function(e, t){
27980 var el = new Roo.Element(t), pn;
27981 if(pn = el.up('td.x-date-mp-month', 2)){
27982 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27983 this.hideMonthPicker();
27985 else if(pn = el.up('td.x-date-mp-year', 2)){
27986 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27987 this.hideMonthPicker();
27991 hideMonthPicker : function(disableAnim){
27992 if(this.monthPicker){
27993 if(disableAnim === true){
27994 this.monthPicker.hide();
27996 this.monthPicker.slideOut('t', {duration:.2});
28002 showPrevMonth : function(e){
28003 this.update(this.activeDate.add("mo", -1));
28007 showNextMonth : function(e){
28008 this.update(this.activeDate.add("mo", 1));
28012 showPrevYear : function(){
28013 this.update(this.activeDate.add("y", -1));
28017 showNextYear : function(){
28018 this.update(this.activeDate.add("y", 1));
28022 handleMouseWheel : function(e){
28023 var delta = e.getWheelDelta();
28025 this.showPrevMonth();
28027 } else if(delta < 0){
28028 this.showNextMonth();
28034 handleDateClick : function(e, t){
28036 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28037 this.setValue(new Date(t.dateValue));
28038 this.fireEvent("select", this, this.value);
28043 selectToday : function(){
28044 this.setValue(new Date().clearTime());
28045 this.fireEvent("select", this, this.value);
28049 update : function(date)
28051 var vd = this.activeDate;
28052 this.activeDate = date;
28054 var t = date.getTime();
28055 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28056 this.cells.removeClass("x-date-selected");
28057 this.cells.each(function(c){
28058 if(c.dom.firstChild.dateValue == t){
28059 c.addClass("x-date-selected");
28060 setTimeout(function(){
28061 try{c.dom.firstChild.focus();}catch(e){}
28070 var days = date.getDaysInMonth();
28071 var firstOfMonth = date.getFirstDateOfMonth();
28072 var startingPos = firstOfMonth.getDay()-this.startDay;
28074 if(startingPos <= this.startDay){
28078 var pm = date.add("mo", -1);
28079 var prevStart = pm.getDaysInMonth()-startingPos;
28081 var cells = this.cells.elements;
28082 var textEls = this.textNodes;
28083 days += startingPos;
28085 // convert everything to numbers so it's fast
28086 var day = 86400000;
28087 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28088 var today = new Date().clearTime().getTime();
28089 var sel = date.clearTime().getTime();
28090 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28091 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28092 var ddMatch = this.disabledDatesRE;
28093 var ddText = this.disabledDatesText;
28094 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28095 var ddaysText = this.disabledDaysText;
28096 var format = this.format;
28098 var setCellClass = function(cal, cell){
28100 var t = d.getTime();
28101 cell.firstChild.dateValue = t;
28103 cell.className += " x-date-today";
28104 cell.title = cal.todayText;
28107 cell.className += " x-date-selected";
28108 setTimeout(function(){
28109 try{cell.firstChild.focus();}catch(e){}
28114 cell.className = " x-date-disabled";
28115 cell.title = cal.minText;
28119 cell.className = " x-date-disabled";
28120 cell.title = cal.maxText;
28124 if(ddays.indexOf(d.getDay()) != -1){
28125 cell.title = ddaysText;
28126 cell.className = " x-date-disabled";
28129 if(ddMatch && format){
28130 var fvalue = d.dateFormat(format);
28131 if(ddMatch.test(fvalue)){
28132 cell.title = ddText.replace("%0", fvalue);
28133 cell.className = " x-date-disabled";
28139 for(; i < startingPos; i++) {
28140 textEls[i].innerHTML = (++prevStart);
28141 d.setDate(d.getDate()+1);
28142 cells[i].className = "x-date-prevday";
28143 setCellClass(this, cells[i]);
28145 for(; i < days; i++){
28146 intDay = i - startingPos + 1;
28147 textEls[i].innerHTML = (intDay);
28148 d.setDate(d.getDate()+1);
28149 cells[i].className = "x-date-active";
28150 setCellClass(this, cells[i]);
28153 for(; i < 42; i++) {
28154 textEls[i].innerHTML = (++extraDays);
28155 d.setDate(d.getDate()+1);
28156 cells[i].className = "x-date-nextday";
28157 setCellClass(this, cells[i]);
28160 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28161 this.fireEvent('monthchange', this, date);
28163 if(!this.internalRender){
28164 var main = this.el.dom.firstChild;
28165 var w = main.offsetWidth;
28166 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28167 Roo.fly(main).setWidth(w);
28168 this.internalRender = true;
28169 // opera does not respect the auto grow header center column
28170 // then, after it gets a width opera refuses to recalculate
28171 // without a second pass
28172 if(Roo.isOpera && !this.secondPass){
28173 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28174 this.secondPass = true;
28175 this.update.defer(10, this, [date]);
28183 * Ext JS Library 1.1.1
28184 * Copyright(c) 2006-2007, Ext JS, LLC.
28186 * Originally Released Under LGPL - original licence link has changed is not relivant.
28189 * <script type="text/javascript">
28192 * @class Roo.TabPanel
28193 * @extends Roo.util.Observable
28194 * A lightweight tab container.
28198 // basic tabs 1, built from existing content
28199 var tabs = new Roo.TabPanel("tabs1");
28200 tabs.addTab("script", "View Script");
28201 tabs.addTab("markup", "View Markup");
28202 tabs.activate("script");
28204 // more advanced tabs, built from javascript
28205 var jtabs = new Roo.TabPanel("jtabs");
28206 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28208 // set up the UpdateManager
28209 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28210 var updater = tab2.getUpdateManager();
28211 updater.setDefaultUrl("ajax1.htm");
28212 tab2.on('activate', updater.refresh, updater, true);
28214 // Use setUrl for Ajax loading
28215 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28216 tab3.setUrl("ajax2.htm", null, true);
28219 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28222 jtabs.activate("jtabs-1");
28225 * Create a new TabPanel.
28226 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28227 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28229 Roo.TabPanel = function(container, config){
28231 * The container element for this TabPanel.
28232 * @type Roo.Element
28234 this.el = Roo.get(container, true);
28236 if(typeof config == "boolean"){
28237 this.tabPosition = config ? "bottom" : "top";
28239 Roo.apply(this, config);
28242 if(this.tabPosition == "bottom"){
28243 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28244 this.el.addClass("x-tabs-bottom");
28246 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28247 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28248 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28250 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28252 if(this.tabPosition != "bottom"){
28253 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28254 * @type Roo.Element
28256 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28257 this.el.addClass("x-tabs-top");
28261 this.bodyEl.setStyle("position", "relative");
28263 this.active = null;
28264 this.activateDelegate = this.activate.createDelegate(this);
28269 * Fires when the active tab changes
28270 * @param {Roo.TabPanel} this
28271 * @param {Roo.TabPanelItem} activePanel The new active tab
28275 * @event beforetabchange
28276 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28277 * @param {Roo.TabPanel} this
28278 * @param {Object} e Set cancel to true on this object to cancel the tab change
28279 * @param {Roo.TabPanelItem} tab The tab being changed to
28281 "beforetabchange" : true
28284 Roo.EventManager.onWindowResize(this.onResize, this);
28285 this.cpad = this.el.getPadding("lr");
28286 this.hiddenCount = 0;
28289 // toolbar on the tabbar support...
28290 if (this.toolbar) {
28291 var tcfg = this.toolbar;
28292 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28293 this.toolbar = new Roo.Toolbar(tcfg);
28294 if (Roo.isSafari) {
28295 var tbl = tcfg.container.child('table', true);
28296 tbl.setAttribute('width', '100%');
28303 Roo.TabPanel.superclass.constructor.call(this);
28306 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28308 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28310 tabPosition : "top",
28312 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28314 currentTabWidth : 0,
28316 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28320 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28324 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28326 preferredTabWidth : 175,
28328 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28330 resizeTabs : false,
28332 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28334 monitorResize : true,
28336 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28341 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28342 * @param {String} id The id of the div to use <b>or create</b>
28343 * @param {String} text The text for the tab
28344 * @param {String} content (optional) Content to put in the TabPanelItem body
28345 * @param {Boolean} closable (optional) True to create a close icon on the tab
28346 * @return {Roo.TabPanelItem} The created TabPanelItem
28348 addTab : function(id, text, content, closable){
28349 var item = new Roo.TabPanelItem(this, id, text, closable);
28350 this.addTabItem(item);
28352 item.setContent(content);
28358 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28359 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28360 * @return {Roo.TabPanelItem}
28362 getTab : function(id){
28363 return this.items[id];
28367 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28368 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28370 hideTab : function(id){
28371 var t = this.items[id];
28374 this.hiddenCount++;
28375 this.autoSizeTabs();
28380 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28381 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28383 unhideTab : function(id){
28384 var t = this.items[id];
28386 t.setHidden(false);
28387 this.hiddenCount--;
28388 this.autoSizeTabs();
28393 * Adds an existing {@link Roo.TabPanelItem}.
28394 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28396 addTabItem : function(item){
28397 this.items[item.id] = item;
28398 this.items.push(item);
28399 if(this.resizeTabs){
28400 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28401 this.autoSizeTabs();
28408 * Removes a {@link Roo.TabPanelItem}.
28409 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28411 removeTab : function(id){
28412 var items = this.items;
28413 var tab = items[id];
28414 if(!tab) { return; }
28415 var index = items.indexOf(tab);
28416 if(this.active == tab && items.length > 1){
28417 var newTab = this.getNextAvailable(index);
28422 this.stripEl.dom.removeChild(tab.pnode.dom);
28423 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28424 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28426 items.splice(index, 1);
28427 delete this.items[tab.id];
28428 tab.fireEvent("close", tab);
28429 tab.purgeListeners();
28430 this.autoSizeTabs();
28433 getNextAvailable : function(start){
28434 var items = this.items;
28436 // look for a next tab that will slide over to
28437 // replace the one being removed
28438 while(index < items.length){
28439 var item = items[++index];
28440 if(item && !item.isHidden()){
28444 // if one isn't found select the previous tab (on the left)
28447 var item = items[--index];
28448 if(item && !item.isHidden()){
28456 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28457 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28459 disableTab : function(id){
28460 var tab = this.items[id];
28461 if(tab && this.active != tab){
28467 * Enables a {@link Roo.TabPanelItem} that is disabled.
28468 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28470 enableTab : function(id){
28471 var tab = this.items[id];
28476 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28477 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28478 * @return {Roo.TabPanelItem} The TabPanelItem.
28480 activate : function(id){
28481 var tab = this.items[id];
28485 if(tab == this.active || tab.disabled){
28489 this.fireEvent("beforetabchange", this, e, tab);
28490 if(e.cancel !== true && !tab.disabled){
28492 this.active.hide();
28494 this.active = this.items[id];
28495 this.active.show();
28496 this.fireEvent("tabchange", this, this.active);
28502 * Gets the active {@link Roo.TabPanelItem}.
28503 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28505 getActiveTab : function(){
28506 return this.active;
28510 * Updates the tab body element to fit the height of the container element
28511 * for overflow scrolling
28512 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28514 syncHeight : function(targetHeight){
28515 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28516 var bm = this.bodyEl.getMargins();
28517 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28518 this.bodyEl.setHeight(newHeight);
28522 onResize : function(){
28523 if(this.monitorResize){
28524 this.autoSizeTabs();
28529 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28531 beginUpdate : function(){
28532 this.updating = true;
28536 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28538 endUpdate : function(){
28539 this.updating = false;
28540 this.autoSizeTabs();
28544 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28546 autoSizeTabs : function(){
28547 var count = this.items.length;
28548 var vcount = count - this.hiddenCount;
28549 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28552 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28553 var availWidth = Math.floor(w / vcount);
28554 var b = this.stripBody;
28555 if(b.getWidth() > w){
28556 var tabs = this.items;
28557 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28558 if(availWidth < this.minTabWidth){
28559 /*if(!this.sleft){ // incomplete scrolling code
28560 this.createScrollButtons();
28563 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28566 if(this.currentTabWidth < this.preferredTabWidth){
28567 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28573 * Returns the number of tabs in this TabPanel.
28576 getCount : function(){
28577 return this.items.length;
28581 * Resizes all the tabs to the passed width
28582 * @param {Number} The new width
28584 setTabWidth : function(width){
28585 this.currentTabWidth = width;
28586 for(var i = 0, len = this.items.length; i < len; i++) {
28587 if(!this.items[i].isHidden()) {
28588 this.items[i].setWidth(width);
28594 * Destroys this TabPanel
28595 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28597 destroy : function(removeEl){
28598 Roo.EventManager.removeResizeListener(this.onResize, this);
28599 for(var i = 0, len = this.items.length; i < len; i++){
28600 this.items[i].purgeListeners();
28602 if(removeEl === true){
28603 this.el.update("");
28610 * @class Roo.TabPanelItem
28611 * @extends Roo.util.Observable
28612 * Represents an individual item (tab plus body) in a TabPanel.
28613 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28614 * @param {String} id The id of this TabPanelItem
28615 * @param {String} text The text for the tab of this TabPanelItem
28616 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28618 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28620 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28621 * @type Roo.TabPanel
28623 this.tabPanel = tabPanel;
28625 * The id for this TabPanelItem
28630 this.disabled = false;
28634 this.loaded = false;
28635 this.closable = closable;
28638 * The body element for this TabPanelItem.
28639 * @type Roo.Element
28641 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28642 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28643 this.bodyEl.setStyle("display", "block");
28644 this.bodyEl.setStyle("zoom", "1");
28647 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28649 this.el = Roo.get(els.el, true);
28650 this.inner = Roo.get(els.inner, true);
28651 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28652 this.pnode = Roo.get(els.el.parentNode, true);
28653 this.el.on("mousedown", this.onTabMouseDown, this);
28654 this.el.on("click", this.onTabClick, this);
28657 var c = Roo.get(els.close, true);
28658 c.dom.title = this.closeText;
28659 c.addClassOnOver("close-over");
28660 c.on("click", this.closeClick, this);
28666 * Fires when this tab becomes the active tab.
28667 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28668 * @param {Roo.TabPanelItem} this
28672 * @event beforeclose
28673 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28674 * @param {Roo.TabPanelItem} this
28675 * @param {Object} e Set cancel to true on this object to cancel the close.
28677 "beforeclose": true,
28680 * Fires when this tab is closed.
28681 * @param {Roo.TabPanelItem} this
28685 * @event deactivate
28686 * Fires when this tab is no longer the active tab.
28687 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28688 * @param {Roo.TabPanelItem} this
28690 "deactivate" : true
28692 this.hidden = false;
28694 Roo.TabPanelItem.superclass.constructor.call(this);
28697 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28698 purgeListeners : function(){
28699 Roo.util.Observable.prototype.purgeListeners.call(this);
28700 this.el.removeAllListeners();
28703 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28706 this.pnode.addClass("on");
28709 this.tabPanel.stripWrap.repaint();
28711 this.fireEvent("activate", this.tabPanel, this);
28715 * Returns true if this tab is the active tab.
28716 * @return {Boolean}
28718 isActive : function(){
28719 return this.tabPanel.getActiveTab() == this;
28723 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28726 this.pnode.removeClass("on");
28728 this.fireEvent("deactivate", this.tabPanel, this);
28731 hideAction : function(){
28732 this.bodyEl.hide();
28733 this.bodyEl.setStyle("position", "absolute");
28734 this.bodyEl.setLeft("-20000px");
28735 this.bodyEl.setTop("-20000px");
28738 showAction : function(){
28739 this.bodyEl.setStyle("position", "relative");
28740 this.bodyEl.setTop("");
28741 this.bodyEl.setLeft("");
28742 this.bodyEl.show();
28746 * Set the tooltip for the tab.
28747 * @param {String} tooltip The tab's tooltip
28749 setTooltip : function(text){
28750 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28751 this.textEl.dom.qtip = text;
28752 this.textEl.dom.removeAttribute('title');
28754 this.textEl.dom.title = text;
28758 onTabClick : function(e){
28759 e.preventDefault();
28760 this.tabPanel.activate(this.id);
28763 onTabMouseDown : function(e){
28764 e.preventDefault();
28765 this.tabPanel.activate(this.id);
28768 getWidth : function(){
28769 return this.inner.getWidth();
28772 setWidth : function(width){
28773 var iwidth = width - this.pnode.getPadding("lr");
28774 this.inner.setWidth(iwidth);
28775 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28776 this.pnode.setWidth(width);
28780 * Show or hide the tab
28781 * @param {Boolean} hidden True to hide or false to show.
28783 setHidden : function(hidden){
28784 this.hidden = hidden;
28785 this.pnode.setStyle("display", hidden ? "none" : "");
28789 * Returns true if this tab is "hidden"
28790 * @return {Boolean}
28792 isHidden : function(){
28793 return this.hidden;
28797 * Returns the text for this tab
28800 getText : function(){
28804 autoSize : function(){
28805 //this.el.beginMeasure();
28806 this.textEl.setWidth(1);
28808 * #2804 [new] Tabs in Roojs
28809 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28811 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28812 //this.el.endMeasure();
28816 * Sets the text for the tab (Note: this also sets the tooltip text)
28817 * @param {String} text The tab's text and tooltip
28819 setText : function(text){
28821 this.textEl.update(text);
28822 this.setTooltip(text);
28823 if(!this.tabPanel.resizeTabs){
28828 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28830 activate : function(){
28831 this.tabPanel.activate(this.id);
28835 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28837 disable : function(){
28838 if(this.tabPanel.active != this){
28839 this.disabled = true;
28840 this.pnode.addClass("disabled");
28845 * Enables this TabPanelItem if it was previously disabled.
28847 enable : function(){
28848 this.disabled = false;
28849 this.pnode.removeClass("disabled");
28853 * Sets the content for this TabPanelItem.
28854 * @param {String} content The content
28855 * @param {Boolean} loadScripts true to look for and load scripts
28857 setContent : function(content, loadScripts){
28858 this.bodyEl.update(content, loadScripts);
28862 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28863 * @return {Roo.UpdateManager} The UpdateManager
28865 getUpdateManager : function(){
28866 return this.bodyEl.getUpdateManager();
28870 * Set a URL to be used to load the content for this TabPanelItem.
28871 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28872 * @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)
28873 * @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)
28874 * @return {Roo.UpdateManager} The UpdateManager
28876 setUrl : function(url, params, loadOnce){
28877 if(this.refreshDelegate){
28878 this.un('activate', this.refreshDelegate);
28880 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28881 this.on("activate", this.refreshDelegate);
28882 return this.bodyEl.getUpdateManager();
28886 _handleRefresh : function(url, params, loadOnce){
28887 if(!loadOnce || !this.loaded){
28888 var updater = this.bodyEl.getUpdateManager();
28889 updater.update(url, params, this._setLoaded.createDelegate(this));
28894 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28895 * Will fail silently if the setUrl method has not been called.
28896 * This does not activate the panel, just updates its content.
28898 refresh : function(){
28899 if(this.refreshDelegate){
28900 this.loaded = false;
28901 this.refreshDelegate();
28906 _setLoaded : function(){
28907 this.loaded = true;
28911 closeClick : function(e){
28914 this.fireEvent("beforeclose", this, o);
28915 if(o.cancel !== true){
28916 this.tabPanel.removeTab(this.id);
28920 * The text displayed in the tooltip for the close icon.
28923 closeText : "Close this tab"
28927 Roo.TabPanel.prototype.createStrip = function(container){
28928 var strip = document.createElement("div");
28929 strip.className = "x-tabs-wrap";
28930 container.appendChild(strip);
28934 Roo.TabPanel.prototype.createStripList = function(strip){
28935 // div wrapper for retard IE
28936 // returns the "tr" element.
28937 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28938 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28939 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28940 return strip.firstChild.firstChild.firstChild.firstChild;
28943 Roo.TabPanel.prototype.createBody = function(container){
28944 var body = document.createElement("div");
28945 Roo.id(body, "tab-body");
28946 Roo.fly(body).addClass("x-tabs-body");
28947 container.appendChild(body);
28951 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28952 var body = Roo.getDom(id);
28954 body = document.createElement("div");
28957 Roo.fly(body).addClass("x-tabs-item-body");
28958 bodyEl.insertBefore(body, bodyEl.firstChild);
28962 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28963 var td = document.createElement("td");
28964 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28965 //stripEl.appendChild(td);
28967 td.className = "x-tabs-closable";
28968 if(!this.closeTpl){
28969 this.closeTpl = new Roo.Template(
28970 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28971 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28972 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28975 var el = this.closeTpl.overwrite(td, {"text": text});
28976 var close = el.getElementsByTagName("div")[0];
28977 var inner = el.getElementsByTagName("em")[0];
28978 return {"el": el, "close": close, "inner": inner};
28981 this.tabTpl = new Roo.Template(
28982 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28983 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28986 var el = this.tabTpl.overwrite(td, {"text": text});
28987 var inner = el.getElementsByTagName("em")[0];
28988 return {"el": el, "inner": inner};
28992 * Ext JS Library 1.1.1
28993 * Copyright(c) 2006-2007, Ext JS, LLC.
28995 * Originally Released Under LGPL - original licence link has changed is not relivant.
28998 * <script type="text/javascript">
29002 * @class Roo.Button
29003 * @extends Roo.util.Observable
29004 * Simple Button class
29005 * @cfg {String} text The button text
29006 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29007 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29008 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29009 * @cfg {Object} scope The scope of the handler
29010 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29011 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29012 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29013 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29014 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29015 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29016 applies if enableToggle = true)
29017 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29018 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29019 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29021 * Create a new button
29022 * @param {Object} config The config object
29024 Roo.Button = function(renderTo, config)
29028 renderTo = config.renderTo || false;
29031 Roo.apply(this, config);
29035 * Fires when this button is clicked
29036 * @param {Button} this
29037 * @param {EventObject} e The click event
29042 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29043 * @param {Button} this
29044 * @param {Boolean} pressed
29049 * Fires when the mouse hovers over the button
29050 * @param {Button} this
29051 * @param {Event} e The event object
29053 'mouseover' : true,
29056 * Fires when the mouse exits the button
29057 * @param {Button} this
29058 * @param {Event} e The event object
29063 * Fires when the button is rendered
29064 * @param {Button} this
29069 this.menu = Roo.menu.MenuMgr.get(this.menu);
29071 // register listeners first!! - so render can be captured..
29072 Roo.util.Observable.call(this);
29074 this.render(renderTo);
29080 Roo.extend(Roo.Button, Roo.util.Observable, {
29086 * Read-only. True if this button is hidden
29091 * Read-only. True if this button is disabled
29096 * Read-only. True if this button is pressed (only if enableToggle = true)
29102 * @cfg {Number} tabIndex
29103 * The DOM tabIndex for this button (defaults to undefined)
29105 tabIndex : undefined,
29108 * @cfg {Boolean} enableToggle
29109 * True to enable pressed/not pressed toggling (defaults to false)
29111 enableToggle: false,
29113 * @cfg {Mixed} menu
29114 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29118 * @cfg {String} menuAlign
29119 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29121 menuAlign : "tl-bl?",
29124 * @cfg {String} iconCls
29125 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29127 iconCls : undefined,
29129 * @cfg {String} type
29130 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29135 menuClassTarget: 'tr',
29138 * @cfg {String} clickEvent
29139 * The type of event to map to the button's event handler (defaults to 'click')
29141 clickEvent : 'click',
29144 * @cfg {Boolean} handleMouseEvents
29145 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29147 handleMouseEvents : true,
29150 * @cfg {String} tooltipType
29151 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29153 tooltipType : 'qtip',
29156 * @cfg {String} cls
29157 * A CSS class to apply to the button's main element.
29161 * @cfg {Roo.Template} template (Optional)
29162 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29163 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29164 * require code modifications if required elements (e.g. a button) aren't present.
29168 render : function(renderTo){
29170 if(this.hideParent){
29171 this.parentEl = Roo.get(renderTo);
29173 if(!this.dhconfig){
29174 if(!this.template){
29175 if(!Roo.Button.buttonTemplate){
29176 // hideous table template
29177 Roo.Button.buttonTemplate = new Roo.Template(
29178 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29179 '<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>',
29180 "</tr></tbody></table>");
29182 this.template = Roo.Button.buttonTemplate;
29184 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29185 var btnEl = btn.child("button:first");
29186 btnEl.on('focus', this.onFocus, this);
29187 btnEl.on('blur', this.onBlur, this);
29189 btn.addClass(this.cls);
29192 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29195 btnEl.addClass(this.iconCls);
29197 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29200 if(this.tabIndex !== undefined){
29201 btnEl.dom.tabIndex = this.tabIndex;
29204 if(typeof this.tooltip == 'object'){
29205 Roo.QuickTips.tips(Roo.apply({
29209 btnEl.dom[this.tooltipType] = this.tooltip;
29213 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29217 this.el.dom.id = this.el.id = this.id;
29220 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29221 this.menu.on("show", this.onMenuShow, this);
29222 this.menu.on("hide", this.onMenuHide, this);
29224 btn.addClass("x-btn");
29225 if(Roo.isIE && !Roo.isIE7){
29226 this.autoWidth.defer(1, this);
29230 if(this.handleMouseEvents){
29231 btn.on("mouseover", this.onMouseOver, this);
29232 btn.on("mouseout", this.onMouseOut, this);
29233 btn.on("mousedown", this.onMouseDown, this);
29235 btn.on(this.clickEvent, this.onClick, this);
29236 //btn.on("mouseup", this.onMouseUp, this);
29243 Roo.ButtonToggleMgr.register(this);
29245 this.el.addClass("x-btn-pressed");
29248 var repeater = new Roo.util.ClickRepeater(btn,
29249 typeof this.repeat == "object" ? this.repeat : {}
29251 repeater.on("click", this.onClick, this);
29254 this.fireEvent('render', this);
29258 * Returns the button's underlying element
29259 * @return {Roo.Element} The element
29261 getEl : function(){
29266 * Destroys this Button and removes any listeners.
29268 destroy : function(){
29269 Roo.ButtonToggleMgr.unregister(this);
29270 this.el.removeAllListeners();
29271 this.purgeListeners();
29276 autoWidth : function(){
29278 this.el.setWidth("auto");
29279 if(Roo.isIE7 && Roo.isStrict){
29280 var ib = this.el.child('button');
29281 if(ib && ib.getWidth() > 20){
29283 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29288 this.el.beginMeasure();
29290 if(this.el.getWidth() < this.minWidth){
29291 this.el.setWidth(this.minWidth);
29294 this.el.endMeasure();
29301 * Assigns this button's click handler
29302 * @param {Function} handler The function to call when the button is clicked
29303 * @param {Object} scope (optional) Scope for the function passed in
29305 setHandler : function(handler, scope){
29306 this.handler = handler;
29307 this.scope = scope;
29311 * Sets this button's text
29312 * @param {String} text The button text
29314 setText : function(text){
29317 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29323 * Gets the text for this button
29324 * @return {String} The button text
29326 getText : function(){
29334 this.hidden = false;
29336 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29344 this.hidden = true;
29346 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29351 * Convenience function for boolean show/hide
29352 * @param {Boolean} visible True to show, false to hide
29354 setVisible: function(visible){
29363 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29364 * @param {Boolean} state (optional) Force a particular state
29366 toggle : function(state){
29367 state = state === undefined ? !this.pressed : state;
29368 if(state != this.pressed){
29370 this.el.addClass("x-btn-pressed");
29371 this.pressed = true;
29372 this.fireEvent("toggle", this, true);
29374 this.el.removeClass("x-btn-pressed");
29375 this.pressed = false;
29376 this.fireEvent("toggle", this, false);
29378 if(this.toggleHandler){
29379 this.toggleHandler.call(this.scope || this, this, state);
29387 focus : function(){
29388 this.el.child('button:first').focus();
29392 * Disable this button
29394 disable : function(){
29396 this.el.addClass("x-btn-disabled");
29398 this.disabled = true;
29402 * Enable this button
29404 enable : function(){
29406 this.el.removeClass("x-btn-disabled");
29408 this.disabled = false;
29412 * Convenience function for boolean enable/disable
29413 * @param {Boolean} enabled True to enable, false to disable
29415 setDisabled : function(v){
29416 this[v !== true ? "enable" : "disable"]();
29420 onClick : function(e)
29423 e.preventDefault();
29428 if(!this.disabled){
29429 if(this.enableToggle){
29432 if(this.menu && !this.menu.isVisible()){
29433 this.menu.show(this.el, this.menuAlign);
29435 this.fireEvent("click", this, e);
29437 this.el.removeClass("x-btn-over");
29438 this.handler.call(this.scope || this, this, e);
29443 onMouseOver : function(e){
29444 if(!this.disabled){
29445 this.el.addClass("x-btn-over");
29446 this.fireEvent('mouseover', this, e);
29450 onMouseOut : function(e){
29451 if(!e.within(this.el, true)){
29452 this.el.removeClass("x-btn-over");
29453 this.fireEvent('mouseout', this, e);
29457 onFocus : function(e){
29458 if(!this.disabled){
29459 this.el.addClass("x-btn-focus");
29463 onBlur : function(e){
29464 this.el.removeClass("x-btn-focus");
29467 onMouseDown : function(e){
29468 if(!this.disabled && e.button == 0){
29469 this.el.addClass("x-btn-click");
29470 Roo.get(document).on('mouseup', this.onMouseUp, this);
29474 onMouseUp : function(e){
29476 this.el.removeClass("x-btn-click");
29477 Roo.get(document).un('mouseup', this.onMouseUp, this);
29481 onMenuShow : function(e){
29482 this.el.addClass("x-btn-menu-active");
29485 onMenuHide : function(e){
29486 this.el.removeClass("x-btn-menu-active");
29490 // Private utility class used by Button
29491 Roo.ButtonToggleMgr = function(){
29494 function toggleGroup(btn, state){
29496 var g = groups[btn.toggleGroup];
29497 for(var i = 0, l = g.length; i < l; i++){
29499 g[i].toggle(false);
29506 register : function(btn){
29507 if(!btn.toggleGroup){
29510 var g = groups[btn.toggleGroup];
29512 g = groups[btn.toggleGroup] = [];
29515 btn.on("toggle", toggleGroup);
29518 unregister : function(btn){
29519 if(!btn.toggleGroup){
29522 var g = groups[btn.toggleGroup];
29525 btn.un("toggle", toggleGroup);
29531 * Ext JS Library 1.1.1
29532 * Copyright(c) 2006-2007, Ext JS, LLC.
29534 * Originally Released Under LGPL - original licence link has changed is not relivant.
29537 * <script type="text/javascript">
29541 * @class Roo.SplitButton
29542 * @extends Roo.Button
29543 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29544 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29545 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29546 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29547 * @cfg {String} arrowTooltip The title attribute of the arrow
29549 * Create a new menu button
29550 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29551 * @param {Object} config The config object
29553 Roo.SplitButton = function(renderTo, config){
29554 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29556 * @event arrowclick
29557 * Fires when this button's arrow is clicked
29558 * @param {SplitButton} this
29559 * @param {EventObject} e The click event
29561 this.addEvents({"arrowclick":true});
29564 Roo.extend(Roo.SplitButton, Roo.Button, {
29565 render : function(renderTo){
29566 // this is one sweet looking template!
29567 var tpl = new Roo.Template(
29568 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29569 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29570 '<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>',
29571 "</tbody></table></td><td>",
29572 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29573 '<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>',
29574 "</tbody></table></td></tr></table>"
29576 var btn = tpl.append(renderTo, [this.text, this.type], true);
29577 var btnEl = btn.child("button");
29579 btn.addClass(this.cls);
29582 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29585 btnEl.addClass(this.iconCls);
29587 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29591 if(this.handleMouseEvents){
29592 btn.on("mouseover", this.onMouseOver, this);
29593 btn.on("mouseout", this.onMouseOut, this);
29594 btn.on("mousedown", this.onMouseDown, this);
29595 btn.on("mouseup", this.onMouseUp, this);
29597 btn.on(this.clickEvent, this.onClick, this);
29599 if(typeof this.tooltip == 'object'){
29600 Roo.QuickTips.tips(Roo.apply({
29604 btnEl.dom[this.tooltipType] = this.tooltip;
29607 if(this.arrowTooltip){
29608 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29617 this.el.addClass("x-btn-pressed");
29619 if(Roo.isIE && !Roo.isIE7){
29620 this.autoWidth.defer(1, this);
29625 this.menu.on("show", this.onMenuShow, this);
29626 this.menu.on("hide", this.onMenuHide, this);
29628 this.fireEvent('render', this);
29632 autoWidth : function(){
29634 var tbl = this.el.child("table:first");
29635 var tbl2 = this.el.child("table:last");
29636 this.el.setWidth("auto");
29637 tbl.setWidth("auto");
29638 if(Roo.isIE7 && Roo.isStrict){
29639 var ib = this.el.child('button:first');
29640 if(ib && ib.getWidth() > 20){
29642 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29647 this.el.beginMeasure();
29649 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29650 tbl.setWidth(this.minWidth-tbl2.getWidth());
29653 this.el.endMeasure();
29656 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29660 * Sets this button's click handler
29661 * @param {Function} handler The function to call when the button is clicked
29662 * @param {Object} scope (optional) Scope for the function passed above
29664 setHandler : function(handler, scope){
29665 this.handler = handler;
29666 this.scope = scope;
29670 * Sets this button's arrow click handler
29671 * @param {Function} handler The function to call when the arrow is clicked
29672 * @param {Object} scope (optional) Scope for the function passed above
29674 setArrowHandler : function(handler, scope){
29675 this.arrowHandler = handler;
29676 this.scope = scope;
29682 focus : function(){
29684 this.el.child("button:first").focus();
29689 onClick : function(e){
29690 e.preventDefault();
29691 if(!this.disabled){
29692 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29693 if(this.menu && !this.menu.isVisible()){
29694 this.menu.show(this.el, this.menuAlign);
29696 this.fireEvent("arrowclick", this, e);
29697 if(this.arrowHandler){
29698 this.arrowHandler.call(this.scope || this, this, e);
29701 this.fireEvent("click", this, e);
29703 this.handler.call(this.scope || this, this, e);
29709 onMouseDown : function(e){
29710 if(!this.disabled){
29711 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29715 onMouseUp : function(e){
29716 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29721 // backwards compat
29722 Roo.MenuButton = Roo.SplitButton;/*
29724 * Ext JS Library 1.1.1
29725 * Copyright(c) 2006-2007, Ext JS, LLC.
29727 * Originally Released Under LGPL - original licence link has changed is not relivant.
29730 * <script type="text/javascript">
29734 * @class Roo.Toolbar
29735 * Basic Toolbar class.
29737 * Creates a new Toolbar
29738 * @param {Object} container The config object
29740 Roo.Toolbar = function(container, buttons, config)
29742 /// old consturctor format still supported..
29743 if(container instanceof Array){ // omit the container for later rendering
29744 buttons = container;
29748 if (typeof(container) == 'object' && container.xtype) {
29749 config = container;
29750 container = config.container;
29751 buttons = config.buttons || []; // not really - use items!!
29754 if (config && config.items) {
29755 xitems = config.items;
29756 delete config.items;
29758 Roo.apply(this, config);
29759 this.buttons = buttons;
29762 this.render(container);
29764 this.xitems = xitems;
29765 Roo.each(xitems, function(b) {
29771 Roo.Toolbar.prototype = {
29773 * @cfg {Array} items
29774 * array of button configs or elements to add (will be converted to a MixedCollection)
29778 * @cfg {String/HTMLElement/Element} container
29779 * The id or element that will contain the toolbar
29782 render : function(ct){
29783 this.el = Roo.get(ct);
29785 this.el.addClass(this.cls);
29787 // using a table allows for vertical alignment
29788 // 100% width is needed by Safari...
29789 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29790 this.tr = this.el.child("tr", true);
29792 this.items = new Roo.util.MixedCollection(false, function(o){
29793 return o.id || ("item" + (++autoId));
29796 this.add.apply(this, this.buttons);
29797 delete this.buttons;
29802 * Adds element(s) to the toolbar -- this function takes a variable number of
29803 * arguments of mixed type and adds them to the toolbar.
29804 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29806 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29807 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29808 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29809 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29810 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29811 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29812 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29813 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29814 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29816 * @param {Mixed} arg2
29817 * @param {Mixed} etc.
29820 var a = arguments, l = a.length;
29821 for(var i = 0; i < l; i++){
29826 _add : function(el) {
29829 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29832 if (el.applyTo){ // some kind of form field
29833 return this.addField(el);
29835 if (el.render){ // some kind of Toolbar.Item
29836 return this.addItem(el);
29838 if (typeof el == "string"){ // string
29839 if(el == "separator" || el == "-"){
29840 return this.addSeparator();
29843 return this.addSpacer();
29846 return this.addFill();
29848 return this.addText(el);
29851 if(el.tagName){ // element
29852 return this.addElement(el);
29854 if(typeof el == "object"){ // must be button config?
29855 return this.addButton(el);
29857 // and now what?!?!
29863 * Add an Xtype element
29864 * @param {Object} xtype Xtype Object
29865 * @return {Object} created Object
29867 addxtype : function(e){
29868 return this.add(e);
29872 * Returns the Element for this toolbar.
29873 * @return {Roo.Element}
29875 getEl : function(){
29881 * @return {Roo.Toolbar.Item} The separator item
29883 addSeparator : function(){
29884 return this.addItem(new Roo.Toolbar.Separator());
29888 * Adds a spacer element
29889 * @return {Roo.Toolbar.Spacer} The spacer item
29891 addSpacer : function(){
29892 return this.addItem(new Roo.Toolbar.Spacer());
29896 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29897 * @return {Roo.Toolbar.Fill} The fill item
29899 addFill : function(){
29900 return this.addItem(new Roo.Toolbar.Fill());
29904 * Adds any standard HTML element to the toolbar
29905 * @param {String/HTMLElement/Element} el The element or id of the element to add
29906 * @return {Roo.Toolbar.Item} The element's item
29908 addElement : function(el){
29909 return this.addItem(new Roo.Toolbar.Item(el));
29912 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29913 * @type Roo.util.MixedCollection
29918 * Adds any Toolbar.Item or subclass
29919 * @param {Roo.Toolbar.Item} item
29920 * @return {Roo.Toolbar.Item} The item
29922 addItem : function(item){
29923 var td = this.nextBlock();
29925 this.items.add(item);
29930 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29931 * @param {Object/Array} config A button config or array of configs
29932 * @return {Roo.Toolbar.Button/Array}
29934 addButton : function(config){
29935 if(config instanceof Array){
29937 for(var i = 0, len = config.length; i < len; i++) {
29938 buttons.push(this.addButton(config[i]));
29943 if(!(config instanceof Roo.Toolbar.Button)){
29945 new Roo.Toolbar.SplitButton(config) :
29946 new Roo.Toolbar.Button(config);
29948 var td = this.nextBlock();
29955 * Adds text to the toolbar
29956 * @param {String} text The text to add
29957 * @return {Roo.Toolbar.Item} The element's item
29959 addText : function(text){
29960 return this.addItem(new Roo.Toolbar.TextItem(text));
29964 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29965 * @param {Number} index The index where the item is to be inserted
29966 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29967 * @return {Roo.Toolbar.Button/Item}
29969 insertButton : function(index, item){
29970 if(item instanceof Array){
29972 for(var i = 0, len = item.length; i < len; i++) {
29973 buttons.push(this.insertButton(index + i, item[i]));
29977 if (!(item instanceof Roo.Toolbar.Button)){
29978 item = new Roo.Toolbar.Button(item);
29980 var td = document.createElement("td");
29981 this.tr.insertBefore(td, this.tr.childNodes[index]);
29983 this.items.insert(index, item);
29988 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29989 * @param {Object} config
29990 * @return {Roo.Toolbar.Item} The element's item
29992 addDom : function(config, returnEl){
29993 var td = this.nextBlock();
29994 Roo.DomHelper.overwrite(td, config);
29995 var ti = new Roo.Toolbar.Item(td.firstChild);
29997 this.items.add(ti);
30002 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30003 * @type Roo.util.MixedCollection
30008 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30009 * Note: the field should not have been rendered yet. For a field that has already been
30010 * rendered, use {@link #addElement}.
30011 * @param {Roo.form.Field} field
30012 * @return {Roo.ToolbarItem}
30016 addField : function(field) {
30017 if (!this.fields) {
30019 this.fields = new Roo.util.MixedCollection(false, function(o){
30020 return o.id || ("item" + (++autoId));
30025 var td = this.nextBlock();
30027 var ti = new Roo.Toolbar.Item(td.firstChild);
30029 this.items.add(ti);
30030 this.fields.add(field);
30041 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30042 this.el.child('div').hide();
30050 this.el.child('div').show();
30054 nextBlock : function(){
30055 var td = document.createElement("td");
30056 this.tr.appendChild(td);
30061 destroy : function(){
30062 if(this.items){ // rendered?
30063 Roo.destroy.apply(Roo, this.items.items);
30065 if(this.fields){ // rendered?
30066 Roo.destroy.apply(Roo, this.fields.items);
30068 Roo.Element.uncache(this.el, this.tr);
30073 * @class Roo.Toolbar.Item
30074 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30076 * Creates a new Item
30077 * @param {HTMLElement} el
30079 Roo.Toolbar.Item = function(el){
30081 if (typeof (el.xtype) != 'undefined') {
30086 this.el = Roo.getDom(el);
30087 this.id = Roo.id(this.el);
30088 this.hidden = false;
30093 * Fires when the button is rendered
30094 * @param {Button} this
30098 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30100 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30101 //Roo.Toolbar.Item.prototype = {
30104 * Get this item's HTML Element
30105 * @return {HTMLElement}
30107 getEl : function(){
30112 render : function(td){
30115 td.appendChild(this.el);
30117 this.fireEvent('render', this);
30121 * Removes and destroys this item.
30123 destroy : function(){
30124 this.td.parentNode.removeChild(this.td);
30131 this.hidden = false;
30132 this.td.style.display = "";
30139 this.hidden = true;
30140 this.td.style.display = "none";
30144 * Convenience function for boolean show/hide.
30145 * @param {Boolean} visible true to show/false to hide
30147 setVisible: function(visible){
30156 * Try to focus this item.
30158 focus : function(){
30159 Roo.fly(this.el).focus();
30163 * Disables this item.
30165 disable : function(){
30166 Roo.fly(this.td).addClass("x-item-disabled");
30167 this.disabled = true;
30168 this.el.disabled = true;
30172 * Enables this item.
30174 enable : function(){
30175 Roo.fly(this.td).removeClass("x-item-disabled");
30176 this.disabled = false;
30177 this.el.disabled = false;
30183 * @class Roo.Toolbar.Separator
30184 * @extends Roo.Toolbar.Item
30185 * A simple toolbar separator class
30187 * Creates a new Separator
30189 Roo.Toolbar.Separator = function(cfg){
30191 var s = document.createElement("span");
30192 s.className = "ytb-sep";
30197 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30199 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30200 enable:Roo.emptyFn,
30201 disable:Roo.emptyFn,
30206 * @class Roo.Toolbar.Spacer
30207 * @extends Roo.Toolbar.Item
30208 * A simple element that adds extra horizontal space to a toolbar.
30210 * Creates a new Spacer
30212 Roo.Toolbar.Spacer = function(cfg){
30213 var s = document.createElement("div");
30214 s.className = "ytb-spacer";
30218 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30220 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30221 enable:Roo.emptyFn,
30222 disable:Roo.emptyFn,
30227 * @class Roo.Toolbar.Fill
30228 * @extends Roo.Toolbar.Spacer
30229 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30231 * Creates a new Spacer
30233 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30235 render : function(td){
30236 td.style.width = '100%';
30237 Roo.Toolbar.Fill.superclass.render.call(this, td);
30242 * @class Roo.Toolbar.TextItem
30243 * @extends Roo.Toolbar.Item
30244 * A simple class that renders text directly into a toolbar.
30246 * Creates a new TextItem
30247 * @param {String} text
30249 Roo.Toolbar.TextItem = function(cfg){
30250 var text = cfg || "";
30251 if (typeof(cfg) == 'object') {
30252 text = cfg.text || "";
30256 var s = document.createElement("span");
30257 s.className = "ytb-text";
30258 s.innerHTML = text;
30263 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30265 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30268 enable:Roo.emptyFn,
30269 disable:Roo.emptyFn,
30274 * @class Roo.Toolbar.Button
30275 * @extends Roo.Button
30276 * A button that renders into a toolbar.
30278 * Creates a new Button
30279 * @param {Object} config A standard {@link Roo.Button} config object
30281 Roo.Toolbar.Button = function(config){
30282 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30284 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30285 render : function(td){
30287 Roo.Toolbar.Button.superclass.render.call(this, td);
30291 * Removes and destroys this button
30293 destroy : function(){
30294 Roo.Toolbar.Button.superclass.destroy.call(this);
30295 this.td.parentNode.removeChild(this.td);
30299 * Shows this button
30302 this.hidden = false;
30303 this.td.style.display = "";
30307 * Hides this button
30310 this.hidden = true;
30311 this.td.style.display = "none";
30315 * Disables this item
30317 disable : function(){
30318 Roo.fly(this.td).addClass("x-item-disabled");
30319 this.disabled = true;
30323 * Enables this item
30325 enable : function(){
30326 Roo.fly(this.td).removeClass("x-item-disabled");
30327 this.disabled = false;
30330 // backwards compat
30331 Roo.ToolbarButton = Roo.Toolbar.Button;
30334 * @class Roo.Toolbar.SplitButton
30335 * @extends Roo.SplitButton
30336 * A menu button that renders into a toolbar.
30338 * Creates a new SplitButton
30339 * @param {Object} config A standard {@link Roo.SplitButton} config object
30341 Roo.Toolbar.SplitButton = function(config){
30342 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30344 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30345 render : function(td){
30347 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30351 * Removes and destroys this button
30353 destroy : function(){
30354 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30355 this.td.parentNode.removeChild(this.td);
30359 * Shows this button
30362 this.hidden = false;
30363 this.td.style.display = "";
30367 * Hides this button
30370 this.hidden = true;
30371 this.td.style.display = "none";
30375 // backwards compat
30376 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30378 * Ext JS Library 1.1.1
30379 * Copyright(c) 2006-2007, Ext JS, LLC.
30381 * Originally Released Under LGPL - original licence link has changed is not relivant.
30384 * <script type="text/javascript">
30388 * @class Roo.PagingToolbar
30389 * @extends Roo.Toolbar
30390 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30392 * Create a new PagingToolbar
30393 * @param {Object} config The config object
30395 Roo.PagingToolbar = function(el, ds, config)
30397 // old args format still supported... - xtype is prefered..
30398 if (typeof(el) == 'object' && el.xtype) {
30399 // created from xtype...
30401 ds = el.dataSource;
30402 el = config.container;
30405 if (config.items) {
30406 items = config.items;
30410 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30413 this.renderButtons(this.el);
30416 // supprot items array.
30418 Roo.each(items, function(e) {
30419 this.add(Roo.factory(e));
30424 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30426 * @cfg {Roo.data.Store} dataSource
30427 * The underlying data store providing the paged data
30430 * @cfg {String/HTMLElement/Element} container
30431 * container The id or element that will contain the toolbar
30434 * @cfg {Boolean} displayInfo
30435 * True to display the displayMsg (defaults to false)
30438 * @cfg {Number} pageSize
30439 * The number of records to display per page (defaults to 20)
30443 * @cfg {String} displayMsg
30444 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30446 displayMsg : 'Displaying {0} - {1} of {2}',
30448 * @cfg {String} emptyMsg
30449 * The message to display when no records are found (defaults to "No data to display")
30451 emptyMsg : 'No data to display',
30453 * Customizable piece of the default paging text (defaults to "Page")
30456 beforePageText : "Page",
30458 * Customizable piece of the default paging text (defaults to "of %0")
30461 afterPageText : "of {0}",
30463 * Customizable piece of the default paging text (defaults to "First Page")
30466 firstText : "First Page",
30468 * Customizable piece of the default paging text (defaults to "Previous Page")
30471 prevText : "Previous Page",
30473 * Customizable piece of the default paging text (defaults to "Next Page")
30476 nextText : "Next Page",
30478 * Customizable piece of the default paging text (defaults to "Last Page")
30481 lastText : "Last Page",
30483 * Customizable piece of the default paging text (defaults to "Refresh")
30486 refreshText : "Refresh",
30489 renderButtons : function(el){
30490 Roo.PagingToolbar.superclass.render.call(this, el);
30491 this.first = this.addButton({
30492 tooltip: this.firstText,
30493 cls: "x-btn-icon x-grid-page-first",
30495 handler: this.onClick.createDelegate(this, ["first"])
30497 this.prev = this.addButton({
30498 tooltip: this.prevText,
30499 cls: "x-btn-icon x-grid-page-prev",
30501 handler: this.onClick.createDelegate(this, ["prev"])
30503 //this.addSeparator();
30504 this.add(this.beforePageText);
30505 this.field = Roo.get(this.addDom({
30510 cls: "x-grid-page-number"
30512 this.field.on("keydown", this.onPagingKeydown, this);
30513 this.field.on("focus", function(){this.dom.select();});
30514 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30515 this.field.setHeight(18);
30516 //this.addSeparator();
30517 this.next = this.addButton({
30518 tooltip: this.nextText,
30519 cls: "x-btn-icon x-grid-page-next",
30521 handler: this.onClick.createDelegate(this, ["next"])
30523 this.last = this.addButton({
30524 tooltip: this.lastText,
30525 cls: "x-btn-icon x-grid-page-last",
30527 handler: this.onClick.createDelegate(this, ["last"])
30529 //this.addSeparator();
30530 this.loading = this.addButton({
30531 tooltip: this.refreshText,
30532 cls: "x-btn-icon x-grid-loading",
30533 handler: this.onClick.createDelegate(this, ["refresh"])
30536 if(this.displayInfo){
30537 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30542 updateInfo : function(){
30543 if(this.displayEl){
30544 var count = this.ds.getCount();
30545 var msg = count == 0 ?
30549 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30551 this.displayEl.update(msg);
30556 onLoad : function(ds, r, o){
30557 this.cursor = o.params ? o.params.start : 0;
30558 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30560 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30561 this.field.dom.value = ap;
30562 this.first.setDisabled(ap == 1);
30563 this.prev.setDisabled(ap == 1);
30564 this.next.setDisabled(ap == ps);
30565 this.last.setDisabled(ap == ps);
30566 this.loading.enable();
30571 getPageData : function(){
30572 var total = this.ds.getTotalCount();
30575 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30576 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30581 onLoadError : function(){
30582 this.loading.enable();
30586 onPagingKeydown : function(e){
30587 var k = e.getKey();
30588 var d = this.getPageData();
30590 var v = this.field.dom.value, pageNum;
30591 if(!v || isNaN(pageNum = parseInt(v, 10))){
30592 this.field.dom.value = d.activePage;
30595 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30596 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30599 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))
30601 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30602 this.field.dom.value = pageNum;
30603 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30606 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30608 var v = this.field.dom.value, pageNum;
30609 var increment = (e.shiftKey) ? 10 : 1;
30610 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30613 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30614 this.field.dom.value = d.activePage;
30617 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30619 this.field.dom.value = parseInt(v, 10) + increment;
30620 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30621 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30628 beforeLoad : function(){
30630 this.loading.disable();
30635 onClick : function(which){
30639 ds.load({params:{start: 0, limit: this.pageSize}});
30642 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30645 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30648 var total = ds.getTotalCount();
30649 var extra = total % this.pageSize;
30650 var lastStart = extra ? (total - extra) : total-this.pageSize;
30651 ds.load({params:{start: lastStart, limit: this.pageSize}});
30654 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30660 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30661 * @param {Roo.data.Store} store The data store to unbind
30663 unbind : function(ds){
30664 ds.un("beforeload", this.beforeLoad, this);
30665 ds.un("load", this.onLoad, this);
30666 ds.un("loadexception", this.onLoadError, this);
30667 ds.un("remove", this.updateInfo, this);
30668 ds.un("add", this.updateInfo, this);
30669 this.ds = undefined;
30673 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30674 * @param {Roo.data.Store} store The data store to bind
30676 bind : function(ds){
30677 ds.on("beforeload", this.beforeLoad, this);
30678 ds.on("load", this.onLoad, this);
30679 ds.on("loadexception", this.onLoadError, this);
30680 ds.on("remove", this.updateInfo, this);
30681 ds.on("add", this.updateInfo, this);
30686 * Ext JS Library 1.1.1
30687 * Copyright(c) 2006-2007, Ext JS, LLC.
30689 * Originally Released Under LGPL - original licence link has changed is not relivant.
30692 * <script type="text/javascript">
30696 * @class Roo.Resizable
30697 * @extends Roo.util.Observable
30698 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30699 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30700 * 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
30701 * the element will be wrapped for you automatically.</p>
30702 * <p>Here is the list of valid resize handles:</p>
30705 ------ -------------------
30714 'hd' horizontal drag
30717 * <p>Here's an example showing the creation of a typical Resizable:</p>
30719 var resizer = new Roo.Resizable("element-id", {
30727 resizer.on("resize", myHandler);
30729 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30730 * resizer.east.setDisplayed(false);</p>
30731 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30732 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30733 * resize operation's new size (defaults to [0, 0])
30734 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30735 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30736 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30737 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30738 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30739 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30740 * @cfg {Number} width The width of the element in pixels (defaults to null)
30741 * @cfg {Number} height The height of the element in pixels (defaults to null)
30742 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30743 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30744 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30745 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30746 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30747 * in favor of the handles config option (defaults to false)
30748 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30749 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30750 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30751 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30752 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30753 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30754 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30755 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30756 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30757 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30758 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30760 * Create a new resizable component
30761 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30762 * @param {Object} config configuration options
30764 Roo.Resizable = function(el, config)
30766 this.el = Roo.get(el);
30768 if(config && config.wrap){
30769 config.resizeChild = this.el;
30770 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30771 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30772 this.el.setStyle("overflow", "hidden");
30773 this.el.setPositioning(config.resizeChild.getPositioning());
30774 config.resizeChild.clearPositioning();
30775 if(!config.width || !config.height){
30776 var csize = config.resizeChild.getSize();
30777 this.el.setSize(csize.width, csize.height);
30779 if(config.pinned && !config.adjustments){
30780 config.adjustments = "auto";
30784 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30785 this.proxy.unselectable();
30786 this.proxy.enableDisplayMode('block');
30788 Roo.apply(this, config);
30791 this.disableTrackOver = true;
30792 this.el.addClass("x-resizable-pinned");
30794 // if the element isn't positioned, make it relative
30795 var position = this.el.getStyle("position");
30796 if(position != "absolute" && position != "fixed"){
30797 this.el.setStyle("position", "relative");
30799 if(!this.handles){ // no handles passed, must be legacy style
30800 this.handles = 's,e,se';
30801 if(this.multiDirectional){
30802 this.handles += ',n,w';
30805 if(this.handles == "all"){
30806 this.handles = "n s e w ne nw se sw";
30808 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30809 var ps = Roo.Resizable.positions;
30810 for(var i = 0, len = hs.length; i < len; i++){
30811 if(hs[i] && ps[hs[i]]){
30812 var pos = ps[hs[i]];
30813 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30817 this.corner = this.southeast;
30819 // updateBox = the box can move..
30820 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30821 this.updateBox = true;
30824 this.activeHandle = null;
30826 if(this.resizeChild){
30827 if(typeof this.resizeChild == "boolean"){
30828 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30830 this.resizeChild = Roo.get(this.resizeChild, true);
30834 if(this.adjustments == "auto"){
30835 var rc = this.resizeChild;
30836 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30837 if(rc && (hw || hn)){
30838 rc.position("relative");
30839 rc.setLeft(hw ? hw.el.getWidth() : 0);
30840 rc.setTop(hn ? hn.el.getHeight() : 0);
30842 this.adjustments = [
30843 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30844 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30848 if(this.draggable){
30849 this.dd = this.dynamic ?
30850 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30851 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30857 * @event beforeresize
30858 * Fired before resize is allowed. Set enabled to false to cancel resize.
30859 * @param {Roo.Resizable} this
30860 * @param {Roo.EventObject} e The mousedown event
30862 "beforeresize" : true,
30865 * Fired a resizing.
30866 * @param {Roo.Resizable} this
30867 * @param {Number} x The new x position
30868 * @param {Number} y The new y position
30869 * @param {Number} w The new w width
30870 * @param {Number} h The new h hight
30871 * @param {Roo.EventObject} e The mouseup event
30876 * Fired after a resize.
30877 * @param {Roo.Resizable} this
30878 * @param {Number} width The new width
30879 * @param {Number} height The new height
30880 * @param {Roo.EventObject} e The mouseup event
30885 if(this.width !== null && this.height !== null){
30886 this.resizeTo(this.width, this.height);
30888 this.updateChildSize();
30891 this.el.dom.style.zoom = 1;
30893 Roo.Resizable.superclass.constructor.call(this);
30896 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30897 resizeChild : false,
30898 adjustments : [0, 0],
30908 multiDirectional : false,
30909 disableTrackOver : false,
30910 easing : 'easeOutStrong',
30911 widthIncrement : 0,
30912 heightIncrement : 0,
30916 preserveRatio : false,
30917 transparent: false,
30923 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30925 constrainTo: undefined,
30927 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30929 resizeRegion: undefined,
30933 * Perform a manual resize
30934 * @param {Number} width
30935 * @param {Number} height
30937 resizeTo : function(width, height){
30938 this.el.setSize(width, height);
30939 this.updateChildSize();
30940 this.fireEvent("resize", this, width, height, null);
30944 startSizing : function(e, handle){
30945 this.fireEvent("beforeresize", this, e);
30946 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30949 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30950 this.overlay.unselectable();
30951 this.overlay.enableDisplayMode("block");
30952 this.overlay.on("mousemove", this.onMouseMove, this);
30953 this.overlay.on("mouseup", this.onMouseUp, this);
30955 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30957 this.resizing = true;
30958 this.startBox = this.el.getBox();
30959 this.startPoint = e.getXY();
30960 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30961 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30963 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30964 this.overlay.show();
30966 if(this.constrainTo) {
30967 var ct = Roo.get(this.constrainTo);
30968 this.resizeRegion = ct.getRegion().adjust(
30969 ct.getFrameWidth('t'),
30970 ct.getFrameWidth('l'),
30971 -ct.getFrameWidth('b'),
30972 -ct.getFrameWidth('r')
30976 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30978 this.proxy.setBox(this.startBox);
30980 this.proxy.setStyle('visibility', 'visible');
30986 onMouseDown : function(handle, e){
30989 this.activeHandle = handle;
30990 this.startSizing(e, handle);
30995 onMouseUp : function(e){
30996 var size = this.resizeElement();
30997 this.resizing = false;
30999 this.overlay.hide();
31001 this.fireEvent("resize", this, size.width, size.height, e);
31005 updateChildSize : function(){
31007 if(this.resizeChild){
31009 var child = this.resizeChild;
31010 var adj = this.adjustments;
31011 if(el.dom.offsetWidth){
31012 var b = el.getSize(true);
31013 child.setSize(b.width+adj[0], b.height+adj[1]);
31015 // Second call here for IE
31016 // The first call enables instant resizing and
31017 // the second call corrects scroll bars if they
31020 setTimeout(function(){
31021 if(el.dom.offsetWidth){
31022 var b = el.getSize(true);
31023 child.setSize(b.width+adj[0], b.height+adj[1]);
31031 snap : function(value, inc, min){
31032 if(!inc || !value) {
31035 var newValue = value;
31036 var m = value % inc;
31039 newValue = value + (inc-m);
31041 newValue = value - m;
31044 return Math.max(min, newValue);
31048 resizeElement : function(){
31049 var box = this.proxy.getBox();
31050 if(this.updateBox){
31051 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31053 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31055 this.updateChildSize();
31063 constrain : function(v, diff, m, mx){
31066 }else if(v - diff > mx){
31073 onMouseMove : function(e){
31076 try{// try catch so if something goes wrong the user doesn't get hung
31078 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31082 //var curXY = this.startPoint;
31083 var curSize = this.curSize || this.startBox;
31084 var x = this.startBox.x, y = this.startBox.y;
31085 var ox = x, oy = y;
31086 var w = curSize.width, h = curSize.height;
31087 var ow = w, oh = h;
31088 var mw = this.minWidth, mh = this.minHeight;
31089 var mxw = this.maxWidth, mxh = this.maxHeight;
31090 var wi = this.widthIncrement;
31091 var hi = this.heightIncrement;
31093 var eventXY = e.getXY();
31094 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31095 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31097 var pos = this.activeHandle.position;
31102 w = Math.min(Math.max(mw, w), mxw);
31107 h = Math.min(Math.max(mh, h), mxh);
31112 w = Math.min(Math.max(mw, w), mxw);
31113 h = Math.min(Math.max(mh, h), mxh);
31116 diffY = this.constrain(h, diffY, mh, mxh);
31123 var adiffX = Math.abs(diffX);
31124 var sub = (adiffX % wi); // how much
31125 if (sub > (wi/2)) { // far enough to snap
31126 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31128 // remove difference..
31129 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31133 x = Math.max(this.minX, x);
31136 diffX = this.constrain(w, diffX, mw, mxw);
31142 w = Math.min(Math.max(mw, w), mxw);
31143 diffY = this.constrain(h, diffY, mh, mxh);
31148 diffX = this.constrain(w, diffX, mw, mxw);
31149 diffY = this.constrain(h, diffY, mh, mxh);
31156 diffX = this.constrain(w, diffX, mw, mxw);
31158 h = Math.min(Math.max(mh, h), mxh);
31164 var sw = this.snap(w, wi, mw);
31165 var sh = this.snap(h, hi, mh);
31166 if(sw != w || sh != h){
31189 if(this.preserveRatio){
31194 h = Math.min(Math.max(mh, h), mxh);
31199 w = Math.min(Math.max(mw, w), mxw);
31204 w = Math.min(Math.max(mw, w), mxw);
31210 w = Math.min(Math.max(mw, w), mxw);
31216 h = Math.min(Math.max(mh, h), mxh);
31224 h = Math.min(Math.max(mh, h), mxh);
31234 h = Math.min(Math.max(mh, h), mxh);
31242 if (pos == 'hdrag') {
31245 this.proxy.setBounds(x, y, w, h);
31247 this.resizeElement();
31251 this.fireEvent("resizing", this, x, y, w, h, e);
31255 handleOver : function(){
31257 this.el.addClass("x-resizable-over");
31262 handleOut : function(){
31263 if(!this.resizing){
31264 this.el.removeClass("x-resizable-over");
31269 * Returns the element this component is bound to.
31270 * @return {Roo.Element}
31272 getEl : function(){
31277 * Returns the resizeChild element (or null).
31278 * @return {Roo.Element}
31280 getResizeChild : function(){
31281 return this.resizeChild;
31283 groupHandler : function()
31288 * Destroys this resizable. If the element was wrapped and
31289 * removeEl is not true then the element remains.
31290 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31292 destroy : function(removeEl){
31293 this.proxy.remove();
31295 this.overlay.removeAllListeners();
31296 this.overlay.remove();
31298 var ps = Roo.Resizable.positions;
31300 if(typeof ps[k] != "function" && this[ps[k]]){
31301 var h = this[ps[k]];
31302 h.el.removeAllListeners();
31307 this.el.update("");
31314 // hash to map config positions to true positions
31315 Roo.Resizable.positions = {
31316 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31321 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31323 // only initialize the template if resizable is used
31324 var tpl = Roo.DomHelper.createTemplate(
31325 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31328 Roo.Resizable.Handle.prototype.tpl = tpl;
31330 this.position = pos;
31332 // show north drag fro topdra
31333 var handlepos = pos == 'hdrag' ? 'north' : pos;
31335 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31336 if (pos == 'hdrag') {
31337 this.el.setStyle('cursor', 'pointer');
31339 this.el.unselectable();
31341 this.el.setOpacity(0);
31343 this.el.on("mousedown", this.onMouseDown, this);
31344 if(!disableTrackOver){
31345 this.el.on("mouseover", this.onMouseOver, this);
31346 this.el.on("mouseout", this.onMouseOut, this);
31351 Roo.Resizable.Handle.prototype = {
31352 afterResize : function(rz){
31357 onMouseDown : function(e){
31358 this.rz.onMouseDown(this, e);
31361 onMouseOver : function(e){
31362 this.rz.handleOver(this, e);
31365 onMouseOut : function(e){
31366 this.rz.handleOut(this, e);
31370 * Ext JS Library 1.1.1
31371 * Copyright(c) 2006-2007, Ext JS, LLC.
31373 * Originally Released Under LGPL - original licence link has changed is not relivant.
31376 * <script type="text/javascript">
31380 * @class Roo.Editor
31381 * @extends Roo.Component
31382 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31384 * Create a new Editor
31385 * @param {Roo.form.Field} field The Field object (or descendant)
31386 * @param {Object} config The config object
31388 Roo.Editor = function(field, config){
31389 Roo.Editor.superclass.constructor.call(this, config);
31390 this.field = field;
31393 * @event beforestartedit
31394 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31395 * false from the handler of this event.
31396 * @param {Editor} this
31397 * @param {Roo.Element} boundEl The underlying element bound to this editor
31398 * @param {Mixed} value The field value being set
31400 "beforestartedit" : true,
31403 * Fires when this editor is displayed
31404 * @param {Roo.Element} boundEl The underlying element bound to this editor
31405 * @param {Mixed} value The starting field value
31407 "startedit" : true,
31409 * @event beforecomplete
31410 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31411 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31412 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31413 * event will not fire since no edit actually occurred.
31414 * @param {Editor} this
31415 * @param {Mixed} value The current field value
31416 * @param {Mixed} startValue The original field value
31418 "beforecomplete" : true,
31421 * Fires after editing is complete and any changed value has been written to the underlying field.
31422 * @param {Editor} this
31423 * @param {Mixed} value The current field value
31424 * @param {Mixed} startValue The original field value
31428 * @event specialkey
31429 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31430 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31431 * @param {Roo.form.Field} this
31432 * @param {Roo.EventObject} e The event object
31434 "specialkey" : true
31438 Roo.extend(Roo.Editor, Roo.Component, {
31440 * @cfg {Boolean/String} autosize
31441 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31442 * or "height" to adopt the height only (defaults to false)
31445 * @cfg {Boolean} revertInvalid
31446 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31447 * validation fails (defaults to true)
31450 * @cfg {Boolean} ignoreNoChange
31451 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31452 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31453 * will never be ignored.
31456 * @cfg {Boolean} hideEl
31457 * False to keep the bound element visible while the editor is displayed (defaults to true)
31460 * @cfg {Mixed} value
31461 * The data value of the underlying field (defaults to "")
31465 * @cfg {String} alignment
31466 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31470 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31471 * for bottom-right shadow (defaults to "frame")
31475 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31479 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31481 completeOnEnter : false,
31483 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31485 cancelOnEsc : false,
31487 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31492 onRender : function(ct, position){
31493 this.el = new Roo.Layer({
31494 shadow: this.shadow,
31500 constrain: this.constrain
31502 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31503 if(this.field.msgTarget != 'title'){
31504 this.field.msgTarget = 'qtip';
31506 this.field.render(this.el);
31508 this.field.el.dom.setAttribute('autocomplete', 'off');
31510 this.field.on("specialkey", this.onSpecialKey, this);
31511 if(this.swallowKeys){
31512 this.field.el.swallowEvent(['keydown','keypress']);
31515 this.field.on("blur", this.onBlur, this);
31516 if(this.field.grow){
31517 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31521 onSpecialKey : function(field, e)
31523 //Roo.log('editor onSpecialKey');
31524 if(this.completeOnEnter && e.getKey() == e.ENTER){
31526 this.completeEdit();
31529 // do not fire special key otherwise it might hide close the editor...
31530 if(e.getKey() == e.ENTER){
31533 if(this.cancelOnEsc && e.getKey() == e.ESC){
31537 this.fireEvent('specialkey', field, e);
31542 * Starts the editing process and shows the editor.
31543 * @param {String/HTMLElement/Element} el The element to edit
31544 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31545 * to the innerHTML of el.
31547 startEdit : function(el, value){
31549 this.completeEdit();
31551 this.boundEl = Roo.get(el);
31552 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31553 if(!this.rendered){
31554 this.render(this.parentEl || document.body);
31556 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31559 this.startValue = v;
31560 this.field.setValue(v);
31562 var sz = this.boundEl.getSize();
31563 switch(this.autoSize){
31565 this.setSize(sz.width, "");
31568 this.setSize("", sz.height);
31571 this.setSize(sz.width, sz.height);
31574 this.el.alignTo(this.boundEl, this.alignment);
31575 this.editing = true;
31577 Roo.QuickTips.disable();
31583 * Sets the height and width of this editor.
31584 * @param {Number} width The new width
31585 * @param {Number} height The new height
31587 setSize : function(w, h){
31588 this.field.setSize(w, h);
31595 * Realigns the editor to the bound field based on the current alignment config value.
31597 realign : function(){
31598 this.el.alignTo(this.boundEl, this.alignment);
31602 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31603 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31605 completeEdit : function(remainVisible){
31609 var v = this.getValue();
31610 if(this.revertInvalid !== false && !this.field.isValid()){
31611 v = this.startValue;
31612 this.cancelEdit(true);
31614 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31615 this.editing = false;
31619 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31620 this.editing = false;
31621 if(this.updateEl && this.boundEl){
31622 this.boundEl.update(v);
31624 if(remainVisible !== true){
31627 this.fireEvent("complete", this, v, this.startValue);
31632 onShow : function(){
31634 if(this.hideEl !== false){
31635 this.boundEl.hide();
31638 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31639 this.fixIEFocus = true;
31640 this.deferredFocus.defer(50, this);
31642 this.field.focus();
31644 this.fireEvent("startedit", this.boundEl, this.startValue);
31647 deferredFocus : function(){
31649 this.field.focus();
31654 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31655 * reverted to the original starting value.
31656 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31657 * cancel (defaults to false)
31659 cancelEdit : function(remainVisible){
31661 this.setValue(this.startValue);
31662 if(remainVisible !== true){
31669 onBlur : function(){
31670 if(this.allowBlur !== true && this.editing){
31671 this.completeEdit();
31676 onHide : function(){
31678 this.completeEdit();
31682 if(this.field.collapse){
31683 this.field.collapse();
31686 if(this.hideEl !== false){
31687 this.boundEl.show();
31690 Roo.QuickTips.enable();
31695 * Sets the data value of the editor
31696 * @param {Mixed} value Any valid value supported by the underlying field
31698 setValue : function(v){
31699 this.field.setValue(v);
31703 * Gets the data value of the editor
31704 * @return {Mixed} The data value
31706 getValue : function(){
31707 return this.field.getValue();
31711 * Ext JS Library 1.1.1
31712 * Copyright(c) 2006-2007, Ext JS, LLC.
31714 * Originally Released Under LGPL - original licence link has changed is not relivant.
31717 * <script type="text/javascript">
31721 * @class Roo.BasicDialog
31722 * @extends Roo.util.Observable
31723 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31725 var dlg = new Roo.BasicDialog("my-dlg", {
31734 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31735 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31736 dlg.addButton('Cancel', dlg.hide, dlg);
31739 <b>A Dialog should always be a direct child of the body element.</b>
31740 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31741 * @cfg {String} title Default text to display in the title bar (defaults to null)
31742 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31743 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31744 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31745 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31746 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31747 * (defaults to null with no animation)
31748 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31749 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31750 * property for valid values (defaults to 'all')
31751 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31752 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31753 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31754 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31755 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31756 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31757 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31758 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31759 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31760 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31761 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31762 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31763 * draggable = true (defaults to false)
31764 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31765 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31766 * shadow (defaults to false)
31767 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31768 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31769 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31770 * @cfg {Array} buttons Array of buttons
31771 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31773 * Create a new BasicDialog.
31774 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31775 * @param {Object} config Configuration options
31777 Roo.BasicDialog = function(el, config){
31778 this.el = Roo.get(el);
31779 var dh = Roo.DomHelper;
31780 if(!this.el && config && config.autoCreate){
31781 if(typeof config.autoCreate == "object"){
31782 if(!config.autoCreate.id){
31783 config.autoCreate.id = el;
31785 this.el = dh.append(document.body,
31786 config.autoCreate, true);
31788 this.el = dh.append(document.body,
31789 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31793 el.setDisplayed(true);
31794 el.hide = this.hideAction;
31796 el.addClass("x-dlg");
31798 Roo.apply(this, config);
31800 this.proxy = el.createProxy("x-dlg-proxy");
31801 this.proxy.hide = this.hideAction;
31802 this.proxy.setOpacity(.5);
31806 el.setWidth(config.width);
31809 el.setHeight(config.height);
31811 this.size = el.getSize();
31812 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31813 this.xy = [config.x,config.y];
31815 this.xy = el.getCenterXY(true);
31817 /** The header element @type Roo.Element */
31818 this.header = el.child("> .x-dlg-hd");
31819 /** The body element @type Roo.Element */
31820 this.body = el.child("> .x-dlg-bd");
31821 /** The footer element @type Roo.Element */
31822 this.footer = el.child("> .x-dlg-ft");
31825 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31828 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31831 this.header.unselectable();
31833 this.header.update(this.title);
31835 // this element allows the dialog to be focused for keyboard event
31836 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31837 this.focusEl.swallowEvent("click", true);
31839 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31841 // wrap the body and footer for special rendering
31842 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31844 this.bwrap.dom.appendChild(this.footer.dom);
31847 this.bg = this.el.createChild({
31848 tag: "div", cls:"x-dlg-bg",
31849 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31851 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31854 if(this.autoScroll !== false && !this.autoTabs){
31855 this.body.setStyle("overflow", "auto");
31858 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31860 if(this.closable !== false){
31861 this.el.addClass("x-dlg-closable");
31862 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31863 this.close.on("click", this.closeClick, this);
31864 this.close.addClassOnOver("x-dlg-close-over");
31866 if(this.collapsible !== false){
31867 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31868 this.collapseBtn.on("click", this.collapseClick, this);
31869 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31870 this.header.on("dblclick", this.collapseClick, this);
31872 if(this.resizable !== false){
31873 this.el.addClass("x-dlg-resizable");
31874 this.resizer = new Roo.Resizable(el, {
31875 minWidth: this.minWidth || 80,
31876 minHeight:this.minHeight || 80,
31877 handles: this.resizeHandles || "all",
31880 this.resizer.on("beforeresize", this.beforeResize, this);
31881 this.resizer.on("resize", this.onResize, this);
31883 if(this.draggable !== false){
31884 el.addClass("x-dlg-draggable");
31885 if (!this.proxyDrag) {
31886 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31889 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31891 dd.setHandleElId(this.header.id);
31892 dd.endDrag = this.endMove.createDelegate(this);
31893 dd.startDrag = this.startMove.createDelegate(this);
31894 dd.onDrag = this.onDrag.createDelegate(this);
31899 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31900 this.mask.enableDisplayMode("block");
31902 this.el.addClass("x-dlg-modal");
31905 this.shadow = new Roo.Shadow({
31906 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31907 offset : this.shadowOffset
31910 this.shadowOffset = 0;
31912 if(Roo.useShims && this.shim !== false){
31913 this.shim = this.el.createShim();
31914 this.shim.hide = this.hideAction;
31922 if (this.buttons) {
31923 var bts= this.buttons;
31925 Roo.each(bts, function(b) {
31934 * Fires when a key is pressed
31935 * @param {Roo.BasicDialog} this
31936 * @param {Roo.EventObject} e
31941 * Fires when this dialog is moved by the user.
31942 * @param {Roo.BasicDialog} this
31943 * @param {Number} x The new page X
31944 * @param {Number} y The new page Y
31949 * Fires when this dialog is resized by the user.
31950 * @param {Roo.BasicDialog} this
31951 * @param {Number} width The new width
31952 * @param {Number} height The new height
31956 * @event beforehide
31957 * Fires before this dialog is hidden.
31958 * @param {Roo.BasicDialog} this
31960 "beforehide" : true,
31963 * Fires when this dialog is hidden.
31964 * @param {Roo.BasicDialog} this
31968 * @event beforeshow
31969 * Fires before this dialog is shown.
31970 * @param {Roo.BasicDialog} this
31972 "beforeshow" : true,
31975 * Fires when this dialog is shown.
31976 * @param {Roo.BasicDialog} this
31980 el.on("keydown", this.onKeyDown, this);
31981 el.on("mousedown", this.toFront, this);
31982 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31984 Roo.DialogManager.register(this);
31985 Roo.BasicDialog.superclass.constructor.call(this);
31988 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31989 shadowOffset: Roo.isIE ? 6 : 5,
31992 minButtonWidth: 75,
31993 defaultButton: null,
31994 buttonAlign: "right",
31999 * Sets the dialog title text
32000 * @param {String} text The title text to display
32001 * @return {Roo.BasicDialog} this
32003 setTitle : function(text){
32004 this.header.update(text);
32009 closeClick : function(){
32014 collapseClick : function(){
32015 this[this.collapsed ? "expand" : "collapse"]();
32019 * Collapses the dialog to its minimized state (only the title bar is visible).
32020 * Equivalent to the user clicking the collapse dialog button.
32022 collapse : function(){
32023 if(!this.collapsed){
32024 this.collapsed = true;
32025 this.el.addClass("x-dlg-collapsed");
32026 this.restoreHeight = this.el.getHeight();
32027 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32032 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32033 * clicking the expand dialog button.
32035 expand : function(){
32036 if(this.collapsed){
32037 this.collapsed = false;
32038 this.el.removeClass("x-dlg-collapsed");
32039 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32044 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32045 * @return {Roo.TabPanel} The tabs component
32047 initTabs : function(){
32048 var tabs = this.getTabs();
32049 while(tabs.getTab(0)){
32052 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32054 tabs.addTab(Roo.id(dom), dom.title);
32062 beforeResize : function(){
32063 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32067 onResize : function(){
32068 this.refreshSize();
32069 this.syncBodyHeight();
32070 this.adjustAssets();
32072 this.fireEvent("resize", this, this.size.width, this.size.height);
32076 onKeyDown : function(e){
32077 if(this.isVisible()){
32078 this.fireEvent("keydown", this, e);
32083 * Resizes the dialog.
32084 * @param {Number} width
32085 * @param {Number} height
32086 * @return {Roo.BasicDialog} this
32088 resizeTo : function(width, height){
32089 this.el.setSize(width, height);
32090 this.size = {width: width, height: height};
32091 this.syncBodyHeight();
32092 if(this.fixedcenter){
32095 if(this.isVisible()){
32096 this.constrainXY();
32097 this.adjustAssets();
32099 this.fireEvent("resize", this, width, height);
32105 * Resizes the dialog to fit the specified content size.
32106 * @param {Number} width
32107 * @param {Number} height
32108 * @return {Roo.BasicDialog} this
32110 setContentSize : function(w, h){
32111 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32112 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32113 //if(!this.el.isBorderBox()){
32114 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32115 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32118 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32119 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32121 this.resizeTo(w, h);
32126 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32127 * executed in response to a particular key being pressed while the dialog is active.
32128 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32129 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32130 * @param {Function} fn The function to call
32131 * @param {Object} scope (optional) The scope of the function
32132 * @return {Roo.BasicDialog} this
32134 addKeyListener : function(key, fn, scope){
32135 var keyCode, shift, ctrl, alt;
32136 if(typeof key == "object" && !(key instanceof Array)){
32137 keyCode = key["key"];
32138 shift = key["shift"];
32139 ctrl = key["ctrl"];
32144 var handler = function(dlg, e){
32145 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32146 var k = e.getKey();
32147 if(keyCode instanceof Array){
32148 for(var i = 0, len = keyCode.length; i < len; i++){
32149 if(keyCode[i] == k){
32150 fn.call(scope || window, dlg, k, e);
32156 fn.call(scope || window, dlg, k, e);
32161 this.on("keydown", handler);
32166 * Returns the TabPanel component (creates it if it doesn't exist).
32167 * Note: If you wish to simply check for the existence of tabs without creating them,
32168 * check for a null 'tabs' property.
32169 * @return {Roo.TabPanel} The tabs component
32171 getTabs : function(){
32173 this.el.addClass("x-dlg-auto-tabs");
32174 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32175 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32181 * Adds a button to the footer section of the dialog.
32182 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32183 * object or a valid Roo.DomHelper element config
32184 * @param {Function} handler The function called when the button is clicked
32185 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32186 * @return {Roo.Button} The new button
32188 addButton : function(config, handler, scope){
32189 var dh = Roo.DomHelper;
32191 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32193 if(!this.btnContainer){
32194 var tb = this.footer.createChild({
32196 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32197 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32199 this.btnContainer = tb.firstChild.firstChild.firstChild;
32204 minWidth: this.minButtonWidth,
32207 if(typeof config == "string"){
32208 bconfig.text = config;
32211 bconfig.dhconfig = config;
32213 Roo.apply(bconfig, config);
32217 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32218 bconfig.position = Math.max(0, bconfig.position);
32219 fc = this.btnContainer.childNodes[bconfig.position];
32222 var btn = new Roo.Button(
32224 this.btnContainer.insertBefore(document.createElement("td"),fc)
32225 : this.btnContainer.appendChild(document.createElement("td")),
32226 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32229 this.syncBodyHeight();
32232 * Array of all the buttons that have been added to this dialog via addButton
32237 this.buttons.push(btn);
32242 * Sets the default button to be focused when the dialog is displayed.
32243 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32244 * @return {Roo.BasicDialog} this
32246 setDefaultButton : function(btn){
32247 this.defaultButton = btn;
32252 getHeaderFooterHeight : function(safe){
32255 height += this.header.getHeight();
32258 var fm = this.footer.getMargins();
32259 height += (this.footer.getHeight()+fm.top+fm.bottom);
32261 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32262 height += this.centerBg.getPadding("tb");
32267 syncBodyHeight : function()
32269 var bd = this.body, // the text
32270 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32272 var height = this.size.height - this.getHeaderFooterHeight(false);
32273 bd.setHeight(height-bd.getMargins("tb"));
32274 var hh = this.header.getHeight();
32275 var h = this.size.height-hh;
32278 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32279 bw.setHeight(h-cb.getPadding("tb"));
32281 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32282 bd.setWidth(bw.getWidth(true));
32284 this.tabs.syncHeight();
32286 this.tabs.el.repaint();
32292 * Restores the previous state of the dialog if Roo.state is configured.
32293 * @return {Roo.BasicDialog} this
32295 restoreState : function(){
32296 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32297 if(box && box.width){
32298 this.xy = [box.x, box.y];
32299 this.resizeTo(box.width, box.height);
32305 beforeShow : function(){
32307 if(this.fixedcenter){
32308 this.xy = this.el.getCenterXY(true);
32311 Roo.get(document.body).addClass("x-body-masked");
32312 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32315 this.constrainXY();
32319 animShow : function(){
32320 var b = Roo.get(this.animateTarget).getBox();
32321 this.proxy.setSize(b.width, b.height);
32322 this.proxy.setLocation(b.x, b.y);
32324 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32325 true, .35, this.showEl.createDelegate(this));
32329 * Shows the dialog.
32330 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32331 * @return {Roo.BasicDialog} this
32333 show : function(animateTarget){
32334 if (this.fireEvent("beforeshow", this) === false){
32337 if(this.syncHeightBeforeShow){
32338 this.syncBodyHeight();
32339 }else if(this.firstShow){
32340 this.firstShow = false;
32341 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32343 this.animateTarget = animateTarget || this.animateTarget;
32344 if(!this.el.isVisible()){
32346 if(this.animateTarget && Roo.get(this.animateTarget)){
32356 showEl : function(){
32358 this.el.setXY(this.xy);
32360 this.adjustAssets(true);
32363 // IE peekaboo bug - fix found by Dave Fenwick
32367 this.fireEvent("show", this);
32371 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32372 * dialog itself will receive focus.
32374 focus : function(){
32375 if(this.defaultButton){
32376 this.defaultButton.focus();
32378 this.focusEl.focus();
32383 constrainXY : function(){
32384 if(this.constraintoviewport !== false){
32385 if(!this.viewSize){
32386 if(this.container){
32387 var s = this.container.getSize();
32388 this.viewSize = [s.width, s.height];
32390 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32393 var s = Roo.get(this.container||document).getScroll();
32395 var x = this.xy[0], y = this.xy[1];
32396 var w = this.size.width, h = this.size.height;
32397 var vw = this.viewSize[0], vh = this.viewSize[1];
32398 // only move it if it needs it
32400 // first validate right/bottom
32401 if(x + w > vw+s.left){
32405 if(y + h > vh+s.top){
32409 // then make sure top/left isn't negative
32421 if(this.isVisible()){
32422 this.el.setLocation(x, y);
32423 this.adjustAssets();
32430 onDrag : function(){
32431 if(!this.proxyDrag){
32432 this.xy = this.el.getXY();
32433 this.adjustAssets();
32438 adjustAssets : function(doShow){
32439 var x = this.xy[0], y = this.xy[1];
32440 var w = this.size.width, h = this.size.height;
32441 if(doShow === true){
32443 this.shadow.show(this.el);
32449 if(this.shadow && this.shadow.isVisible()){
32450 this.shadow.show(this.el);
32452 if(this.shim && this.shim.isVisible()){
32453 this.shim.setBounds(x, y, w, h);
32458 adjustViewport : function(w, h){
32460 w = Roo.lib.Dom.getViewWidth();
32461 h = Roo.lib.Dom.getViewHeight();
32464 this.viewSize = [w, h];
32465 if(this.modal && this.mask.isVisible()){
32466 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32467 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32469 if(this.isVisible()){
32470 this.constrainXY();
32475 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32476 * shadow, proxy, mask, etc.) Also removes all event listeners.
32477 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32479 destroy : function(removeEl){
32480 if(this.isVisible()){
32481 this.animateTarget = null;
32484 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32486 this.tabs.destroy(removeEl);
32499 for(var i = 0, len = this.buttons.length; i < len; i++){
32500 this.buttons[i].destroy();
32503 this.el.removeAllListeners();
32504 if(removeEl === true){
32505 this.el.update("");
32508 Roo.DialogManager.unregister(this);
32512 startMove : function(){
32513 if(this.proxyDrag){
32516 if(this.constraintoviewport !== false){
32517 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32522 endMove : function(){
32523 if(!this.proxyDrag){
32524 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32526 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32529 this.refreshSize();
32530 this.adjustAssets();
32532 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32536 * Brings this dialog to the front of any other visible dialogs
32537 * @return {Roo.BasicDialog} this
32539 toFront : function(){
32540 Roo.DialogManager.bringToFront(this);
32545 * Sends this dialog to the back (under) of any other visible dialogs
32546 * @return {Roo.BasicDialog} this
32548 toBack : function(){
32549 Roo.DialogManager.sendToBack(this);
32554 * Centers this dialog in the viewport
32555 * @return {Roo.BasicDialog} this
32557 center : function(){
32558 var xy = this.el.getCenterXY(true);
32559 this.moveTo(xy[0], xy[1]);
32564 * Moves the dialog's top-left corner to the specified point
32565 * @param {Number} x
32566 * @param {Number} y
32567 * @return {Roo.BasicDialog} this
32569 moveTo : function(x, y){
32571 if(this.isVisible()){
32572 this.el.setXY(this.xy);
32573 this.adjustAssets();
32579 * Aligns the dialog to the specified element
32580 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32581 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32582 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32583 * @return {Roo.BasicDialog} this
32585 alignTo : function(element, position, offsets){
32586 this.xy = this.el.getAlignToXY(element, position, offsets);
32587 if(this.isVisible()){
32588 this.el.setXY(this.xy);
32589 this.adjustAssets();
32595 * Anchors an element to another element and realigns it when the window is resized.
32596 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32597 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32598 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32599 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32600 * is a number, it is used as the buffer delay (defaults to 50ms).
32601 * @return {Roo.BasicDialog} this
32603 anchorTo : function(el, alignment, offsets, monitorScroll){
32604 var action = function(){
32605 this.alignTo(el, alignment, offsets);
32607 Roo.EventManager.onWindowResize(action, this);
32608 var tm = typeof monitorScroll;
32609 if(tm != 'undefined'){
32610 Roo.EventManager.on(window, 'scroll', action, this,
32611 {buffer: tm == 'number' ? monitorScroll : 50});
32618 * Returns true if the dialog is visible
32619 * @return {Boolean}
32621 isVisible : function(){
32622 return this.el.isVisible();
32626 animHide : function(callback){
32627 var b = Roo.get(this.animateTarget).getBox();
32629 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32631 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32632 this.hideEl.createDelegate(this, [callback]));
32636 * Hides the dialog.
32637 * @param {Function} callback (optional) Function to call when the dialog is hidden
32638 * @return {Roo.BasicDialog} this
32640 hide : function(callback){
32641 if (this.fireEvent("beforehide", this) === false){
32645 this.shadow.hide();
32650 // sometimes animateTarget seems to get set.. causing problems...
32651 // this just double checks..
32652 if(this.animateTarget && Roo.get(this.animateTarget)) {
32653 this.animHide(callback);
32656 this.hideEl(callback);
32662 hideEl : function(callback){
32666 Roo.get(document.body).removeClass("x-body-masked");
32668 this.fireEvent("hide", this);
32669 if(typeof callback == "function"){
32675 hideAction : function(){
32676 this.setLeft("-10000px");
32677 this.setTop("-10000px");
32678 this.setStyle("visibility", "hidden");
32682 refreshSize : function(){
32683 this.size = this.el.getSize();
32684 this.xy = this.el.getXY();
32685 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32689 // z-index is managed by the DialogManager and may be overwritten at any time
32690 setZIndex : function(index){
32692 this.mask.setStyle("z-index", index);
32695 this.shim.setStyle("z-index", ++index);
32698 this.shadow.setZIndex(++index);
32700 this.el.setStyle("z-index", ++index);
32702 this.proxy.setStyle("z-index", ++index);
32705 this.resizer.proxy.setStyle("z-index", ++index);
32708 this.lastZIndex = index;
32712 * Returns the element for this dialog
32713 * @return {Roo.Element} The underlying dialog Element
32715 getEl : function(){
32721 * @class Roo.DialogManager
32722 * Provides global access to BasicDialogs that have been created and
32723 * support for z-indexing (layering) multiple open dialogs.
32725 Roo.DialogManager = function(){
32727 var accessList = [];
32731 var sortDialogs = function(d1, d2){
32732 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32736 var orderDialogs = function(){
32737 accessList.sort(sortDialogs);
32738 var seed = Roo.DialogManager.zseed;
32739 for(var i = 0, len = accessList.length; i < len; i++){
32740 var dlg = accessList[i];
32742 dlg.setZIndex(seed + (i*10));
32749 * The starting z-index for BasicDialogs (defaults to 9000)
32750 * @type Number The z-index value
32755 register : function(dlg){
32756 list[dlg.id] = dlg;
32757 accessList.push(dlg);
32761 unregister : function(dlg){
32762 delete list[dlg.id];
32765 if(!accessList.indexOf){
32766 for( i = 0, len = accessList.length; i < len; i++){
32767 if(accessList[i] == dlg){
32768 accessList.splice(i, 1);
32773 i = accessList.indexOf(dlg);
32775 accessList.splice(i, 1);
32781 * Gets a registered dialog by id
32782 * @param {String/Object} id The id of the dialog or a dialog
32783 * @return {Roo.BasicDialog} this
32785 get : function(id){
32786 return typeof id == "object" ? id : list[id];
32790 * Brings the specified dialog to the front
32791 * @param {String/Object} dlg The id of the dialog or a dialog
32792 * @return {Roo.BasicDialog} this
32794 bringToFront : function(dlg){
32795 dlg = this.get(dlg);
32798 dlg._lastAccess = new Date().getTime();
32805 * Sends the specified dialog to the back
32806 * @param {String/Object} dlg The id of the dialog or a dialog
32807 * @return {Roo.BasicDialog} this
32809 sendToBack : function(dlg){
32810 dlg = this.get(dlg);
32811 dlg._lastAccess = -(new Date().getTime());
32817 * Hides all dialogs
32819 hideAll : function(){
32820 for(var id in list){
32821 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32830 * @class Roo.LayoutDialog
32831 * @extends Roo.BasicDialog
32832 * Dialog which provides adjustments for working with a layout in a Dialog.
32833 * Add your necessary layout config options to the dialog's config.<br>
32834 * Example usage (including a nested layout):
32837 dialog = new Roo.LayoutDialog("download-dlg", {
32846 // layout config merges with the dialog config
32848 tabPosition: "top",
32849 alwaysShowTabs: true
32852 dialog.addKeyListener(27, dialog.hide, dialog);
32853 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32854 dialog.addButton("Build It!", this.getDownload, this);
32856 // we can even add nested layouts
32857 var innerLayout = new Roo.BorderLayout("dl-inner", {
32867 innerLayout.beginUpdate();
32868 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32869 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32870 innerLayout.endUpdate(true);
32872 var layout = dialog.getLayout();
32873 layout.beginUpdate();
32874 layout.add("center", new Roo.ContentPanel("standard-panel",
32875 {title: "Download the Source", fitToFrame:true}));
32876 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32877 {title: "Build your own roo.js"}));
32878 layout.getRegion("center").showPanel(sp);
32879 layout.endUpdate();
32883 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32884 * @param {Object} config configuration options
32886 Roo.LayoutDialog = function(el, cfg){
32889 if (typeof(cfg) == 'undefined') {
32890 config = Roo.apply({}, el);
32891 // not sure why we use documentElement here.. - it should always be body.
32892 // IE7 borks horribly if we use documentElement.
32893 // webkit also does not like documentElement - it creates a body element...
32894 el = Roo.get( document.body || document.documentElement ).createChild();
32895 //config.autoCreate = true;
32899 config.autoTabs = false;
32900 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32901 this.body.setStyle({overflow:"hidden", position:"relative"});
32902 this.layout = new Roo.BorderLayout(this.body.dom, config);
32903 this.layout.monitorWindowResize = false;
32904 this.el.addClass("x-dlg-auto-layout");
32905 // fix case when center region overwrites center function
32906 this.center = Roo.BasicDialog.prototype.center;
32907 this.on("show", this.layout.layout, this.layout, true);
32908 if (config.items) {
32909 var xitems = config.items;
32910 delete config.items;
32911 Roo.each(xitems, this.addxtype, this);
32916 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32918 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32921 endUpdate : function(){
32922 this.layout.endUpdate();
32926 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32929 beginUpdate : function(){
32930 this.layout.beginUpdate();
32934 * Get the BorderLayout for this dialog
32935 * @return {Roo.BorderLayout}
32937 getLayout : function(){
32938 return this.layout;
32941 showEl : function(){
32942 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32944 this.layout.layout();
32949 // Use the syncHeightBeforeShow config option to control this automatically
32950 syncBodyHeight : function(){
32951 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32952 if(this.layout){this.layout.layout();}
32956 * Add an xtype element (actually adds to the layout.)
32957 * @return {Object} xdata xtype object data.
32960 addxtype : function(c) {
32961 return this.layout.addxtype(c);
32965 * Ext JS Library 1.1.1
32966 * Copyright(c) 2006-2007, Ext JS, LLC.
32968 * Originally Released Under LGPL - original licence link has changed is not relivant.
32971 * <script type="text/javascript">
32975 * @class Roo.MessageBox
32976 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32980 Roo.Msg.alert('Status', 'Changes saved successfully.');
32982 // Prompt for user data:
32983 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32985 // process text value...
32989 // Show a dialog using config options:
32991 title:'Save Changes?',
32992 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32993 buttons: Roo.Msg.YESNOCANCEL,
33000 Roo.MessageBox = function(){
33001 var dlg, opt, mask, waitTimer;
33002 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33003 var buttons, activeTextEl, bwidth;
33006 var handleButton = function(button){
33008 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33012 var handleHide = function(){
33013 if(opt && opt.cls){
33014 dlg.el.removeClass(opt.cls);
33017 Roo.TaskMgr.stop(waitTimer);
33023 var updateButtons = function(b){
33026 buttons["ok"].hide();
33027 buttons["cancel"].hide();
33028 buttons["yes"].hide();
33029 buttons["no"].hide();
33030 dlg.footer.dom.style.display = 'none';
33033 dlg.footer.dom.style.display = '';
33034 for(var k in buttons){
33035 if(typeof buttons[k] != "function"){
33038 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33039 width += buttons[k].el.getWidth()+15;
33049 var handleEsc = function(d, k, e){
33050 if(opt && opt.closable !== false){
33060 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33061 * @return {Roo.BasicDialog} The BasicDialog element
33063 getDialog : function(){
33065 dlg = new Roo.BasicDialog("x-msg-box", {
33070 constraintoviewport:false,
33072 collapsible : false,
33075 width:400, height:100,
33076 buttonAlign:"center",
33077 closeClick : function(){
33078 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33079 handleButton("no");
33081 handleButton("cancel");
33085 dlg.on("hide", handleHide);
33087 dlg.addKeyListener(27, handleEsc);
33089 var bt = this.buttonText;
33090 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33091 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33092 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33093 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33094 bodyEl = dlg.body.createChild({
33096 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>'
33098 msgEl = bodyEl.dom.firstChild;
33099 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33100 textboxEl.enableDisplayMode();
33101 textboxEl.addKeyListener([10,13], function(){
33102 if(dlg.isVisible() && opt && opt.buttons){
33103 if(opt.buttons.ok){
33104 handleButton("ok");
33105 }else if(opt.buttons.yes){
33106 handleButton("yes");
33110 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33111 textareaEl.enableDisplayMode();
33112 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33113 progressEl.enableDisplayMode();
33114 var pf = progressEl.dom.firstChild;
33116 pp = Roo.get(pf.firstChild);
33117 pp.setHeight(pf.offsetHeight);
33125 * Updates the message box body text
33126 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33127 * the XHTML-compliant non-breaking space character '&#160;')
33128 * @return {Roo.MessageBox} This message box
33130 updateText : function(text){
33131 if(!dlg.isVisible() && !opt.width){
33132 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33134 msgEl.innerHTML = text || ' ';
33136 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33137 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33139 Math.min(opt.width || cw , this.maxWidth),
33140 Math.max(opt.minWidth || this.minWidth, bwidth)
33143 activeTextEl.setWidth(w);
33145 if(dlg.isVisible()){
33146 dlg.fixedcenter = false;
33148 // to big, make it scroll. = But as usual stupid IE does not support
33151 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33152 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33153 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33155 bodyEl.dom.style.height = '';
33156 bodyEl.dom.style.overflowY = '';
33159 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33161 bodyEl.dom.style.overflowX = '';
33164 dlg.setContentSize(w, bodyEl.getHeight());
33165 if(dlg.isVisible()){
33166 dlg.fixedcenter = true;
33172 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33173 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33174 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33175 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33176 * @return {Roo.MessageBox} This message box
33178 updateProgress : function(value, text){
33180 this.updateText(text);
33182 if (pp) { // weird bug on my firefox - for some reason this is not defined
33183 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33189 * Returns true if the message box is currently displayed
33190 * @return {Boolean} True if the message box is visible, else false
33192 isVisible : function(){
33193 return dlg && dlg.isVisible();
33197 * Hides the message box if it is displayed
33200 if(this.isVisible()){
33206 * Displays a new message box, or reinitializes an existing message box, based on the config options
33207 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33208 * The following config object properties are supported:
33210 Property Type Description
33211 ---------- --------------- ------------------------------------------------------------------------------------
33212 animEl String/Element An id or Element from which the message box should animate as it opens and
33213 closes (defaults to undefined)
33214 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33215 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33216 closable Boolean False to hide the top-right close button (defaults to true). Note that
33217 progress and wait dialogs will ignore this property and always hide the
33218 close button as they can only be closed programmatically.
33219 cls String A custom CSS class to apply to the message box element
33220 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33221 displayed (defaults to 75)
33222 fn Function A callback function to execute after closing the dialog. The arguments to the
33223 function will be btn (the name of the button that was clicked, if applicable,
33224 e.g. "ok"), and text (the value of the active text field, if applicable).
33225 Progress and wait dialogs will ignore this option since they do not respond to
33226 user actions and can only be closed programmatically, so any required function
33227 should be called by the same code after it closes the dialog.
33228 icon String A CSS class that provides a background image to be used as an icon for
33229 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33230 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33231 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33232 modal Boolean False to allow user interaction with the page while the message box is
33233 displayed (defaults to true)
33234 msg String A string that will replace the existing message box body text (defaults
33235 to the XHTML-compliant non-breaking space character ' ')
33236 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33237 progress Boolean True to display a progress bar (defaults to false)
33238 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33239 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33240 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33241 title String The title text
33242 value String The string value to set into the active textbox element if displayed
33243 wait Boolean True to display a progress bar (defaults to false)
33244 width Number The width of the dialog in pixels
33251 msg: 'Please enter your address:',
33253 buttons: Roo.MessageBox.OKCANCEL,
33256 animEl: 'addAddressBtn'
33259 * @param {Object} config Configuration options
33260 * @return {Roo.MessageBox} This message box
33262 show : function(options)
33265 // this causes nightmares if you show one dialog after another
33266 // especially on callbacks..
33268 if(this.isVisible()){
33271 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33272 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33273 Roo.log("New Dialog Message:" + options.msg )
33274 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33275 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33278 var d = this.getDialog();
33280 d.setTitle(opt.title || " ");
33281 d.close.setDisplayed(opt.closable !== false);
33282 activeTextEl = textboxEl;
33283 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33288 textareaEl.setHeight(typeof opt.multiline == "number" ?
33289 opt.multiline : this.defaultTextHeight);
33290 activeTextEl = textareaEl;
33299 progressEl.setDisplayed(opt.progress === true);
33300 this.updateProgress(0);
33301 activeTextEl.dom.value = opt.value || "";
33303 dlg.setDefaultButton(activeTextEl);
33305 var bs = opt.buttons;
33308 db = buttons["ok"];
33309 }else if(bs && bs.yes){
33310 db = buttons["yes"];
33312 dlg.setDefaultButton(db);
33314 bwidth = updateButtons(opt.buttons);
33315 this.updateText(opt.msg);
33317 d.el.addClass(opt.cls);
33319 d.proxyDrag = opt.proxyDrag === true;
33320 d.modal = opt.modal !== false;
33321 d.mask = opt.modal !== false ? mask : false;
33322 if(!d.isVisible()){
33323 // force it to the end of the z-index stack so it gets a cursor in FF
33324 document.body.appendChild(dlg.el.dom);
33325 d.animateTarget = null;
33326 d.show(options.animEl);
33332 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33333 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33334 * and closing the message box when the process is complete.
33335 * @param {String} title The title bar text
33336 * @param {String} msg The message box body text
33337 * @return {Roo.MessageBox} This message box
33339 progress : function(title, msg){
33346 minWidth: this.minProgressWidth,
33353 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33354 * If a callback function is passed it will be called after the user clicks the button, and the
33355 * id of the button that was clicked will be passed as the only parameter to the callback
33356 * (could also be the top-right close button).
33357 * @param {String} title The title bar text
33358 * @param {String} msg The message box body text
33359 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33360 * @param {Object} scope (optional) The scope of the callback function
33361 * @return {Roo.MessageBox} This message box
33363 alert : function(title, msg, fn, scope){
33376 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33377 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33378 * You are responsible for closing the message box when the process is complete.
33379 * @param {String} msg The message box body text
33380 * @param {String} title (optional) The title bar text
33381 * @return {Roo.MessageBox} This message box
33383 wait : function(msg, title){
33394 waitTimer = Roo.TaskMgr.start({
33396 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33404 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33405 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33406 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33407 * @param {String} title The title bar text
33408 * @param {String} msg The message box body text
33409 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33410 * @param {Object} scope (optional) The scope of the callback function
33411 * @return {Roo.MessageBox} This message box
33413 confirm : function(title, msg, fn, scope){
33417 buttons: this.YESNO,
33426 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33427 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33428 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33429 * (could also be the top-right close button) and the text that was entered will be passed as the two
33430 * parameters to the callback.
33431 * @param {String} title The title bar text
33432 * @param {String} msg The message box body text
33433 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33434 * @param {Object} scope (optional) The scope of the callback function
33435 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33436 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33437 * @return {Roo.MessageBox} This message box
33439 prompt : function(title, msg, fn, scope, multiline){
33443 buttons: this.OKCANCEL,
33448 multiline: multiline,
33455 * Button config that displays a single OK button
33460 * Button config that displays Yes and No buttons
33463 YESNO : {yes:true, no:true},
33465 * Button config that displays OK and Cancel buttons
33468 OKCANCEL : {ok:true, cancel:true},
33470 * Button config that displays Yes, No and Cancel buttons
33473 YESNOCANCEL : {yes:true, no:true, cancel:true},
33476 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33479 defaultTextHeight : 75,
33481 * The maximum width in pixels of the message box (defaults to 600)
33486 * The minimum width in pixels of the message box (defaults to 100)
33491 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33492 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33495 minProgressWidth : 250,
33497 * An object containing the default button text strings that can be overriden for localized language support.
33498 * Supported properties are: ok, cancel, yes and no.
33499 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33512 * Shorthand for {@link Roo.MessageBox}
33514 Roo.Msg = Roo.MessageBox;/*
33516 * Ext JS Library 1.1.1
33517 * Copyright(c) 2006-2007, Ext JS, LLC.
33519 * Originally Released Under LGPL - original licence link has changed is not relivant.
33522 * <script type="text/javascript">
33525 * @class Roo.QuickTips
33526 * Provides attractive and customizable tooltips for any element.
33529 Roo.QuickTips = function(){
33530 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33531 var ce, bd, xy, dd;
33532 var visible = false, disabled = true, inited = false;
33533 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33535 var onOver = function(e){
33539 var t = e.getTarget();
33540 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33543 if(ce && t == ce.el){
33544 clearTimeout(hideProc);
33547 if(t && tagEls[t.id]){
33548 tagEls[t.id].el = t;
33549 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33552 var ttp, et = Roo.fly(t);
33553 var ns = cfg.namespace;
33554 if(tm.interceptTitles && t.title){
33557 t.removeAttribute("title");
33558 e.preventDefault();
33560 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33563 showProc = show.defer(tm.showDelay, tm, [{
33566 width: et.getAttributeNS(ns, cfg.width),
33567 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33568 title: et.getAttributeNS(ns, cfg.title),
33569 cls: et.getAttributeNS(ns, cfg.cls)
33574 var onOut = function(e){
33575 clearTimeout(showProc);
33576 var t = e.getTarget();
33577 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33578 hideProc = setTimeout(hide, tm.hideDelay);
33582 var onMove = function(e){
33588 if(tm.trackMouse && ce){
33593 var onDown = function(e){
33594 clearTimeout(showProc);
33595 clearTimeout(hideProc);
33597 if(tm.hideOnClick){
33600 tm.enable.defer(100, tm);
33605 var getPad = function(){
33606 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33609 var show = function(o){
33613 clearTimeout(dismissProc);
33615 if(removeCls){ // in case manually hidden
33616 el.removeClass(removeCls);
33620 el.addClass(ce.cls);
33621 removeCls = ce.cls;
33624 tipTitle.update(ce.title);
33627 tipTitle.update('');
33630 el.dom.style.width = tm.maxWidth+'px';
33631 //tipBody.dom.style.width = '';
33632 tipBodyText.update(o.text);
33633 var p = getPad(), w = ce.width;
33635 var td = tipBodyText.dom;
33636 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33637 if(aw > tm.maxWidth){
33639 }else if(aw < tm.minWidth){
33645 //tipBody.setWidth(w);
33646 el.setWidth(parseInt(w, 10) + p);
33647 if(ce.autoHide === false){
33648 close.setDisplayed(true);
33653 close.setDisplayed(false);
33659 el.avoidY = xy[1]-18;
33664 el.setStyle("visibility", "visible");
33665 el.fadeIn({callback: afterShow});
33671 var afterShow = function(){
33675 if(tm.autoDismiss && ce.autoHide !== false){
33676 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33681 var hide = function(noanim){
33682 clearTimeout(dismissProc);
33683 clearTimeout(hideProc);
33685 if(el.isVisible()){
33687 if(noanim !== true && tm.animate){
33688 el.fadeOut({callback: afterHide});
33695 var afterHide = function(){
33698 el.removeClass(removeCls);
33705 * @cfg {Number} minWidth
33706 * The minimum width of the quick tip (defaults to 40)
33710 * @cfg {Number} maxWidth
33711 * The maximum width of the quick tip (defaults to 300)
33715 * @cfg {Boolean} interceptTitles
33716 * True to automatically use the element's DOM title value if available (defaults to false)
33718 interceptTitles : false,
33720 * @cfg {Boolean} trackMouse
33721 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33723 trackMouse : false,
33725 * @cfg {Boolean} hideOnClick
33726 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33728 hideOnClick : true,
33730 * @cfg {Number} showDelay
33731 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33735 * @cfg {Number} hideDelay
33736 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33740 * @cfg {Boolean} autoHide
33741 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33742 * Used in conjunction with hideDelay.
33747 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33748 * (defaults to true). Used in conjunction with autoDismissDelay.
33750 autoDismiss : true,
33753 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33755 autoDismissDelay : 5000,
33757 * @cfg {Boolean} animate
33758 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33763 * @cfg {String} title
33764 * Title text to display (defaults to ''). This can be any valid HTML markup.
33768 * @cfg {String} text
33769 * Body text to display (defaults to ''). This can be any valid HTML markup.
33773 * @cfg {String} cls
33774 * A CSS class to apply to the base quick tip element (defaults to '').
33778 * @cfg {Number} width
33779 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33780 * minWidth or maxWidth.
33785 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33786 * or display QuickTips in a page.
33789 tm = Roo.QuickTips;
33790 cfg = tm.tagConfig;
33792 if(!Roo.isReady){ // allow calling of init() before onReady
33793 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33796 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33797 el.fxDefaults = {stopFx: true};
33798 // maximum custom styling
33799 //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>');
33800 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>');
33801 tipTitle = el.child('h3');
33802 tipTitle.enableDisplayMode("block");
33803 tipBody = el.child('div.x-tip-bd');
33804 tipBodyText = el.child('div.x-tip-bd-inner');
33805 //bdLeft = el.child('div.x-tip-bd-left');
33806 //bdRight = el.child('div.x-tip-bd-right');
33807 close = el.child('div.x-tip-close');
33808 close.enableDisplayMode("block");
33809 close.on("click", hide);
33810 var d = Roo.get(document);
33811 d.on("mousedown", onDown);
33812 d.on("mouseover", onOver);
33813 d.on("mouseout", onOut);
33814 d.on("mousemove", onMove);
33815 esc = d.addKeyListener(27, hide);
33818 dd = el.initDD("default", null, {
33819 onDrag : function(){
33823 dd.setHandleElId(tipTitle.id);
33832 * Configures a new quick tip instance and assigns it to a target element. The following config options
33835 Property Type Description
33836 ---------- --------------------- ------------------------------------------------------------------------
33837 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33839 * @param {Object} config The config object
33841 register : function(config){
33842 var cs = config instanceof Array ? config : arguments;
33843 for(var i = 0, len = cs.length; i < len; i++) {
33845 var target = c.target;
33847 if(target instanceof Array){
33848 for(var j = 0, jlen = target.length; j < jlen; j++){
33849 tagEls[target[j]] = c;
33852 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33859 * Removes this quick tip from its element and destroys it.
33860 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33862 unregister : function(el){
33863 delete tagEls[Roo.id(el)];
33867 * Enable this quick tip.
33869 enable : function(){
33870 if(inited && disabled){
33872 if(locks.length < 1){
33879 * Disable this quick tip.
33881 disable : function(){
33883 clearTimeout(showProc);
33884 clearTimeout(hideProc);
33885 clearTimeout(dismissProc);
33893 * Returns true if the quick tip is enabled, else false.
33895 isEnabled : function(){
33901 namespace : "roo", // was ext?? this may break..
33902 alt_namespace : "ext",
33903 attribute : "qtip",
33913 // backwards compat
33914 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33916 * Ext JS Library 1.1.1
33917 * Copyright(c) 2006-2007, Ext JS, LLC.
33919 * Originally Released Under LGPL - original licence link has changed is not relivant.
33922 * <script type="text/javascript">
33927 * @class Roo.tree.TreePanel
33928 * @extends Roo.data.Tree
33930 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33931 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33932 * @cfg {Boolean} enableDD true to enable drag and drop
33933 * @cfg {Boolean} enableDrag true to enable just drag
33934 * @cfg {Boolean} enableDrop true to enable just drop
33935 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33936 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33937 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33938 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33939 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33940 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33941 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33942 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33943 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33944 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33945 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33946 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33947 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33948 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33949 * @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>
33950 * @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>
33953 * @param {String/HTMLElement/Element} el The container element
33954 * @param {Object} config
33956 Roo.tree.TreePanel = function(el, config){
33958 var loader = false;
33960 root = config.root;
33961 delete config.root;
33963 if (config.loader) {
33964 loader = config.loader;
33965 delete config.loader;
33968 Roo.apply(this, config);
33969 Roo.tree.TreePanel.superclass.constructor.call(this);
33970 this.el = Roo.get(el);
33971 this.el.addClass('x-tree');
33972 //console.log(root);
33974 this.setRootNode( Roo.factory(root, Roo.tree));
33977 this.loader = Roo.factory(loader, Roo.tree);
33980 * Read-only. The id of the container element becomes this TreePanel's id.
33982 this.id = this.el.id;
33985 * @event beforeload
33986 * Fires before a node is loaded, return false to cancel
33987 * @param {Node} node The node being loaded
33989 "beforeload" : true,
33992 * Fires when a node is loaded
33993 * @param {Node} node The node that was loaded
33997 * @event textchange
33998 * Fires when the text for a node is changed
33999 * @param {Node} node The node
34000 * @param {String} text The new text
34001 * @param {String} oldText The old text
34003 "textchange" : true,
34005 * @event beforeexpand
34006 * Fires before a node is expanded, return false to cancel.
34007 * @param {Node} node The node
34008 * @param {Boolean} deep
34009 * @param {Boolean} anim
34011 "beforeexpand" : true,
34013 * @event beforecollapse
34014 * Fires before a node is collapsed, return false to cancel.
34015 * @param {Node} node The node
34016 * @param {Boolean} deep
34017 * @param {Boolean} anim
34019 "beforecollapse" : true,
34022 * Fires when a node is expanded
34023 * @param {Node} node The node
34027 * @event disabledchange
34028 * Fires when the disabled status of a node changes
34029 * @param {Node} node The node
34030 * @param {Boolean} disabled
34032 "disabledchange" : true,
34035 * Fires when a node is collapsed
34036 * @param {Node} node The node
34040 * @event beforeclick
34041 * Fires before click processing on a node. Return false to cancel the default action.
34042 * @param {Node} node The node
34043 * @param {Roo.EventObject} e The event object
34045 "beforeclick":true,
34047 * @event checkchange
34048 * Fires when a node with a checkbox's checked property changes
34049 * @param {Node} this This node
34050 * @param {Boolean} checked
34052 "checkchange":true,
34055 * Fires when a node is clicked
34056 * @param {Node} node The node
34057 * @param {Roo.EventObject} e The event object
34062 * Fires when a node is double clicked
34063 * @param {Node} node The node
34064 * @param {Roo.EventObject} e The event object
34068 * @event contextmenu
34069 * Fires when a node is right clicked
34070 * @param {Node} node The node
34071 * @param {Roo.EventObject} e The event object
34073 "contextmenu":true,
34075 * @event beforechildrenrendered
34076 * Fires right before the child nodes for a node are rendered
34077 * @param {Node} node The node
34079 "beforechildrenrendered":true,
34082 * Fires when a node starts being dragged
34083 * @param {Roo.tree.TreePanel} this
34084 * @param {Roo.tree.TreeNode} node
34085 * @param {event} e The raw browser event
34087 "startdrag" : true,
34090 * Fires when a drag operation is complete
34091 * @param {Roo.tree.TreePanel} this
34092 * @param {Roo.tree.TreeNode} node
34093 * @param {event} e The raw browser event
34098 * Fires when a dragged node is dropped on a valid DD target
34099 * @param {Roo.tree.TreePanel} this
34100 * @param {Roo.tree.TreeNode} node
34101 * @param {DD} dd The dd it was dropped on
34102 * @param {event} e The raw browser event
34106 * @event beforenodedrop
34107 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34108 * passed to handlers has the following properties:<br />
34109 * <ul style="padding:5px;padding-left:16px;">
34110 * <li>tree - The TreePanel</li>
34111 * <li>target - The node being targeted for the drop</li>
34112 * <li>data - The drag data from the drag source</li>
34113 * <li>point - The point of the drop - append, above or below</li>
34114 * <li>source - The drag source</li>
34115 * <li>rawEvent - Raw mouse event</li>
34116 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34117 * to be inserted by setting them on this object.</li>
34118 * <li>cancel - Set this to true to cancel the drop.</li>
34120 * @param {Object} dropEvent
34122 "beforenodedrop" : true,
34125 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34126 * passed to handlers has the following properties:<br />
34127 * <ul style="padding:5px;padding-left:16px;">
34128 * <li>tree - The TreePanel</li>
34129 * <li>target - The node being targeted for the drop</li>
34130 * <li>data - The drag data from the drag source</li>
34131 * <li>point - The point of the drop - append, above or below</li>
34132 * <li>source - The drag source</li>
34133 * <li>rawEvent - Raw mouse event</li>
34134 * <li>dropNode - Dropped node(s).</li>
34136 * @param {Object} dropEvent
34140 * @event nodedragover
34141 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34142 * passed to handlers has the following properties:<br />
34143 * <ul style="padding:5px;padding-left:16px;">
34144 * <li>tree - The TreePanel</li>
34145 * <li>target - The node being targeted for the drop</li>
34146 * <li>data - The drag data from the drag source</li>
34147 * <li>point - The point of the drop - append, above or below</li>
34148 * <li>source - The drag source</li>
34149 * <li>rawEvent - Raw mouse event</li>
34150 * <li>dropNode - Drop node(s) provided by the source.</li>
34151 * <li>cancel - Set this to true to signal drop not allowed.</li>
34153 * @param {Object} dragOverEvent
34155 "nodedragover" : true
34158 if(this.singleExpand){
34159 this.on("beforeexpand", this.restrictExpand, this);
34162 this.editor.tree = this;
34163 this.editor = Roo.factory(this.editor, Roo.tree);
34166 if (this.selModel) {
34167 this.selModel = Roo.factory(this.selModel, Roo.tree);
34171 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34172 rootVisible : true,
34173 animate: Roo.enableFx,
34176 hlDrop : Roo.enableFx,
34180 rendererTip: false,
34182 restrictExpand : function(node){
34183 var p = node.parentNode;
34185 if(p.expandedChild && p.expandedChild.parentNode == p){
34186 p.expandedChild.collapse();
34188 p.expandedChild = node;
34192 // private override
34193 setRootNode : function(node){
34194 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34195 if(!this.rootVisible){
34196 node.ui = new Roo.tree.RootTreeNodeUI(node);
34202 * Returns the container element for this TreePanel
34204 getEl : function(){
34209 * Returns the default TreeLoader for this TreePanel
34211 getLoader : function(){
34212 return this.loader;
34218 expandAll : function(){
34219 this.root.expand(true);
34223 * Collapse all nodes
34225 collapseAll : function(){
34226 this.root.collapse(true);
34230 * Returns the selection model used by this TreePanel
34232 getSelectionModel : function(){
34233 if(!this.selModel){
34234 this.selModel = new Roo.tree.DefaultSelectionModel();
34236 return this.selModel;
34240 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34241 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34242 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34245 getChecked : function(a, startNode){
34246 startNode = startNode || this.root;
34248 var f = function(){
34249 if(this.attributes.checked){
34250 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34253 startNode.cascade(f);
34258 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34259 * @param {String} path
34260 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34261 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34262 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34264 expandPath : function(path, attr, callback){
34265 attr = attr || "id";
34266 var keys = path.split(this.pathSeparator);
34267 var curNode = this.root;
34268 if(curNode.attributes[attr] != keys[1]){ // invalid root
34270 callback(false, null);
34275 var f = function(){
34276 if(++index == keys.length){
34278 callback(true, curNode);
34282 var c = curNode.findChild(attr, keys[index]);
34285 callback(false, curNode);
34290 c.expand(false, false, f);
34292 curNode.expand(false, false, f);
34296 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34297 * @param {String} path
34298 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34299 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34300 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34302 selectPath : function(path, attr, callback){
34303 attr = attr || "id";
34304 var keys = path.split(this.pathSeparator);
34305 var v = keys.pop();
34306 if(keys.length > 0){
34307 var f = function(success, node){
34308 if(success && node){
34309 var n = node.findChild(attr, v);
34315 }else if(callback){
34316 callback(false, n);
34320 callback(false, n);
34324 this.expandPath(keys.join(this.pathSeparator), attr, f);
34326 this.root.select();
34328 callback(true, this.root);
34333 getTreeEl : function(){
34338 * Trigger rendering of this TreePanel
34340 render : function(){
34341 if (this.innerCt) {
34342 return this; // stop it rendering more than once!!
34345 this.innerCt = this.el.createChild({tag:"ul",
34346 cls:"x-tree-root-ct " +
34347 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34349 if(this.containerScroll){
34350 Roo.dd.ScrollManager.register(this.el);
34352 if((this.enableDD || this.enableDrop) && !this.dropZone){
34354 * The dropZone used by this tree if drop is enabled
34355 * @type Roo.tree.TreeDropZone
34357 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34358 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34361 if((this.enableDD || this.enableDrag) && !this.dragZone){
34363 * The dragZone used by this tree if drag is enabled
34364 * @type Roo.tree.TreeDragZone
34366 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34367 ddGroup: this.ddGroup || "TreeDD",
34368 scroll: this.ddScroll
34371 this.getSelectionModel().init(this);
34373 Roo.log("ROOT not set in tree");
34376 this.root.render();
34377 if(!this.rootVisible){
34378 this.root.renderChildren();
34384 * Ext JS Library 1.1.1
34385 * Copyright(c) 2006-2007, Ext JS, LLC.
34387 * Originally Released Under LGPL - original licence link has changed is not relivant.
34390 * <script type="text/javascript">
34395 * @class Roo.tree.DefaultSelectionModel
34396 * @extends Roo.util.Observable
34397 * The default single selection for a TreePanel.
34398 * @param {Object} cfg Configuration
34400 Roo.tree.DefaultSelectionModel = function(cfg){
34401 this.selNode = null;
34407 * @event selectionchange
34408 * Fires when the selected node changes
34409 * @param {DefaultSelectionModel} this
34410 * @param {TreeNode} node the new selection
34412 "selectionchange" : true,
34415 * @event beforeselect
34416 * Fires before the selected node changes, return false to cancel the change
34417 * @param {DefaultSelectionModel} this
34418 * @param {TreeNode} node the new selection
34419 * @param {TreeNode} node the old selection
34421 "beforeselect" : true
34424 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34427 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34428 init : function(tree){
34430 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34431 tree.on("click", this.onNodeClick, this);
34434 onNodeClick : function(node, e){
34435 if (e.ctrlKey && this.selNode == node) {
34436 this.unselect(node);
34444 * @param {TreeNode} node The node to select
34445 * @return {TreeNode} The selected node
34447 select : function(node){
34448 var last = this.selNode;
34449 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34451 last.ui.onSelectedChange(false);
34453 this.selNode = node;
34454 node.ui.onSelectedChange(true);
34455 this.fireEvent("selectionchange", this, node, last);
34462 * @param {TreeNode} node The node to unselect
34464 unselect : function(node){
34465 if(this.selNode == node){
34466 this.clearSelections();
34471 * Clear all selections
34473 clearSelections : function(){
34474 var n = this.selNode;
34476 n.ui.onSelectedChange(false);
34477 this.selNode = null;
34478 this.fireEvent("selectionchange", this, null);
34484 * Get the selected node
34485 * @return {TreeNode} The selected node
34487 getSelectedNode : function(){
34488 return this.selNode;
34492 * Returns true if the node is selected
34493 * @param {TreeNode} node The node to check
34494 * @return {Boolean}
34496 isSelected : function(node){
34497 return this.selNode == node;
34501 * Selects the node above the selected node in the tree, intelligently walking the nodes
34502 * @return TreeNode The new selection
34504 selectPrevious : function(){
34505 var s = this.selNode || this.lastSelNode;
34509 var ps = s.previousSibling;
34511 if(!ps.isExpanded() || ps.childNodes.length < 1){
34512 return this.select(ps);
34514 var lc = ps.lastChild;
34515 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34518 return this.select(lc);
34520 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34521 return this.select(s.parentNode);
34527 * Selects the node above the selected node in the tree, intelligently walking the nodes
34528 * @return TreeNode The new selection
34530 selectNext : function(){
34531 var s = this.selNode || this.lastSelNode;
34535 if(s.firstChild && s.isExpanded()){
34536 return this.select(s.firstChild);
34537 }else if(s.nextSibling){
34538 return this.select(s.nextSibling);
34539 }else if(s.parentNode){
34541 s.parentNode.bubble(function(){
34542 if(this.nextSibling){
34543 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34552 onKeyDown : function(e){
34553 var s = this.selNode || this.lastSelNode;
34554 // undesirable, but required
34559 var k = e.getKey();
34567 this.selectPrevious();
34570 e.preventDefault();
34571 if(s.hasChildNodes()){
34572 if(!s.isExpanded()){
34574 }else if(s.firstChild){
34575 this.select(s.firstChild, e);
34580 e.preventDefault();
34581 if(s.hasChildNodes() && s.isExpanded()){
34583 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34584 this.select(s.parentNode, e);
34592 * @class Roo.tree.MultiSelectionModel
34593 * @extends Roo.util.Observable
34594 * Multi selection for a TreePanel.
34595 * @param {Object} cfg Configuration
34597 Roo.tree.MultiSelectionModel = function(){
34598 this.selNodes = [];
34602 * @event selectionchange
34603 * Fires when the selected nodes change
34604 * @param {MultiSelectionModel} this
34605 * @param {Array} nodes Array of the selected nodes
34607 "selectionchange" : true
34609 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34613 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34614 init : function(tree){
34616 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34617 tree.on("click", this.onNodeClick, this);
34620 onNodeClick : function(node, e){
34621 this.select(node, e, e.ctrlKey);
34626 * @param {TreeNode} node The node to select
34627 * @param {EventObject} e (optional) An event associated with the selection
34628 * @param {Boolean} keepExisting True to retain existing selections
34629 * @return {TreeNode} The selected node
34631 select : function(node, e, keepExisting){
34632 if(keepExisting !== true){
34633 this.clearSelections(true);
34635 if(this.isSelected(node)){
34636 this.lastSelNode = node;
34639 this.selNodes.push(node);
34640 this.selMap[node.id] = node;
34641 this.lastSelNode = node;
34642 node.ui.onSelectedChange(true);
34643 this.fireEvent("selectionchange", this, this.selNodes);
34649 * @param {TreeNode} node The node to unselect
34651 unselect : function(node){
34652 if(this.selMap[node.id]){
34653 node.ui.onSelectedChange(false);
34654 var sn = this.selNodes;
34657 index = sn.indexOf(node);
34659 for(var i = 0, len = sn.length; i < len; i++){
34667 this.selNodes.splice(index, 1);
34669 delete this.selMap[node.id];
34670 this.fireEvent("selectionchange", this, this.selNodes);
34675 * Clear all selections
34677 clearSelections : function(suppressEvent){
34678 var sn = this.selNodes;
34680 for(var i = 0, len = sn.length; i < len; i++){
34681 sn[i].ui.onSelectedChange(false);
34683 this.selNodes = [];
34685 if(suppressEvent !== true){
34686 this.fireEvent("selectionchange", this, this.selNodes);
34692 * Returns true if the node is selected
34693 * @param {TreeNode} node The node to check
34694 * @return {Boolean}
34696 isSelected : function(node){
34697 return this.selMap[node.id] ? true : false;
34701 * Returns an array of the selected nodes
34704 getSelectedNodes : function(){
34705 return this.selNodes;
34708 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34710 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34712 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34715 * Ext JS Library 1.1.1
34716 * Copyright(c) 2006-2007, Ext JS, LLC.
34718 * Originally Released Under LGPL - original licence link has changed is not relivant.
34721 * <script type="text/javascript">
34725 * @class Roo.tree.TreeNode
34726 * @extends Roo.data.Node
34727 * @cfg {String} text The text for this node
34728 * @cfg {Boolean} expanded true to start the node expanded
34729 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34730 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34731 * @cfg {Boolean} disabled true to start the node disabled
34732 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34733 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34734 * @cfg {String} cls A css class to be added to the node
34735 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34736 * @cfg {String} href URL of the link used for the node (defaults to #)
34737 * @cfg {String} hrefTarget target frame for the link
34738 * @cfg {String} qtip An Ext QuickTip for the node
34739 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34740 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34741 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34742 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34743 * (defaults to undefined with no checkbox rendered)
34745 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34747 Roo.tree.TreeNode = function(attributes){
34748 attributes = attributes || {};
34749 if(typeof attributes == "string"){
34750 attributes = {text: attributes};
34752 this.childrenRendered = false;
34753 this.rendered = false;
34754 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34755 this.expanded = attributes.expanded === true;
34756 this.isTarget = attributes.isTarget !== false;
34757 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34758 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34761 * Read-only. The text for this node. To change it use setText().
34764 this.text = attributes.text;
34766 * True if this node is disabled.
34769 this.disabled = attributes.disabled === true;
34773 * @event textchange
34774 * Fires when the text for this node is changed
34775 * @param {Node} this This node
34776 * @param {String} text The new text
34777 * @param {String} oldText The old text
34779 "textchange" : true,
34781 * @event beforeexpand
34782 * Fires before this node is expanded, return false to cancel.
34783 * @param {Node} this This node
34784 * @param {Boolean} deep
34785 * @param {Boolean} anim
34787 "beforeexpand" : true,
34789 * @event beforecollapse
34790 * Fires before this node is collapsed, return false to cancel.
34791 * @param {Node} this This node
34792 * @param {Boolean} deep
34793 * @param {Boolean} anim
34795 "beforecollapse" : true,
34798 * Fires when this node is expanded
34799 * @param {Node} this This node
34803 * @event disabledchange
34804 * Fires when the disabled status of this node changes
34805 * @param {Node} this This node
34806 * @param {Boolean} disabled
34808 "disabledchange" : true,
34811 * Fires when this node is collapsed
34812 * @param {Node} this This node
34816 * @event beforeclick
34817 * Fires before click processing. Return false to cancel the default action.
34818 * @param {Node} this This node
34819 * @param {Roo.EventObject} e The event object
34821 "beforeclick":true,
34823 * @event checkchange
34824 * Fires when a node with a checkbox's checked property changes
34825 * @param {Node} this This node
34826 * @param {Boolean} checked
34828 "checkchange":true,
34831 * Fires when this node is clicked
34832 * @param {Node} this This node
34833 * @param {Roo.EventObject} e The event object
34838 * Fires when this node is double clicked
34839 * @param {Node} this This node
34840 * @param {Roo.EventObject} e The event object
34844 * @event contextmenu
34845 * Fires when this node is right clicked
34846 * @param {Node} this This node
34847 * @param {Roo.EventObject} e The event object
34849 "contextmenu":true,
34851 * @event beforechildrenrendered
34852 * Fires right before the child nodes for this node are rendered
34853 * @param {Node} this This node
34855 "beforechildrenrendered":true
34858 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34861 * Read-only. The UI for this node
34864 this.ui = new uiClass(this);
34866 // finally support items[]
34867 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34872 Roo.each(this.attributes.items, function(c) {
34873 this.appendChild(Roo.factory(c,Roo.Tree));
34875 delete this.attributes.items;
34880 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34881 preventHScroll: true,
34883 * Returns true if this node is expanded
34884 * @return {Boolean}
34886 isExpanded : function(){
34887 return this.expanded;
34891 * Returns the UI object for this node
34892 * @return {TreeNodeUI}
34894 getUI : function(){
34898 // private override
34899 setFirstChild : function(node){
34900 var of = this.firstChild;
34901 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34902 if(this.childrenRendered && of && node != of){
34903 of.renderIndent(true, true);
34906 this.renderIndent(true, true);
34910 // private override
34911 setLastChild : function(node){
34912 var ol = this.lastChild;
34913 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34914 if(this.childrenRendered && ol && node != ol){
34915 ol.renderIndent(true, true);
34918 this.renderIndent(true, true);
34922 // these methods are overridden to provide lazy rendering support
34923 // private override
34924 appendChild : function()
34926 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34927 if(node && this.childrenRendered){
34930 this.ui.updateExpandIcon();
34934 // private override
34935 removeChild : function(node){
34936 this.ownerTree.getSelectionModel().unselect(node);
34937 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34938 // if it's been rendered remove dom node
34939 if(this.childrenRendered){
34942 if(this.childNodes.length < 1){
34943 this.collapse(false, false);
34945 this.ui.updateExpandIcon();
34947 if(!this.firstChild) {
34948 this.childrenRendered = false;
34953 // private override
34954 insertBefore : function(node, refNode){
34955 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34956 if(newNode && refNode && this.childrenRendered){
34959 this.ui.updateExpandIcon();
34964 * Sets the text for this node
34965 * @param {String} text
34967 setText : function(text){
34968 var oldText = this.text;
34970 this.attributes.text = text;
34971 if(this.rendered){ // event without subscribing
34972 this.ui.onTextChange(this, text, oldText);
34974 this.fireEvent("textchange", this, text, oldText);
34978 * Triggers selection of this node
34980 select : function(){
34981 this.getOwnerTree().getSelectionModel().select(this);
34985 * Triggers deselection of this node
34987 unselect : function(){
34988 this.getOwnerTree().getSelectionModel().unselect(this);
34992 * Returns true if this node is selected
34993 * @return {Boolean}
34995 isSelected : function(){
34996 return this.getOwnerTree().getSelectionModel().isSelected(this);
35000 * Expand this node.
35001 * @param {Boolean} deep (optional) True to expand all children as well
35002 * @param {Boolean} anim (optional) false to cancel the default animation
35003 * @param {Function} callback (optional) A callback to be called when
35004 * expanding this node completes (does not wait for deep expand to complete).
35005 * Called with 1 parameter, this node.
35007 expand : function(deep, anim, callback){
35008 if(!this.expanded){
35009 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35012 if(!this.childrenRendered){
35013 this.renderChildren();
35015 this.expanded = true;
35016 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35017 this.ui.animExpand(function(){
35018 this.fireEvent("expand", this);
35019 if(typeof callback == "function"){
35023 this.expandChildNodes(true);
35025 }.createDelegate(this));
35029 this.fireEvent("expand", this);
35030 if(typeof callback == "function"){
35035 if(typeof callback == "function"){
35040 this.expandChildNodes(true);
35044 isHiddenRoot : function(){
35045 return this.isRoot && !this.getOwnerTree().rootVisible;
35049 * Collapse this node.
35050 * @param {Boolean} deep (optional) True to collapse all children as well
35051 * @param {Boolean} anim (optional) false to cancel the default animation
35053 collapse : function(deep, anim){
35054 if(this.expanded && !this.isHiddenRoot()){
35055 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35058 this.expanded = false;
35059 if((this.getOwnerTree().animate && anim !== false) || anim){
35060 this.ui.animCollapse(function(){
35061 this.fireEvent("collapse", this);
35063 this.collapseChildNodes(true);
35065 }.createDelegate(this));
35068 this.ui.collapse();
35069 this.fireEvent("collapse", this);
35073 var cs = this.childNodes;
35074 for(var i = 0, len = cs.length; i < len; i++) {
35075 cs[i].collapse(true, false);
35081 delayedExpand : function(delay){
35082 if(!this.expandProcId){
35083 this.expandProcId = this.expand.defer(delay, this);
35088 cancelExpand : function(){
35089 if(this.expandProcId){
35090 clearTimeout(this.expandProcId);
35092 this.expandProcId = false;
35096 * Toggles expanded/collapsed state of the node
35098 toggle : function(){
35107 * Ensures all parent nodes are expanded
35109 ensureVisible : function(callback){
35110 var tree = this.getOwnerTree();
35111 tree.expandPath(this.parentNode.getPath(), false, function(){
35112 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35113 Roo.callback(callback);
35114 }.createDelegate(this));
35118 * Expand all child nodes
35119 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35121 expandChildNodes : function(deep){
35122 var cs = this.childNodes;
35123 for(var i = 0, len = cs.length; i < len; i++) {
35124 cs[i].expand(deep);
35129 * Collapse all child nodes
35130 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35132 collapseChildNodes : function(deep){
35133 var cs = this.childNodes;
35134 for(var i = 0, len = cs.length; i < len; i++) {
35135 cs[i].collapse(deep);
35140 * Disables this node
35142 disable : function(){
35143 this.disabled = true;
35145 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35146 this.ui.onDisableChange(this, true);
35148 this.fireEvent("disabledchange", this, true);
35152 * Enables this node
35154 enable : function(){
35155 this.disabled = false;
35156 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35157 this.ui.onDisableChange(this, false);
35159 this.fireEvent("disabledchange", this, false);
35163 renderChildren : function(suppressEvent){
35164 if(suppressEvent !== false){
35165 this.fireEvent("beforechildrenrendered", this);
35167 var cs = this.childNodes;
35168 for(var i = 0, len = cs.length; i < len; i++){
35169 cs[i].render(true);
35171 this.childrenRendered = true;
35175 sort : function(fn, scope){
35176 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35177 if(this.childrenRendered){
35178 var cs = this.childNodes;
35179 for(var i = 0, len = cs.length; i < len; i++){
35180 cs[i].render(true);
35186 render : function(bulkRender){
35187 this.ui.render(bulkRender);
35188 if(!this.rendered){
35189 this.rendered = true;
35191 this.expanded = false;
35192 this.expand(false, false);
35198 renderIndent : function(deep, refresh){
35200 this.ui.childIndent = null;
35202 this.ui.renderIndent();
35203 if(deep === true && this.childrenRendered){
35204 var cs = this.childNodes;
35205 for(var i = 0, len = cs.length; i < len; i++){
35206 cs[i].renderIndent(true, refresh);
35212 * Ext JS Library 1.1.1
35213 * Copyright(c) 2006-2007, Ext JS, LLC.
35215 * Originally Released Under LGPL - original licence link has changed is not relivant.
35218 * <script type="text/javascript">
35222 * @class Roo.tree.AsyncTreeNode
35223 * @extends Roo.tree.TreeNode
35224 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35226 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35228 Roo.tree.AsyncTreeNode = function(config){
35229 this.loaded = false;
35230 this.loading = false;
35231 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35233 * @event beforeload
35234 * Fires before this node is loaded, return false to cancel
35235 * @param {Node} this This node
35237 this.addEvents({'beforeload':true, 'load': true});
35240 * Fires when this node is loaded
35241 * @param {Node} this This node
35244 * The loader used by this node (defaults to using the tree's defined loader)
35249 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35250 expand : function(deep, anim, callback){
35251 if(this.loading){ // if an async load is already running, waiting til it's done
35253 var f = function(){
35254 if(!this.loading){ // done loading
35255 clearInterval(timer);
35256 this.expand(deep, anim, callback);
35258 }.createDelegate(this);
35259 timer = setInterval(f, 200);
35263 if(this.fireEvent("beforeload", this) === false){
35266 this.loading = true;
35267 this.ui.beforeLoad(this);
35268 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35270 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35274 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35278 * Returns true if this node is currently loading
35279 * @return {Boolean}
35281 isLoading : function(){
35282 return this.loading;
35285 loadComplete : function(deep, anim, callback){
35286 this.loading = false;
35287 this.loaded = true;
35288 this.ui.afterLoad(this);
35289 this.fireEvent("load", this);
35290 this.expand(deep, anim, callback);
35294 * Returns true if this node has been loaded
35295 * @return {Boolean}
35297 isLoaded : function(){
35298 return this.loaded;
35301 hasChildNodes : function(){
35302 if(!this.isLeaf() && !this.loaded){
35305 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35310 * Trigger a reload for this node
35311 * @param {Function} callback
35313 reload : function(callback){
35314 this.collapse(false, false);
35315 while(this.firstChild){
35316 this.removeChild(this.firstChild);
35318 this.childrenRendered = false;
35319 this.loaded = false;
35320 if(this.isHiddenRoot()){
35321 this.expanded = false;
35323 this.expand(false, false, callback);
35327 * Ext JS Library 1.1.1
35328 * Copyright(c) 2006-2007, Ext JS, LLC.
35330 * Originally Released Under LGPL - original licence link has changed is not relivant.
35333 * <script type="text/javascript">
35337 * @class Roo.tree.TreeNodeUI
35339 * @param {Object} node The node to render
35340 * The TreeNode UI implementation is separate from the
35341 * tree implementation. Unless you are customizing the tree UI,
35342 * you should never have to use this directly.
35344 Roo.tree.TreeNodeUI = function(node){
35346 this.rendered = false;
35347 this.animating = false;
35348 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35351 Roo.tree.TreeNodeUI.prototype = {
35352 removeChild : function(node){
35354 this.ctNode.removeChild(node.ui.getEl());
35358 beforeLoad : function(){
35359 this.addClass("x-tree-node-loading");
35362 afterLoad : function(){
35363 this.removeClass("x-tree-node-loading");
35366 onTextChange : function(node, text, oldText){
35368 this.textNode.innerHTML = text;
35372 onDisableChange : function(node, state){
35373 this.disabled = state;
35375 this.addClass("x-tree-node-disabled");
35377 this.removeClass("x-tree-node-disabled");
35381 onSelectedChange : function(state){
35384 this.addClass("x-tree-selected");
35387 this.removeClass("x-tree-selected");
35391 onMove : function(tree, node, oldParent, newParent, index, refNode){
35392 this.childIndent = null;
35394 var targetNode = newParent.ui.getContainer();
35395 if(!targetNode){//target not rendered
35396 this.holder = document.createElement("div");
35397 this.holder.appendChild(this.wrap);
35400 var insertBefore = refNode ? refNode.ui.getEl() : null;
35402 targetNode.insertBefore(this.wrap, insertBefore);
35404 targetNode.appendChild(this.wrap);
35406 this.node.renderIndent(true);
35410 addClass : function(cls){
35412 Roo.fly(this.elNode).addClass(cls);
35416 removeClass : function(cls){
35418 Roo.fly(this.elNode).removeClass(cls);
35422 remove : function(){
35424 this.holder = document.createElement("div");
35425 this.holder.appendChild(this.wrap);
35429 fireEvent : function(){
35430 return this.node.fireEvent.apply(this.node, arguments);
35433 initEvents : function(){
35434 this.node.on("move", this.onMove, this);
35435 var E = Roo.EventManager;
35436 var a = this.anchor;
35438 var el = Roo.fly(a, '_treeui');
35440 if(Roo.isOpera){ // opera render bug ignores the CSS
35441 el.setStyle("text-decoration", "none");
35444 el.on("click", this.onClick, this);
35445 el.on("dblclick", this.onDblClick, this);
35448 Roo.EventManager.on(this.checkbox,
35449 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35452 el.on("contextmenu", this.onContextMenu, this);
35454 var icon = Roo.fly(this.iconNode);
35455 icon.on("click", this.onClick, this);
35456 icon.on("dblclick", this.onDblClick, this);
35457 icon.on("contextmenu", this.onContextMenu, this);
35458 E.on(this.ecNode, "click", this.ecClick, this, true);
35460 if(this.node.disabled){
35461 this.addClass("x-tree-node-disabled");
35463 if(this.node.hidden){
35464 this.addClass("x-tree-node-disabled");
35466 var ot = this.node.getOwnerTree();
35467 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35468 if(dd && (!this.node.isRoot || ot.rootVisible)){
35469 Roo.dd.Registry.register(this.elNode, {
35471 handles: this.getDDHandles(),
35477 getDDHandles : function(){
35478 return [this.iconNode, this.textNode];
35483 this.wrap.style.display = "none";
35489 this.wrap.style.display = "";
35493 onContextMenu : function(e){
35494 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35495 e.preventDefault();
35497 this.fireEvent("contextmenu", this.node, e);
35501 onClick : function(e){
35506 if(this.fireEvent("beforeclick", this.node, e) !== false){
35507 if(!this.disabled && this.node.attributes.href){
35508 this.fireEvent("click", this.node, e);
35511 e.preventDefault();
35516 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35517 this.node.toggle();
35520 this.fireEvent("click", this.node, e);
35526 onDblClick : function(e){
35527 e.preventDefault();
35532 this.toggleCheck();
35534 if(!this.animating && this.node.hasChildNodes()){
35535 this.node.toggle();
35537 this.fireEvent("dblclick", this.node, e);
35540 onCheckChange : function(){
35541 var checked = this.checkbox.checked;
35542 this.node.attributes.checked = checked;
35543 this.fireEvent('checkchange', this.node, checked);
35546 ecClick : function(e){
35547 if(!this.animating && this.node.hasChildNodes()){
35548 this.node.toggle();
35552 startDrop : function(){
35553 this.dropping = true;
35556 // delayed drop so the click event doesn't get fired on a drop
35557 endDrop : function(){
35558 setTimeout(function(){
35559 this.dropping = false;
35560 }.createDelegate(this), 50);
35563 expand : function(){
35564 this.updateExpandIcon();
35565 this.ctNode.style.display = "";
35568 focus : function(){
35569 if(!this.node.preventHScroll){
35570 try{this.anchor.focus();
35572 }else if(!Roo.isIE){
35574 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35575 var l = noscroll.scrollLeft;
35576 this.anchor.focus();
35577 noscroll.scrollLeft = l;
35582 toggleCheck : function(value){
35583 var cb = this.checkbox;
35585 cb.checked = (value === undefined ? !cb.checked : value);
35591 this.anchor.blur();
35595 animExpand : function(callback){
35596 var ct = Roo.get(this.ctNode);
35598 if(!this.node.hasChildNodes()){
35599 this.updateExpandIcon();
35600 this.ctNode.style.display = "";
35601 Roo.callback(callback);
35604 this.animating = true;
35605 this.updateExpandIcon();
35608 callback : function(){
35609 this.animating = false;
35610 Roo.callback(callback);
35613 duration: this.node.ownerTree.duration || .25
35617 highlight : function(){
35618 var tree = this.node.getOwnerTree();
35619 Roo.fly(this.wrap).highlight(
35620 tree.hlColor || "C3DAF9",
35621 {endColor: tree.hlBaseColor}
35625 collapse : function(){
35626 this.updateExpandIcon();
35627 this.ctNode.style.display = "none";
35630 animCollapse : function(callback){
35631 var ct = Roo.get(this.ctNode);
35632 ct.enableDisplayMode('block');
35635 this.animating = true;
35636 this.updateExpandIcon();
35639 callback : function(){
35640 this.animating = false;
35641 Roo.callback(callback);
35644 duration: this.node.ownerTree.duration || .25
35648 getContainer : function(){
35649 return this.ctNode;
35652 getEl : function(){
35656 appendDDGhost : function(ghostNode){
35657 ghostNode.appendChild(this.elNode.cloneNode(true));
35660 getDDRepairXY : function(){
35661 return Roo.lib.Dom.getXY(this.iconNode);
35664 onRender : function(){
35668 render : function(bulkRender){
35669 var n = this.node, a = n.attributes;
35670 var targetNode = n.parentNode ?
35671 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35673 if(!this.rendered){
35674 this.rendered = true;
35676 this.renderElements(n, a, targetNode, bulkRender);
35679 if(this.textNode.setAttributeNS){
35680 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35682 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35685 this.textNode.setAttribute("ext:qtip", a.qtip);
35687 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35690 }else if(a.qtipCfg){
35691 a.qtipCfg.target = Roo.id(this.textNode);
35692 Roo.QuickTips.register(a.qtipCfg);
35695 if(!this.node.expanded){
35696 this.updateExpandIcon();
35699 if(bulkRender === true) {
35700 targetNode.appendChild(this.wrap);
35705 renderElements : function(n, a, targetNode, bulkRender)
35707 // add some indent caching, this helps performance when rendering a large tree
35708 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35709 var t = n.getOwnerTree();
35710 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35711 if (typeof(n.attributes.html) != 'undefined') {
35712 txt = n.attributes.html;
35714 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35715 var cb = typeof a.checked == 'boolean';
35716 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35717 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35718 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35719 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35720 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35721 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35722 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35723 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35724 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35725 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35728 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35729 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35730 n.nextSibling.ui.getEl(), buf.join(""));
35732 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35735 this.elNode = this.wrap.childNodes[0];
35736 this.ctNode = this.wrap.childNodes[1];
35737 var cs = this.elNode.childNodes;
35738 this.indentNode = cs[0];
35739 this.ecNode = cs[1];
35740 this.iconNode = cs[2];
35743 this.checkbox = cs[3];
35746 this.anchor = cs[index];
35747 this.textNode = cs[index].firstChild;
35750 getAnchor : function(){
35751 return this.anchor;
35754 getTextEl : function(){
35755 return this.textNode;
35758 getIconEl : function(){
35759 return this.iconNode;
35762 isChecked : function(){
35763 return this.checkbox ? this.checkbox.checked : false;
35766 updateExpandIcon : function(){
35768 var n = this.node, c1, c2;
35769 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35770 var hasChild = n.hasChildNodes();
35774 c1 = "x-tree-node-collapsed";
35775 c2 = "x-tree-node-expanded";
35778 c1 = "x-tree-node-expanded";
35779 c2 = "x-tree-node-collapsed";
35782 this.removeClass("x-tree-node-leaf");
35783 this.wasLeaf = false;
35785 if(this.c1 != c1 || this.c2 != c2){
35786 Roo.fly(this.elNode).replaceClass(c1, c2);
35787 this.c1 = c1; this.c2 = c2;
35790 // this changes non-leafs into leafs if they have no children.
35791 // it's not very rational behaviour..
35793 if(!this.wasLeaf && this.node.leaf){
35794 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35797 this.wasLeaf = true;
35800 var ecc = "x-tree-ec-icon "+cls;
35801 if(this.ecc != ecc){
35802 this.ecNode.className = ecc;
35808 getChildIndent : function(){
35809 if(!this.childIndent){
35813 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35815 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35817 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35822 this.childIndent = buf.join("");
35824 return this.childIndent;
35827 renderIndent : function(){
35830 var p = this.node.parentNode;
35832 indent = p.ui.getChildIndent();
35834 if(this.indentMarkup != indent){ // don't rerender if not required
35835 this.indentNode.innerHTML = indent;
35836 this.indentMarkup = indent;
35838 this.updateExpandIcon();
35843 Roo.tree.RootTreeNodeUI = function(){
35844 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35846 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35847 render : function(){
35848 if(!this.rendered){
35849 var targetNode = this.node.ownerTree.innerCt.dom;
35850 this.node.expanded = true;
35851 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35852 this.wrap = this.ctNode = targetNode.firstChild;
35855 collapse : function(){
35857 expand : function(){
35861 * Ext JS Library 1.1.1
35862 * Copyright(c) 2006-2007, Ext JS, LLC.
35864 * Originally Released Under LGPL - original licence link has changed is not relivant.
35867 * <script type="text/javascript">
35870 * @class Roo.tree.TreeLoader
35871 * @extends Roo.util.Observable
35872 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35873 * nodes from a specified URL. The response must be a javascript Array definition
35874 * who's elements are node definition objects. eg:
35879 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35880 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35887 * The old style respose with just an array is still supported, but not recommended.
35890 * A server request is sent, and child nodes are loaded only when a node is expanded.
35891 * The loading node's id is passed to the server under the parameter name "node" to
35892 * enable the server to produce the correct child nodes.
35894 * To pass extra parameters, an event handler may be attached to the "beforeload"
35895 * event, and the parameters specified in the TreeLoader's baseParams property:
35897 myTreeLoader.on("beforeload", function(treeLoader, node) {
35898 this.baseParams.category = node.attributes.category;
35901 * This would pass an HTTP parameter called "category" to the server containing
35902 * the value of the Node's "category" attribute.
35904 * Creates a new Treeloader.
35905 * @param {Object} config A config object containing config properties.
35907 Roo.tree.TreeLoader = function(config){
35908 this.baseParams = {};
35909 this.requestMethod = "POST";
35910 Roo.apply(this, config);
35915 * @event beforeload
35916 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35917 * @param {Object} This TreeLoader object.
35918 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35919 * @param {Object} callback The callback function specified in the {@link #load} call.
35924 * Fires when the node has been successfuly loaded.
35925 * @param {Object} This TreeLoader object.
35926 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35927 * @param {Object} response The response object containing the data from the server.
35931 * @event loadexception
35932 * Fires if the network request failed.
35933 * @param {Object} This TreeLoader object.
35934 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35935 * @param {Object} response The response object containing the data from the server.
35937 loadexception : true,
35940 * Fires before a node is created, enabling you to return custom Node types
35941 * @param {Object} This TreeLoader object.
35942 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35947 Roo.tree.TreeLoader.superclass.constructor.call(this);
35950 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35952 * @cfg {String} dataUrl The URL from which to request a Json string which
35953 * specifies an array of node definition object representing the child nodes
35957 * @cfg {String} requestMethod either GET or POST
35958 * defaults to POST (due to BC)
35962 * @cfg {Object} baseParams (optional) An object containing properties which
35963 * specify HTTP parameters to be passed to each request for child nodes.
35966 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35967 * created by this loader. If the attributes sent by the server have an attribute in this object,
35968 * they take priority.
35971 * @cfg {Object} uiProviders (optional) An object containing properties which
35973 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35974 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35975 * <i>uiProvider</i> attribute of a returned child node is a string rather
35976 * than a reference to a TreeNodeUI implementation, this that string value
35977 * is used as a property name in the uiProviders object. You can define the provider named
35978 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35983 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35984 * child nodes before loading.
35986 clearOnLoad : true,
35989 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35990 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35991 * Grid query { data : [ .....] }
35996 * @cfg {String} queryParam (optional)
35997 * Name of the query as it will be passed on the querystring (defaults to 'node')
35998 * eg. the request will be ?node=[id]
36005 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36006 * This is called automatically when a node is expanded, but may be used to reload
36007 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36008 * @param {Roo.tree.TreeNode} node
36009 * @param {Function} callback
36011 load : function(node, callback){
36012 if(this.clearOnLoad){
36013 while(node.firstChild){
36014 node.removeChild(node.firstChild);
36017 if(node.attributes.children){ // preloaded json children
36018 var cs = node.attributes.children;
36019 for(var i = 0, len = cs.length; i < len; i++){
36020 node.appendChild(this.createNode(cs[i]));
36022 if(typeof callback == "function"){
36025 }else if(this.dataUrl){
36026 this.requestData(node, callback);
36030 getParams: function(node){
36031 var buf = [], bp = this.baseParams;
36032 for(var key in bp){
36033 if(typeof bp[key] != "function"){
36034 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36037 var n = this.queryParam === false ? 'node' : this.queryParam;
36038 buf.push(n + "=", encodeURIComponent(node.id));
36039 return buf.join("");
36042 requestData : function(node, callback){
36043 if(this.fireEvent("beforeload", this, node, callback) !== false){
36044 this.transId = Roo.Ajax.request({
36045 method:this.requestMethod,
36046 url: this.dataUrl||this.url,
36047 success: this.handleResponse,
36048 failure: this.handleFailure,
36050 argument: {callback: callback, node: node},
36051 params: this.getParams(node)
36054 // if the load is cancelled, make sure we notify
36055 // the node that we are done
36056 if(typeof callback == "function"){
36062 isLoading : function(){
36063 return this.transId ? true : false;
36066 abort : function(){
36067 if(this.isLoading()){
36068 Roo.Ajax.abort(this.transId);
36073 createNode : function(attr)
36075 // apply baseAttrs, nice idea Corey!
36076 if(this.baseAttrs){
36077 Roo.applyIf(attr, this.baseAttrs);
36079 if(this.applyLoader !== false){
36080 attr.loader = this;
36082 // uiProvider = depreciated..
36084 if(typeof(attr.uiProvider) == 'string'){
36085 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36086 /** eval:var:attr */ eval(attr.uiProvider);
36088 if(typeof(this.uiProviders['default']) != 'undefined') {
36089 attr.uiProvider = this.uiProviders['default'];
36092 this.fireEvent('create', this, attr);
36094 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36096 new Roo.tree.TreeNode(attr) :
36097 new Roo.tree.AsyncTreeNode(attr));
36100 processResponse : function(response, node, callback)
36102 var json = response.responseText;
36105 var o = Roo.decode(json);
36107 if (this.root === false && typeof(o.success) != undefined) {
36108 this.root = 'data'; // the default behaviour for list like data..
36111 if (this.root !== false && !o.success) {
36112 // it's a failure condition.
36113 var a = response.argument;
36114 this.fireEvent("loadexception", this, a.node, response);
36115 Roo.log("Load failed - should have a handler really");
36121 if (this.root !== false) {
36125 for(var i = 0, len = o.length; i < len; i++){
36126 var n = this.createNode(o[i]);
36128 node.appendChild(n);
36131 if(typeof callback == "function"){
36132 callback(this, node);
36135 this.handleFailure(response);
36139 handleResponse : function(response){
36140 this.transId = false;
36141 var a = response.argument;
36142 this.processResponse(response, a.node, a.callback);
36143 this.fireEvent("load", this, a.node, response);
36146 handleFailure : function(response)
36148 // should handle failure better..
36149 this.transId = false;
36150 var a = response.argument;
36151 this.fireEvent("loadexception", this, a.node, response);
36152 if(typeof a.callback == "function"){
36153 a.callback(this, a.node);
36158 * Ext JS Library 1.1.1
36159 * Copyright(c) 2006-2007, Ext JS, LLC.
36161 * Originally Released Under LGPL - original licence link has changed is not relivant.
36164 * <script type="text/javascript">
36168 * @class Roo.tree.TreeFilter
36169 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36170 * @param {TreePanel} tree
36171 * @param {Object} config (optional)
36173 Roo.tree.TreeFilter = function(tree, config){
36175 this.filtered = {};
36176 Roo.apply(this, config);
36179 Roo.tree.TreeFilter.prototype = {
36186 * Filter the data by a specific attribute.
36187 * @param {String/RegExp} value Either string that the attribute value
36188 * should start with or a RegExp to test against the attribute
36189 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36190 * @param {TreeNode} startNode (optional) The node to start the filter at.
36192 filter : function(value, attr, startNode){
36193 attr = attr || "text";
36195 if(typeof value == "string"){
36196 var vlen = value.length;
36197 // auto clear empty filter
36198 if(vlen == 0 && this.clearBlank){
36202 value = value.toLowerCase();
36204 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36206 }else if(value.exec){ // regex?
36208 return value.test(n.attributes[attr]);
36211 throw 'Illegal filter type, must be string or regex';
36213 this.filterBy(f, null, startNode);
36217 * Filter by a function. The passed function will be called with each
36218 * node in the tree (or from the startNode). If the function returns true, the node is kept
36219 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36220 * @param {Function} fn The filter function
36221 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36223 filterBy : function(fn, scope, startNode){
36224 startNode = startNode || this.tree.root;
36225 if(this.autoClear){
36228 var af = this.filtered, rv = this.reverse;
36229 var f = function(n){
36230 if(n == startNode){
36236 var m = fn.call(scope || n, n);
36244 startNode.cascade(f);
36247 if(typeof id != "function"){
36249 if(n && n.parentNode){
36250 n.parentNode.removeChild(n);
36258 * Clears the current filter. Note: with the "remove" option
36259 * set a filter cannot be cleared.
36261 clear : function(){
36263 var af = this.filtered;
36265 if(typeof id != "function"){
36272 this.filtered = {};
36277 * Ext JS Library 1.1.1
36278 * Copyright(c) 2006-2007, Ext JS, LLC.
36280 * Originally Released Under LGPL - original licence link has changed is not relivant.
36283 * <script type="text/javascript">
36288 * @class Roo.tree.TreeSorter
36289 * Provides sorting of nodes in a TreePanel
36291 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36292 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36293 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36294 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36295 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36296 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36298 * @param {TreePanel} tree
36299 * @param {Object} config
36301 Roo.tree.TreeSorter = function(tree, config){
36302 Roo.apply(this, config);
36303 tree.on("beforechildrenrendered", this.doSort, this);
36304 tree.on("append", this.updateSort, this);
36305 tree.on("insert", this.updateSort, this);
36307 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36308 var p = this.property || "text";
36309 var sortType = this.sortType;
36310 var fs = this.folderSort;
36311 var cs = this.caseSensitive === true;
36312 var leafAttr = this.leafAttr || 'leaf';
36314 this.sortFn = function(n1, n2){
36316 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36319 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36323 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36324 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36326 return dsc ? +1 : -1;
36328 return dsc ? -1 : +1;
36335 Roo.tree.TreeSorter.prototype = {
36336 doSort : function(node){
36337 node.sort(this.sortFn);
36340 compareNodes : function(n1, n2){
36341 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36344 updateSort : function(tree, node){
36345 if(node.childrenRendered){
36346 this.doSort.defer(1, this, [node]);
36351 * Ext JS Library 1.1.1
36352 * Copyright(c) 2006-2007, Ext JS, LLC.
36354 * Originally Released Under LGPL - original licence link has changed is not relivant.
36357 * <script type="text/javascript">
36360 if(Roo.dd.DropZone){
36362 Roo.tree.TreeDropZone = function(tree, config){
36363 this.allowParentInsert = false;
36364 this.allowContainerDrop = false;
36365 this.appendOnly = false;
36366 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36368 this.lastInsertClass = "x-tree-no-status";
36369 this.dragOverData = {};
36372 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36373 ddGroup : "TreeDD",
36376 expandDelay : 1000,
36378 expandNode : function(node){
36379 if(node.hasChildNodes() && !node.isExpanded()){
36380 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36384 queueExpand : function(node){
36385 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36388 cancelExpand : function(){
36389 if(this.expandProcId){
36390 clearTimeout(this.expandProcId);
36391 this.expandProcId = false;
36395 isValidDropPoint : function(n, pt, dd, e, data){
36396 if(!n || !data){ return false; }
36397 var targetNode = n.node;
36398 var dropNode = data.node;
36399 // default drop rules
36400 if(!(targetNode && targetNode.isTarget && pt)){
36403 if(pt == "append" && targetNode.allowChildren === false){
36406 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36409 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36412 // reuse the object
36413 var overEvent = this.dragOverData;
36414 overEvent.tree = this.tree;
36415 overEvent.target = targetNode;
36416 overEvent.data = data;
36417 overEvent.point = pt;
36418 overEvent.source = dd;
36419 overEvent.rawEvent = e;
36420 overEvent.dropNode = dropNode;
36421 overEvent.cancel = false;
36422 var result = this.tree.fireEvent("nodedragover", overEvent);
36423 return overEvent.cancel === false && result !== false;
36426 getDropPoint : function(e, n, dd)
36430 return tn.allowChildren !== false ? "append" : false; // always append for root
36432 var dragEl = n.ddel;
36433 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36434 var y = Roo.lib.Event.getPageY(e);
36435 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36437 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36438 var noAppend = tn.allowChildren === false;
36439 if(this.appendOnly || tn.parentNode.allowChildren === false){
36440 return noAppend ? false : "append";
36442 var noBelow = false;
36443 if(!this.allowParentInsert){
36444 noBelow = tn.hasChildNodes() && tn.isExpanded();
36446 var q = (b - t) / (noAppend ? 2 : 3);
36447 if(y >= t && y < (t + q)){
36449 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36456 onNodeEnter : function(n, dd, e, data)
36458 this.cancelExpand();
36461 onNodeOver : function(n, dd, e, data)
36464 var pt = this.getDropPoint(e, n, dd);
36467 // auto node expand check
36468 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36469 this.queueExpand(node);
36470 }else if(pt != "append"){
36471 this.cancelExpand();
36474 // set the insert point style on the target node
36475 var returnCls = this.dropNotAllowed;
36476 if(this.isValidDropPoint(n, pt, dd, e, data)){
36481 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36482 cls = "x-tree-drag-insert-above";
36483 }else if(pt == "below"){
36484 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36485 cls = "x-tree-drag-insert-below";
36487 returnCls = "x-tree-drop-ok-append";
36488 cls = "x-tree-drag-append";
36490 if(this.lastInsertClass != cls){
36491 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36492 this.lastInsertClass = cls;
36499 onNodeOut : function(n, dd, e, data){
36501 this.cancelExpand();
36502 this.removeDropIndicators(n);
36505 onNodeDrop : function(n, dd, e, data){
36506 var point = this.getDropPoint(e, n, dd);
36507 var targetNode = n.node;
36508 targetNode.ui.startDrop();
36509 if(!this.isValidDropPoint(n, point, dd, e, data)){
36510 targetNode.ui.endDrop();
36513 // first try to find the drop node
36514 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36517 target: targetNode,
36522 dropNode: dropNode,
36525 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36526 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36527 targetNode.ui.endDrop();
36530 // allow target changing
36531 targetNode = dropEvent.target;
36532 if(point == "append" && !targetNode.isExpanded()){
36533 targetNode.expand(false, null, function(){
36534 this.completeDrop(dropEvent);
36535 }.createDelegate(this));
36537 this.completeDrop(dropEvent);
36542 completeDrop : function(de){
36543 var ns = de.dropNode, p = de.point, t = de.target;
36544 if(!(ns instanceof Array)){
36548 for(var i = 0, len = ns.length; i < len; i++){
36551 t.parentNode.insertBefore(n, t);
36552 }else if(p == "below"){
36553 t.parentNode.insertBefore(n, t.nextSibling);
36559 if(this.tree.hlDrop){
36563 this.tree.fireEvent("nodedrop", de);
36566 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36567 if(this.tree.hlDrop){
36568 dropNode.ui.focus();
36569 dropNode.ui.highlight();
36571 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36574 getTree : function(){
36578 removeDropIndicators : function(n){
36581 Roo.fly(el).removeClass([
36582 "x-tree-drag-insert-above",
36583 "x-tree-drag-insert-below",
36584 "x-tree-drag-append"]);
36585 this.lastInsertClass = "_noclass";
36589 beforeDragDrop : function(target, e, id){
36590 this.cancelExpand();
36594 afterRepair : function(data){
36595 if(data && Roo.enableFx){
36596 data.node.ui.highlight();
36606 * Ext JS Library 1.1.1
36607 * Copyright(c) 2006-2007, Ext JS, LLC.
36609 * Originally Released Under LGPL - original licence link has changed is not relivant.
36612 * <script type="text/javascript">
36616 if(Roo.dd.DragZone){
36617 Roo.tree.TreeDragZone = function(tree, config){
36618 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36622 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36623 ddGroup : "TreeDD",
36625 onBeforeDrag : function(data, e){
36627 return n && n.draggable && !n.disabled;
36631 onInitDrag : function(e){
36632 var data = this.dragData;
36633 this.tree.getSelectionModel().select(data.node);
36634 this.proxy.update("");
36635 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36636 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36639 getRepairXY : function(e, data){
36640 return data.node.ui.getDDRepairXY();
36643 onEndDrag : function(data, e){
36644 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36649 onValidDrop : function(dd, e, id){
36650 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36654 beforeInvalidDrop : function(e, id){
36655 // this scrolls the original position back into view
36656 var sm = this.tree.getSelectionModel();
36657 sm.clearSelections();
36658 sm.select(this.dragData.node);
36663 * Ext JS Library 1.1.1
36664 * Copyright(c) 2006-2007, Ext JS, LLC.
36666 * Originally Released Under LGPL - original licence link has changed is not relivant.
36669 * <script type="text/javascript">
36672 * @class Roo.tree.TreeEditor
36673 * @extends Roo.Editor
36674 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36675 * as the editor field.
36677 * @param {Object} config (used to be the tree panel.)
36678 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36680 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36681 * @cfg {Roo.form.TextField|Object} field The field configuration
36685 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36688 if (oldconfig) { // old style..
36689 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36692 tree = config.tree;
36693 config.field = config.field || {};
36694 config.field.xtype = 'TextField';
36695 field = Roo.factory(config.field, Roo.form);
36697 config = config || {};
36702 * @event beforenodeedit
36703 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36704 * false from the handler of this event.
36705 * @param {Editor} this
36706 * @param {Roo.tree.Node} node
36708 "beforenodeedit" : true
36712 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36716 tree.on('beforeclick', this.beforeNodeClick, this);
36717 tree.getTreeEl().on('mousedown', this.hide, this);
36718 this.on('complete', this.updateNode, this);
36719 this.on('beforestartedit', this.fitToTree, this);
36720 this.on('startedit', this.bindScroll, this, {delay:10});
36721 this.on('specialkey', this.onSpecialKey, this);
36724 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36726 * @cfg {String} alignment
36727 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36733 * @cfg {Boolean} hideEl
36734 * True to hide the bound element while the editor is displayed (defaults to false)
36738 * @cfg {String} cls
36739 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36741 cls: "x-small-editor x-tree-editor",
36743 * @cfg {Boolean} shim
36744 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36750 * @cfg {Number} maxWidth
36751 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36752 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36753 * scroll and client offsets into account prior to each edit.
36760 fitToTree : function(ed, el){
36761 var td = this.tree.getTreeEl().dom, nd = el.dom;
36762 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36763 td.scrollLeft = nd.offsetLeft;
36767 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36768 this.setSize(w, '');
36770 return this.fireEvent('beforenodeedit', this, this.editNode);
36775 triggerEdit : function(node){
36776 this.completeEdit();
36777 this.editNode = node;
36778 this.startEdit(node.ui.textNode, node.text);
36782 bindScroll : function(){
36783 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36787 beforeNodeClick : function(node, e){
36788 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36789 this.lastClick = new Date();
36790 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36792 this.triggerEdit(node);
36799 updateNode : function(ed, value){
36800 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36801 this.editNode.setText(value);
36805 onHide : function(){
36806 Roo.tree.TreeEditor.superclass.onHide.call(this);
36808 this.editNode.ui.focus();
36813 onSpecialKey : function(field, e){
36814 var k = e.getKey();
36818 }else if(k == e.ENTER && !e.hasModifier()){
36820 this.completeEdit();
36823 });//<Script type="text/javascript">
36826 * Ext JS Library 1.1.1
36827 * Copyright(c) 2006-2007, Ext JS, LLC.
36829 * Originally Released Under LGPL - original licence link has changed is not relivant.
36832 * <script type="text/javascript">
36836 * Not documented??? - probably should be...
36839 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36840 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36842 renderElements : function(n, a, targetNode, bulkRender){
36843 //consel.log("renderElements?");
36844 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36846 var t = n.getOwnerTree();
36847 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36849 var cols = t.columns;
36850 var bw = t.borderWidth;
36852 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36853 var cb = typeof a.checked == "boolean";
36854 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36855 var colcls = 'x-t-' + tid + '-c0';
36857 '<li class="x-tree-node">',
36860 '<div class="x-tree-node-el ', a.cls,'">',
36862 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36865 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36866 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36867 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36868 (a.icon ? ' x-tree-node-inline-icon' : ''),
36869 (a.iconCls ? ' '+a.iconCls : ''),
36870 '" unselectable="on" />',
36871 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36872 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36874 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36875 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36876 '<span unselectable="on" qtip="' + tx + '">',
36880 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36881 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36883 for(var i = 1, len = cols.length; i < len; i++){
36885 colcls = 'x-t-' + tid + '-c' +i;
36886 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36887 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36888 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36894 '<div class="x-clear"></div></div>',
36895 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36898 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36899 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36900 n.nextSibling.ui.getEl(), buf.join(""));
36902 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36904 var el = this.wrap.firstChild;
36906 this.elNode = el.firstChild;
36907 this.ranchor = el.childNodes[1];
36908 this.ctNode = this.wrap.childNodes[1];
36909 var cs = el.firstChild.childNodes;
36910 this.indentNode = cs[0];
36911 this.ecNode = cs[1];
36912 this.iconNode = cs[2];
36915 this.checkbox = cs[3];
36918 this.anchor = cs[index];
36920 this.textNode = cs[index].firstChild;
36922 //el.on("click", this.onClick, this);
36923 //el.on("dblclick", this.onDblClick, this);
36926 // console.log(this);
36928 initEvents : function(){
36929 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36932 var a = this.ranchor;
36934 var el = Roo.get(a);
36936 if(Roo.isOpera){ // opera render bug ignores the CSS
36937 el.setStyle("text-decoration", "none");
36940 el.on("click", this.onClick, this);
36941 el.on("dblclick", this.onDblClick, this);
36942 el.on("contextmenu", this.onContextMenu, this);
36946 /*onSelectedChange : function(state){
36949 this.addClass("x-tree-selected");
36952 this.removeClass("x-tree-selected");
36955 addClass : function(cls){
36957 Roo.fly(this.elRow).addClass(cls);
36963 removeClass : function(cls){
36965 Roo.fly(this.elRow).removeClass(cls);
36971 });//<Script type="text/javascript">
36975 * Ext JS Library 1.1.1
36976 * Copyright(c) 2006-2007, Ext JS, LLC.
36978 * Originally Released Under LGPL - original licence link has changed is not relivant.
36981 * <script type="text/javascript">
36986 * @class Roo.tree.ColumnTree
36987 * @extends Roo.data.TreePanel
36988 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36989 * @cfg {int} borderWidth compined right/left border allowance
36991 * @param {String/HTMLElement/Element} el The container element
36992 * @param {Object} config
36994 Roo.tree.ColumnTree = function(el, config)
36996 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37000 * Fire this event on a container when it resizes
37001 * @param {int} w Width
37002 * @param {int} h Height
37006 this.on('resize', this.onResize, this);
37009 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37013 borderWidth: Roo.isBorderBox ? 0 : 2,
37016 render : function(){
37017 // add the header.....
37019 Roo.tree.ColumnTree.superclass.render.apply(this);
37021 this.el.addClass('x-column-tree');
37023 this.headers = this.el.createChild(
37024 {cls:'x-tree-headers'},this.innerCt.dom);
37026 var cols = this.columns, c;
37027 var totalWidth = 0;
37029 var len = cols.length;
37030 for(var i = 0; i < len; i++){
37032 totalWidth += c.width;
37033 this.headEls.push(this.headers.createChild({
37034 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37036 cls:'x-tree-hd-text',
37039 style:'width:'+(c.width-this.borderWidth)+'px;'
37042 this.headers.createChild({cls:'x-clear'});
37043 // prevent floats from wrapping when clipped
37044 this.headers.setWidth(totalWidth);
37045 //this.innerCt.setWidth(totalWidth);
37046 this.innerCt.setStyle({ overflow: 'auto' });
37047 this.onResize(this.width, this.height);
37051 onResize : function(w,h)
37056 this.innerCt.setWidth(this.width);
37057 this.innerCt.setHeight(this.height-20);
37060 var cols = this.columns, c;
37061 var totalWidth = 0;
37063 var len = cols.length;
37064 for(var i = 0; i < len; i++){
37066 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37067 // it's the expander..
37068 expEl = this.headEls[i];
37071 totalWidth += c.width;
37075 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37077 this.headers.setWidth(w-20);
37086 * Ext JS Library 1.1.1
37087 * Copyright(c) 2006-2007, Ext JS, LLC.
37089 * Originally Released Under LGPL - original licence link has changed is not relivant.
37092 * <script type="text/javascript">
37096 * @class Roo.menu.Menu
37097 * @extends Roo.util.Observable
37098 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37099 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37101 * Creates a new Menu
37102 * @param {Object} config Configuration options
37104 Roo.menu.Menu = function(config){
37105 Roo.apply(this, config);
37106 this.id = this.id || Roo.id();
37109 * @event beforeshow
37110 * Fires before this menu is displayed
37111 * @param {Roo.menu.Menu} this
37115 * @event beforehide
37116 * Fires before this menu is hidden
37117 * @param {Roo.menu.Menu} this
37122 * Fires after this menu is displayed
37123 * @param {Roo.menu.Menu} this
37128 * Fires after this menu is hidden
37129 * @param {Roo.menu.Menu} this
37134 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37135 * @param {Roo.menu.Menu} this
37136 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37137 * @param {Roo.EventObject} e
37142 * Fires when the mouse is hovering over this menu
37143 * @param {Roo.menu.Menu} this
37144 * @param {Roo.EventObject} e
37145 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37150 * Fires when the mouse exits this menu
37151 * @param {Roo.menu.Menu} this
37152 * @param {Roo.EventObject} e
37153 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37158 * Fires when a menu item contained in this menu is clicked
37159 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37160 * @param {Roo.EventObject} e
37164 if (this.registerMenu) {
37165 Roo.menu.MenuMgr.register(this);
37168 var mis = this.items;
37169 this.items = new Roo.util.MixedCollection();
37171 this.add.apply(this, mis);
37175 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37177 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37181 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37182 * for bottom-right shadow (defaults to "sides")
37186 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37187 * this menu (defaults to "tl-tr?")
37189 subMenuAlign : "tl-tr?",
37191 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37192 * relative to its element of origin (defaults to "tl-bl?")
37194 defaultAlign : "tl-bl?",
37196 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37198 allowOtherMenus : false,
37200 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37202 registerMenu : true,
37207 render : function(){
37211 var el = this.el = new Roo.Layer({
37213 shadow:this.shadow,
37215 parentEl: this.parentEl || document.body,
37219 this.keyNav = new Roo.menu.MenuNav(this);
37222 el.addClass("x-menu-plain");
37225 el.addClass(this.cls);
37227 // generic focus element
37228 this.focusEl = el.createChild({
37229 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37231 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37232 //disabling touch- as it's causing issues ..
37233 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37234 ul.on('click' , this.onClick, this);
37237 ul.on("mouseover", this.onMouseOver, this);
37238 ul.on("mouseout", this.onMouseOut, this);
37239 this.items.each(function(item){
37244 var li = document.createElement("li");
37245 li.className = "x-menu-list-item";
37246 ul.dom.appendChild(li);
37247 item.render(li, this);
37254 autoWidth : function(){
37255 var el = this.el, ul = this.ul;
37259 var w = this.width;
37262 }else if(Roo.isIE){
37263 el.setWidth(this.minWidth);
37264 var t = el.dom.offsetWidth; // force recalc
37265 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37270 delayAutoWidth : function(){
37273 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37275 this.awTask.delay(20);
37280 findTargetItem : function(e){
37281 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37282 if(t && t.menuItemId){
37283 return this.items.get(t.menuItemId);
37288 onClick : function(e){
37289 Roo.log("menu.onClick");
37290 var t = this.findTargetItem(e);
37295 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37296 if(t == this.activeItem && t.shouldDeactivate(e)){
37297 this.activeItem.deactivate();
37298 delete this.activeItem;
37302 this.setActiveItem(t, true);
37310 this.fireEvent("click", this, t, e);
37314 setActiveItem : function(item, autoExpand){
37315 if(item != this.activeItem){
37316 if(this.activeItem){
37317 this.activeItem.deactivate();
37319 this.activeItem = item;
37320 item.activate(autoExpand);
37321 }else if(autoExpand){
37327 tryActivate : function(start, step){
37328 var items = this.items;
37329 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37330 var item = items.get(i);
37331 if(!item.disabled && item.canActivate){
37332 this.setActiveItem(item, false);
37340 onMouseOver : function(e){
37342 if(t = this.findTargetItem(e)){
37343 if(t.canActivate && !t.disabled){
37344 this.setActiveItem(t, true);
37347 this.fireEvent("mouseover", this, e, t);
37351 onMouseOut : function(e){
37353 if(t = this.findTargetItem(e)){
37354 if(t == this.activeItem && t.shouldDeactivate(e)){
37355 this.activeItem.deactivate();
37356 delete this.activeItem;
37359 this.fireEvent("mouseout", this, e, t);
37363 * Read-only. Returns true if the menu is currently displayed, else false.
37366 isVisible : function(){
37367 return this.el && !this.hidden;
37371 * Displays this menu relative to another element
37372 * @param {String/HTMLElement/Roo.Element} element The element to align to
37373 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37374 * the element (defaults to this.defaultAlign)
37375 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37377 show : function(el, pos, parentMenu){
37378 this.parentMenu = parentMenu;
37382 this.fireEvent("beforeshow", this);
37383 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37387 * Displays this menu at a specific xy position
37388 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37389 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37391 showAt : function(xy, parentMenu, /* private: */_e){
37392 this.parentMenu = parentMenu;
37397 this.fireEvent("beforeshow", this);
37398 xy = this.el.adjustForConstraints(xy);
37402 this.hidden = false;
37404 this.fireEvent("show", this);
37407 focus : function(){
37409 this.doFocus.defer(50, this);
37413 doFocus : function(){
37415 this.focusEl.focus();
37420 * Hides this menu and optionally all parent menus
37421 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37423 hide : function(deep){
37424 if(this.el && this.isVisible()){
37425 this.fireEvent("beforehide", this);
37426 if(this.activeItem){
37427 this.activeItem.deactivate();
37428 this.activeItem = null;
37431 this.hidden = true;
37432 this.fireEvent("hide", this);
37434 if(deep === true && this.parentMenu){
37435 this.parentMenu.hide(true);
37440 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37441 * Any of the following are valid:
37443 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37444 * <li>An HTMLElement object which will be converted to a menu item</li>
37445 * <li>A menu item config object that will be created as a new menu item</li>
37446 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37447 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37452 var menu = new Roo.menu.Menu();
37454 // Create a menu item to add by reference
37455 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37457 // Add a bunch of items at once using different methods.
37458 // Only the last item added will be returned.
37459 var item = menu.add(
37460 menuItem, // add existing item by ref
37461 'Dynamic Item', // new TextItem
37462 '-', // new separator
37463 { text: 'Config Item' } // new item by config
37466 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37467 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37470 var a = arguments, l = a.length, item;
37471 for(var i = 0; i < l; i++){
37473 if ((typeof(el) == "object") && el.xtype && el.xns) {
37474 el = Roo.factory(el, Roo.menu);
37477 if(el.render){ // some kind of Item
37478 item = this.addItem(el);
37479 }else if(typeof el == "string"){ // string
37480 if(el == "separator" || el == "-"){
37481 item = this.addSeparator();
37483 item = this.addText(el);
37485 }else if(el.tagName || el.el){ // element
37486 item = this.addElement(el);
37487 }else if(typeof el == "object"){ // must be menu item config?
37488 item = this.addMenuItem(el);
37495 * Returns this menu's underlying {@link Roo.Element} object
37496 * @return {Roo.Element} The element
37498 getEl : function(){
37506 * Adds a separator bar to the menu
37507 * @return {Roo.menu.Item} The menu item that was added
37509 addSeparator : function(){
37510 return this.addItem(new Roo.menu.Separator());
37514 * Adds an {@link Roo.Element} object to the menu
37515 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37516 * @return {Roo.menu.Item} The menu item that was added
37518 addElement : function(el){
37519 return this.addItem(new Roo.menu.BaseItem(el));
37523 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37524 * @param {Roo.menu.Item} item The menu item to add
37525 * @return {Roo.menu.Item} The menu item that was added
37527 addItem : function(item){
37528 this.items.add(item);
37530 var li = document.createElement("li");
37531 li.className = "x-menu-list-item";
37532 this.ul.dom.appendChild(li);
37533 item.render(li, this);
37534 this.delayAutoWidth();
37540 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37541 * @param {Object} config A MenuItem config object
37542 * @return {Roo.menu.Item} The menu item that was added
37544 addMenuItem : function(config){
37545 if(!(config instanceof Roo.menu.Item)){
37546 if(typeof config.checked == "boolean"){ // must be check menu item config?
37547 config = new Roo.menu.CheckItem(config);
37549 config = new Roo.menu.Item(config);
37552 return this.addItem(config);
37556 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37557 * @param {String} text The text to display in the menu item
37558 * @return {Roo.menu.Item} The menu item that was added
37560 addText : function(text){
37561 return this.addItem(new Roo.menu.TextItem({ text : text }));
37565 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37566 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37567 * @param {Roo.menu.Item} item The menu item to add
37568 * @return {Roo.menu.Item} The menu item that was added
37570 insert : function(index, item){
37571 this.items.insert(index, item);
37573 var li = document.createElement("li");
37574 li.className = "x-menu-list-item";
37575 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37576 item.render(li, this);
37577 this.delayAutoWidth();
37583 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37584 * @param {Roo.menu.Item} item The menu item to remove
37586 remove : function(item){
37587 this.items.removeKey(item.id);
37592 * Removes and destroys all items in the menu
37594 removeAll : function(){
37596 while(f = this.items.first()){
37602 // MenuNav is a private utility class used internally by the Menu
37603 Roo.menu.MenuNav = function(menu){
37604 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37605 this.scope = this.menu = menu;
37608 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37609 doRelay : function(e, h){
37610 var k = e.getKey();
37611 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37612 this.menu.tryActivate(0, 1);
37615 return h.call(this.scope || this, e, this.menu);
37618 up : function(e, m){
37619 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37620 m.tryActivate(m.items.length-1, -1);
37624 down : function(e, m){
37625 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37626 m.tryActivate(0, 1);
37630 right : function(e, m){
37632 m.activeItem.expandMenu(true);
37636 left : function(e, m){
37638 if(m.parentMenu && m.parentMenu.activeItem){
37639 m.parentMenu.activeItem.activate();
37643 enter : function(e, m){
37645 e.stopPropagation();
37646 m.activeItem.onClick(e);
37647 m.fireEvent("click", this, m.activeItem);
37653 * Ext JS Library 1.1.1
37654 * Copyright(c) 2006-2007, Ext JS, LLC.
37656 * Originally Released Under LGPL - original licence link has changed is not relivant.
37659 * <script type="text/javascript">
37663 * @class Roo.menu.MenuMgr
37664 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37667 Roo.menu.MenuMgr = function(){
37668 var menus, active, groups = {}, attached = false, lastShow = new Date();
37670 // private - called when first menu is created
37673 active = new Roo.util.MixedCollection();
37674 Roo.get(document).addKeyListener(27, function(){
37675 if(active.length > 0){
37682 function hideAll(){
37683 if(active && active.length > 0){
37684 var c = active.clone();
37685 c.each(function(m){
37692 function onHide(m){
37694 if(active.length < 1){
37695 Roo.get(document).un("mousedown", onMouseDown);
37701 function onShow(m){
37702 var last = active.last();
37703 lastShow = new Date();
37706 Roo.get(document).on("mousedown", onMouseDown);
37710 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37711 m.parentMenu.activeChild = m;
37712 }else if(last && last.isVisible()){
37713 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37718 function onBeforeHide(m){
37720 m.activeChild.hide();
37722 if(m.autoHideTimer){
37723 clearTimeout(m.autoHideTimer);
37724 delete m.autoHideTimer;
37729 function onBeforeShow(m){
37730 var pm = m.parentMenu;
37731 if(!pm && !m.allowOtherMenus){
37733 }else if(pm && pm.activeChild && active != m){
37734 pm.activeChild.hide();
37739 function onMouseDown(e){
37740 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37746 function onBeforeCheck(mi, state){
37748 var g = groups[mi.group];
37749 for(var i = 0, l = g.length; i < l; i++){
37751 g[i].setChecked(false);
37760 * Hides all menus that are currently visible
37762 hideAll : function(){
37767 register : function(menu){
37771 menus[menu.id] = menu;
37772 menu.on("beforehide", onBeforeHide);
37773 menu.on("hide", onHide);
37774 menu.on("beforeshow", onBeforeShow);
37775 menu.on("show", onShow);
37776 var g = menu.group;
37777 if(g && menu.events["checkchange"]){
37781 groups[g].push(menu);
37782 menu.on("checkchange", onCheck);
37787 * Returns a {@link Roo.menu.Menu} object
37788 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37789 * be used to generate and return a new Menu instance.
37791 get : function(menu){
37792 if(typeof menu == "string"){ // menu id
37793 return menus[menu];
37794 }else if(menu.events){ // menu instance
37796 }else if(typeof menu.length == 'number'){ // array of menu items?
37797 return new Roo.menu.Menu({items:menu});
37798 }else{ // otherwise, must be a config
37799 return new Roo.menu.Menu(menu);
37804 unregister : function(menu){
37805 delete menus[menu.id];
37806 menu.un("beforehide", onBeforeHide);
37807 menu.un("hide", onHide);
37808 menu.un("beforeshow", onBeforeShow);
37809 menu.un("show", onShow);
37810 var g = menu.group;
37811 if(g && menu.events["checkchange"]){
37812 groups[g].remove(menu);
37813 menu.un("checkchange", onCheck);
37818 registerCheckable : function(menuItem){
37819 var g = menuItem.group;
37824 groups[g].push(menuItem);
37825 menuItem.on("beforecheckchange", onBeforeCheck);
37830 unregisterCheckable : function(menuItem){
37831 var g = menuItem.group;
37833 groups[g].remove(menuItem);
37834 menuItem.un("beforecheckchange", onBeforeCheck);
37840 * Ext JS Library 1.1.1
37841 * Copyright(c) 2006-2007, Ext JS, LLC.
37843 * Originally Released Under LGPL - original licence link has changed is not relivant.
37846 * <script type="text/javascript">
37851 * @class Roo.menu.BaseItem
37852 * @extends Roo.Component
37853 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37854 * management and base configuration options shared by all menu components.
37856 * Creates a new BaseItem
37857 * @param {Object} config Configuration options
37859 Roo.menu.BaseItem = function(config){
37860 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37865 * Fires when this item is clicked
37866 * @param {Roo.menu.BaseItem} this
37867 * @param {Roo.EventObject} e
37872 * Fires when this item is activated
37873 * @param {Roo.menu.BaseItem} this
37877 * @event deactivate
37878 * Fires when this item is deactivated
37879 * @param {Roo.menu.BaseItem} this
37885 this.on("click", this.handler, this.scope, true);
37889 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37891 * @cfg {Function} handler
37892 * A function that will handle the click event of this menu item (defaults to undefined)
37895 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37897 canActivate : false,
37900 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37905 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37907 activeClass : "x-menu-item-active",
37909 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37911 hideOnClick : true,
37913 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37918 ctype: "Roo.menu.BaseItem",
37921 actionMode : "container",
37924 render : function(container, parentMenu){
37925 this.parentMenu = parentMenu;
37926 Roo.menu.BaseItem.superclass.render.call(this, container);
37927 this.container.menuItemId = this.id;
37931 onRender : function(container, position){
37932 this.el = Roo.get(this.el);
37933 container.dom.appendChild(this.el.dom);
37937 onClick : function(e){
37938 if(!this.disabled && this.fireEvent("click", this, e) !== false
37939 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37940 this.handleClick(e);
37947 activate : function(){
37951 var li = this.container;
37952 li.addClass(this.activeClass);
37953 this.region = li.getRegion().adjust(2, 2, -2, -2);
37954 this.fireEvent("activate", this);
37959 deactivate : function(){
37960 this.container.removeClass(this.activeClass);
37961 this.fireEvent("deactivate", this);
37965 shouldDeactivate : function(e){
37966 return !this.region || !this.region.contains(e.getPoint());
37970 handleClick : function(e){
37971 if(this.hideOnClick){
37972 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37977 expandMenu : function(autoActivate){
37982 hideMenu : function(){
37987 * Ext JS Library 1.1.1
37988 * Copyright(c) 2006-2007, Ext JS, LLC.
37990 * Originally Released Under LGPL - original licence link has changed is not relivant.
37993 * <script type="text/javascript">
37997 * @class Roo.menu.Adapter
37998 * @extends Roo.menu.BaseItem
37999 * 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.
38000 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38002 * Creates a new Adapter
38003 * @param {Object} config Configuration options
38005 Roo.menu.Adapter = function(component, config){
38006 Roo.menu.Adapter.superclass.constructor.call(this, config);
38007 this.component = component;
38009 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38011 canActivate : true,
38014 onRender : function(container, position){
38015 this.component.render(container);
38016 this.el = this.component.getEl();
38020 activate : function(){
38024 this.component.focus();
38025 this.fireEvent("activate", this);
38030 deactivate : function(){
38031 this.fireEvent("deactivate", this);
38035 disable : function(){
38036 this.component.disable();
38037 Roo.menu.Adapter.superclass.disable.call(this);
38041 enable : function(){
38042 this.component.enable();
38043 Roo.menu.Adapter.superclass.enable.call(this);
38047 * Ext JS Library 1.1.1
38048 * Copyright(c) 2006-2007, Ext JS, LLC.
38050 * Originally Released Under LGPL - original licence link has changed is not relivant.
38053 * <script type="text/javascript">
38057 * @class Roo.menu.TextItem
38058 * @extends Roo.menu.BaseItem
38059 * Adds a static text string to a menu, usually used as either a heading or group separator.
38060 * Note: old style constructor with text is still supported.
38063 * Creates a new TextItem
38064 * @param {Object} cfg Configuration
38066 Roo.menu.TextItem = function(cfg){
38067 if (typeof(cfg) == 'string') {
38070 Roo.apply(this,cfg);
38073 Roo.menu.TextItem.superclass.constructor.call(this);
38076 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38078 * @cfg {Boolean} text Text to show on item.
38083 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38085 hideOnClick : false,
38087 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38089 itemCls : "x-menu-text",
38092 onRender : function(){
38093 var s = document.createElement("span");
38094 s.className = this.itemCls;
38095 s.innerHTML = this.text;
38097 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38101 * Ext JS Library 1.1.1
38102 * Copyright(c) 2006-2007, Ext JS, LLC.
38104 * Originally Released Under LGPL - original licence link has changed is not relivant.
38107 * <script type="text/javascript">
38111 * @class Roo.menu.Separator
38112 * @extends Roo.menu.BaseItem
38113 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38114 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38116 * @param {Object} config Configuration options
38118 Roo.menu.Separator = function(config){
38119 Roo.menu.Separator.superclass.constructor.call(this, config);
38122 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38124 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38126 itemCls : "x-menu-sep",
38128 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38130 hideOnClick : false,
38133 onRender : function(li){
38134 var s = document.createElement("span");
38135 s.className = this.itemCls;
38136 s.innerHTML = " ";
38138 li.addClass("x-menu-sep-li");
38139 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38143 * Ext JS Library 1.1.1
38144 * Copyright(c) 2006-2007, Ext JS, LLC.
38146 * Originally Released Under LGPL - original licence link has changed is not relivant.
38149 * <script type="text/javascript">
38152 * @class Roo.menu.Item
38153 * @extends Roo.menu.BaseItem
38154 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38155 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38156 * activation and click handling.
38158 * Creates a new Item
38159 * @param {Object} config Configuration options
38161 Roo.menu.Item = function(config){
38162 Roo.menu.Item.superclass.constructor.call(this, config);
38164 this.menu = Roo.menu.MenuMgr.get(this.menu);
38167 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38170 * @cfg {String} text
38171 * The text to show on the menu item.
38175 * @cfg {String} HTML to render in menu
38176 * The text to show on the menu item (HTML version).
38180 * @cfg {String} icon
38181 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38185 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38187 itemCls : "x-menu-item",
38189 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38191 canActivate : true,
38193 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38196 // doc'd in BaseItem
38200 ctype: "Roo.menu.Item",
38203 onRender : function(container, position){
38204 var el = document.createElement("a");
38205 el.hideFocus = true;
38206 el.unselectable = "on";
38207 el.href = this.href || "#";
38208 if(this.hrefTarget){
38209 el.target = this.hrefTarget;
38211 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38213 var html = this.html.length ? this.html : String.format('{0}',this.text);
38215 el.innerHTML = String.format(
38216 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38217 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38219 Roo.menu.Item.superclass.onRender.call(this, container, position);
38223 * Sets the text to display in this menu item
38224 * @param {String} text The text to display
38225 * @param {Boolean} isHTML true to indicate text is pure html.
38227 setText : function(text, isHTML){
38235 var html = this.html.length ? this.html : String.format('{0}',this.text);
38237 this.el.update(String.format(
38238 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38239 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38240 this.parentMenu.autoWidth();
38245 handleClick : function(e){
38246 if(!this.href){ // if no link defined, stop the event automatically
38249 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38253 activate : function(autoExpand){
38254 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38264 shouldDeactivate : function(e){
38265 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38266 if(this.menu && this.menu.isVisible()){
38267 return !this.menu.getEl().getRegion().contains(e.getPoint());
38275 deactivate : function(){
38276 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38281 expandMenu : function(autoActivate){
38282 if(!this.disabled && this.menu){
38283 clearTimeout(this.hideTimer);
38284 delete this.hideTimer;
38285 if(!this.menu.isVisible() && !this.showTimer){
38286 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38287 }else if (this.menu.isVisible() && autoActivate){
38288 this.menu.tryActivate(0, 1);
38294 deferExpand : function(autoActivate){
38295 delete this.showTimer;
38296 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38298 this.menu.tryActivate(0, 1);
38303 hideMenu : function(){
38304 clearTimeout(this.showTimer);
38305 delete this.showTimer;
38306 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38307 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38312 deferHide : function(){
38313 delete this.hideTimer;
38318 * Ext JS Library 1.1.1
38319 * Copyright(c) 2006-2007, Ext JS, LLC.
38321 * Originally Released Under LGPL - original licence link has changed is not relivant.
38324 * <script type="text/javascript">
38328 * @class Roo.menu.CheckItem
38329 * @extends Roo.menu.Item
38330 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38332 * Creates a new CheckItem
38333 * @param {Object} config Configuration options
38335 Roo.menu.CheckItem = function(config){
38336 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38339 * @event beforecheckchange
38340 * Fires before the checked value is set, providing an opportunity to cancel if needed
38341 * @param {Roo.menu.CheckItem} this
38342 * @param {Boolean} checked The new checked value that will be set
38344 "beforecheckchange" : true,
38346 * @event checkchange
38347 * Fires after the checked value has been set
38348 * @param {Roo.menu.CheckItem} this
38349 * @param {Boolean} checked The checked value that was set
38351 "checkchange" : true
38353 if(this.checkHandler){
38354 this.on('checkchange', this.checkHandler, this.scope);
38357 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38359 * @cfg {String} group
38360 * All check items with the same group name will automatically be grouped into a single-select
38361 * radio button group (defaults to '')
38364 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38366 itemCls : "x-menu-item x-menu-check-item",
38368 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38370 groupClass : "x-menu-group-item",
38373 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38374 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38375 * initialized with checked = true will be rendered as checked.
38380 ctype: "Roo.menu.CheckItem",
38383 onRender : function(c){
38384 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38386 this.el.addClass(this.groupClass);
38388 Roo.menu.MenuMgr.registerCheckable(this);
38390 this.checked = false;
38391 this.setChecked(true, true);
38396 destroy : function(){
38398 Roo.menu.MenuMgr.unregisterCheckable(this);
38400 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38404 * Set the checked state of this item
38405 * @param {Boolean} checked The new checked value
38406 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38408 setChecked : function(state, suppressEvent){
38409 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38410 if(this.container){
38411 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38413 this.checked = state;
38414 if(suppressEvent !== true){
38415 this.fireEvent("checkchange", this, state);
38421 handleClick : function(e){
38422 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38423 this.setChecked(!this.checked);
38425 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38429 * Ext JS Library 1.1.1
38430 * Copyright(c) 2006-2007, Ext JS, LLC.
38432 * Originally Released Under LGPL - original licence link has changed is not relivant.
38435 * <script type="text/javascript">
38439 * @class Roo.menu.DateItem
38440 * @extends Roo.menu.Adapter
38441 * A menu item that wraps the {@link Roo.DatPicker} component.
38443 * Creates a new DateItem
38444 * @param {Object} config Configuration options
38446 Roo.menu.DateItem = function(config){
38447 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38448 /** The Roo.DatePicker object @type Roo.DatePicker */
38449 this.picker = this.component;
38450 this.addEvents({select: true});
38452 this.picker.on("render", function(picker){
38453 picker.getEl().swallowEvent("click");
38454 picker.container.addClass("x-menu-date-item");
38457 this.picker.on("select", this.onSelect, this);
38460 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38462 onSelect : function(picker, date){
38463 this.fireEvent("select", this, date, picker);
38464 Roo.menu.DateItem.superclass.handleClick.call(this);
38468 * Ext JS Library 1.1.1
38469 * Copyright(c) 2006-2007, Ext JS, LLC.
38471 * Originally Released Under LGPL - original licence link has changed is not relivant.
38474 * <script type="text/javascript">
38478 * @class Roo.menu.ColorItem
38479 * @extends Roo.menu.Adapter
38480 * A menu item that wraps the {@link Roo.ColorPalette} component.
38482 * Creates a new ColorItem
38483 * @param {Object} config Configuration options
38485 Roo.menu.ColorItem = function(config){
38486 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38487 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38488 this.palette = this.component;
38489 this.relayEvents(this.palette, ["select"]);
38490 if(this.selectHandler){
38491 this.on('select', this.selectHandler, this.scope);
38494 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38496 * Ext JS Library 1.1.1
38497 * Copyright(c) 2006-2007, Ext JS, LLC.
38499 * Originally Released Under LGPL - original licence link has changed is not relivant.
38502 * <script type="text/javascript">
38507 * @class Roo.menu.DateMenu
38508 * @extends Roo.menu.Menu
38509 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38511 * Creates a new DateMenu
38512 * @param {Object} config Configuration options
38514 Roo.menu.DateMenu = function(config){
38515 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38517 var di = new Roo.menu.DateItem(config);
38520 * The {@link Roo.DatePicker} instance for this DateMenu
38523 this.picker = di.picker;
38526 * @param {DatePicker} picker
38527 * @param {Date} date
38529 this.relayEvents(di, ["select"]);
38530 this.on('beforeshow', function(){
38532 this.picker.hideMonthPicker(false);
38536 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38540 * Ext JS Library 1.1.1
38541 * Copyright(c) 2006-2007, Ext JS, LLC.
38543 * Originally Released Under LGPL - original licence link has changed is not relivant.
38546 * <script type="text/javascript">
38551 * @class Roo.menu.ColorMenu
38552 * @extends Roo.menu.Menu
38553 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38555 * Creates a new ColorMenu
38556 * @param {Object} config Configuration options
38558 Roo.menu.ColorMenu = function(config){
38559 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38561 var ci = new Roo.menu.ColorItem(config);
38564 * The {@link Roo.ColorPalette} instance for this ColorMenu
38565 * @type ColorPalette
38567 this.palette = ci.palette;
38570 * @param {ColorPalette} palette
38571 * @param {String} color
38573 this.relayEvents(ci, ["select"]);
38575 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38577 * Ext JS Library 1.1.1
38578 * Copyright(c) 2006-2007, Ext JS, LLC.
38580 * Originally Released Under LGPL - original licence link has changed is not relivant.
38583 * <script type="text/javascript">
38587 * @class Roo.form.Field
38588 * @extends Roo.BoxComponent
38589 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38591 * Creates a new Field
38592 * @param {Object} config Configuration options
38594 Roo.form.Field = function(config){
38595 Roo.form.Field.superclass.constructor.call(this, config);
38598 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38600 * @cfg {String} fieldLabel Label to use when rendering a form.
38603 * @cfg {String} qtip Mouse over tip
38607 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38609 invalidClass : "x-form-invalid",
38611 * @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")
38613 invalidText : "The value in this field is invalid",
38615 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38617 focusClass : "x-form-focus",
38619 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38620 automatic validation (defaults to "keyup").
38622 validationEvent : "keyup",
38624 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38626 validateOnBlur : true,
38628 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38630 validationDelay : 250,
38632 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38633 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38635 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38637 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38639 fieldClass : "x-form-field",
38641 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38644 ----------- ----------------------------------------------------------------------
38645 qtip Display a quick tip when the user hovers over the field
38646 title Display a default browser title attribute popup
38647 under Add a block div beneath the field containing the error text
38648 side Add an error icon to the right of the field with a popup on hover
38649 [element id] Add the error text directly to the innerHTML of the specified element
38652 msgTarget : 'qtip',
38654 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38659 * @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.
38664 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38669 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38671 inputType : undefined,
38674 * @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).
38676 tabIndex : undefined,
38679 isFormField : true,
38684 * @property {Roo.Element} fieldEl
38685 * Element Containing the rendered Field (with label etc.)
38688 * @cfg {Mixed} value A value to initialize this field with.
38693 * @cfg {String} name The field's HTML name attribute.
38696 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38699 loadedValue : false,
38703 initComponent : function(){
38704 Roo.form.Field.superclass.initComponent.call(this);
38708 * Fires when this field receives input focus.
38709 * @param {Roo.form.Field} this
38714 * Fires when this field loses input focus.
38715 * @param {Roo.form.Field} this
38719 * @event specialkey
38720 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38721 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38722 * @param {Roo.form.Field} this
38723 * @param {Roo.EventObject} e The event object
38728 * Fires just before the field blurs if the field value has changed.
38729 * @param {Roo.form.Field} this
38730 * @param {Mixed} newValue The new value
38731 * @param {Mixed} oldValue The original value
38736 * Fires after the field has been marked as invalid.
38737 * @param {Roo.form.Field} this
38738 * @param {String} msg The validation message
38743 * Fires after the field has been validated with no errors.
38744 * @param {Roo.form.Field} this
38749 * Fires after the key up
38750 * @param {Roo.form.Field} this
38751 * @param {Roo.EventObject} e The event Object
38758 * Returns the name attribute of the field if available
38759 * @return {String} name The field name
38761 getName: function(){
38762 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38766 onRender : function(ct, position){
38767 Roo.form.Field.superclass.onRender.call(this, ct, position);
38769 var cfg = this.getAutoCreate();
38771 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38773 if (!cfg.name.length) {
38776 if(this.inputType){
38777 cfg.type = this.inputType;
38779 this.el = ct.createChild(cfg, position);
38781 var type = this.el.dom.type;
38783 if(type == 'password'){
38786 this.el.addClass('x-form-'+type);
38789 this.el.dom.readOnly = true;
38791 if(this.tabIndex !== undefined){
38792 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38795 this.el.addClass([this.fieldClass, this.cls]);
38800 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38801 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38802 * @return {Roo.form.Field} this
38804 applyTo : function(target){
38805 this.allowDomMove = false;
38806 this.el = Roo.get(target);
38807 this.render(this.el.dom.parentNode);
38812 initValue : function(){
38813 if(this.value !== undefined){
38814 this.setValue(this.value);
38815 }else if(this.el.dom.value.length > 0){
38816 this.setValue(this.el.dom.value);
38821 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38822 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38824 isDirty : function() {
38825 if(this.disabled) {
38828 return String(this.getValue()) !== String(this.originalValue);
38832 * stores the current value in loadedValue
38834 resetHasChanged : function()
38836 this.loadedValue = String(this.getValue());
38839 * checks the current value against the 'loaded' value.
38840 * Note - will return false if 'resetHasChanged' has not been called first.
38842 hasChanged : function()
38844 if(this.disabled || this.readOnly) {
38847 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38853 afterRender : function(){
38854 Roo.form.Field.superclass.afterRender.call(this);
38859 fireKey : function(e){
38860 //Roo.log('field ' + e.getKey());
38861 if(e.isNavKeyPress()){
38862 this.fireEvent("specialkey", this, e);
38867 * Resets the current field value to the originally loaded value and clears any validation messages
38869 reset : function(){
38870 this.setValue(this.resetValue);
38871 this.clearInvalid();
38875 initEvents : function(){
38876 // safari killled keypress - so keydown is now used..
38877 this.el.on("keydown" , this.fireKey, this);
38878 this.el.on("focus", this.onFocus, this);
38879 this.el.on("blur", this.onBlur, this);
38880 this.el.relayEvent('keyup', this);
38882 // reference to original value for reset
38883 this.originalValue = this.getValue();
38884 this.resetValue = this.getValue();
38888 onFocus : function(){
38889 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38890 this.el.addClass(this.focusClass);
38892 if(!this.hasFocus){
38893 this.hasFocus = true;
38894 this.startValue = this.getValue();
38895 this.fireEvent("focus", this);
38899 beforeBlur : Roo.emptyFn,
38902 onBlur : function(){
38904 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38905 this.el.removeClass(this.focusClass);
38907 this.hasFocus = false;
38908 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38911 var v = this.getValue();
38912 if(String(v) !== String(this.startValue)){
38913 this.fireEvent('change', this, v, this.startValue);
38915 this.fireEvent("blur", this);
38919 * Returns whether or not the field value is currently valid
38920 * @param {Boolean} preventMark True to disable marking the field invalid
38921 * @return {Boolean} True if the value is valid, else false
38923 isValid : function(preventMark){
38927 var restore = this.preventMark;
38928 this.preventMark = preventMark === true;
38929 var v = this.validateValue(this.processValue(this.getRawValue()));
38930 this.preventMark = restore;
38935 * Validates the field value
38936 * @return {Boolean} True if the value is valid, else false
38938 validate : function(){
38939 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38940 this.clearInvalid();
38946 processValue : function(value){
38951 // Subclasses should provide the validation implementation by overriding this
38952 validateValue : function(value){
38957 * Mark this field as invalid
38958 * @param {String} msg The validation message
38960 markInvalid : function(msg){
38961 if(!this.rendered || this.preventMark){ // not rendered
38965 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38967 obj.el.addClass(this.invalidClass);
38968 msg = msg || this.invalidText;
38969 switch(this.msgTarget){
38971 obj.el.dom.qtip = msg;
38972 obj.el.dom.qclass = 'x-form-invalid-tip';
38973 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38974 Roo.QuickTips.enable();
38978 this.el.dom.title = msg;
38982 var elp = this.el.findParent('.x-form-element', 5, true);
38983 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38984 this.errorEl.setWidth(elp.getWidth(true)-20);
38986 this.errorEl.update(msg);
38987 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38990 if(!this.errorIcon){
38991 var elp = this.el.findParent('.x-form-element', 5, true);
38992 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38994 this.alignErrorIcon();
38995 this.errorIcon.dom.qtip = msg;
38996 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38997 this.errorIcon.show();
38998 this.on('resize', this.alignErrorIcon, this);
39001 var t = Roo.getDom(this.msgTarget);
39003 t.style.display = this.msgDisplay;
39006 this.fireEvent('invalid', this, msg);
39010 alignErrorIcon : function(){
39011 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39015 * Clear any invalid styles/messages for this field
39017 clearInvalid : function(){
39018 if(!this.rendered || this.preventMark){ // not rendered
39021 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39023 obj.el.removeClass(this.invalidClass);
39024 switch(this.msgTarget){
39026 obj.el.dom.qtip = '';
39029 this.el.dom.title = '';
39033 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39037 if(this.errorIcon){
39038 this.errorIcon.dom.qtip = '';
39039 this.errorIcon.hide();
39040 this.un('resize', this.alignErrorIcon, this);
39044 var t = Roo.getDom(this.msgTarget);
39046 t.style.display = 'none';
39049 this.fireEvent('valid', this);
39053 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39054 * @return {Mixed} value The field value
39056 getRawValue : function(){
39057 var v = this.el.getValue();
39063 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39064 * @return {Mixed} value The field value
39066 getValue : function(){
39067 var v = this.el.getValue();
39073 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39074 * @param {Mixed} value The value to set
39076 setRawValue : function(v){
39077 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39081 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39082 * @param {Mixed} value The value to set
39084 setValue : function(v){
39087 this.el.dom.value = (v === null || v === undefined ? '' : v);
39092 adjustSize : function(w, h){
39093 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39094 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39098 adjustWidth : function(tag, w){
39099 tag = tag.toLowerCase();
39100 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39101 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39102 if(tag == 'input'){
39105 if(tag == 'textarea'){
39108 }else if(Roo.isOpera){
39109 if(tag == 'input'){
39112 if(tag == 'textarea'){
39122 // anything other than normal should be considered experimental
39123 Roo.form.Field.msgFx = {
39125 show: function(msgEl, f){
39126 msgEl.setDisplayed('block');
39129 hide : function(msgEl, f){
39130 msgEl.setDisplayed(false).update('');
39135 show: function(msgEl, f){
39136 msgEl.slideIn('t', {stopFx:true});
39139 hide : function(msgEl, f){
39140 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39145 show: function(msgEl, f){
39146 msgEl.fixDisplay();
39147 msgEl.alignTo(f.el, 'tl-tr');
39148 msgEl.slideIn('l', {stopFx:true});
39151 hide : function(msgEl, f){
39152 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39157 * Ext JS Library 1.1.1
39158 * Copyright(c) 2006-2007, Ext JS, LLC.
39160 * Originally Released Under LGPL - original licence link has changed is not relivant.
39163 * <script type="text/javascript">
39168 * @class Roo.form.TextField
39169 * @extends Roo.form.Field
39170 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39171 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39173 * Creates a new TextField
39174 * @param {Object} config Configuration options
39176 Roo.form.TextField = function(config){
39177 Roo.form.TextField.superclass.constructor.call(this, config);
39181 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39182 * according to the default logic, but this event provides a hook for the developer to apply additional
39183 * logic at runtime to resize the field if needed.
39184 * @param {Roo.form.Field} this This text field
39185 * @param {Number} width The new field width
39191 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39193 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39197 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39201 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39205 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39209 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39213 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39215 disableKeyFilter : false,
39217 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39221 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39225 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39227 maxLength : Number.MAX_VALUE,
39229 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39231 minLengthText : "The minimum length for this field is {0}",
39233 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39235 maxLengthText : "The maximum length for this field is {0}",
39237 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39239 selectOnFocus : false,
39241 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39243 blankText : "This field is required",
39245 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39246 * If available, this function will be called only after the basic validators all return true, and will be passed the
39247 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39251 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39252 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39253 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39257 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39261 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39267 initEvents : function()
39269 if (this.emptyText) {
39270 this.el.attr('placeholder', this.emptyText);
39273 Roo.form.TextField.superclass.initEvents.call(this);
39274 if(this.validationEvent == 'keyup'){
39275 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39276 this.el.on('keyup', this.filterValidation, this);
39278 else if(this.validationEvent !== false){
39279 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39282 if(this.selectOnFocus){
39283 this.on("focus", this.preFocus, this);
39286 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39287 this.el.on("keypress", this.filterKeys, this);
39290 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39291 this.el.on("click", this.autoSize, this);
39293 if(this.el.is('input[type=password]') && Roo.isSafari){
39294 this.el.on('keydown', this.SafariOnKeyDown, this);
39298 processValue : function(value){
39299 if(this.stripCharsRe){
39300 var newValue = value.replace(this.stripCharsRe, '');
39301 if(newValue !== value){
39302 this.setRawValue(newValue);
39309 filterValidation : function(e){
39310 if(!e.isNavKeyPress()){
39311 this.validationTask.delay(this.validationDelay);
39316 onKeyUp : function(e){
39317 if(!e.isNavKeyPress()){
39323 * Resets the current field value to the originally-loaded value and clears any validation messages.
39326 reset : function(){
39327 Roo.form.TextField.superclass.reset.call(this);
39333 preFocus : function(){
39335 if(this.selectOnFocus){
39336 this.el.dom.select();
39342 filterKeys : function(e){
39343 var k = e.getKey();
39344 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39347 var c = e.getCharCode(), cc = String.fromCharCode(c);
39348 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39351 if(!this.maskRe.test(cc)){
39356 setValue : function(v){
39358 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39364 * Validates a value according to the field's validation rules and marks the field as invalid
39365 * if the validation fails
39366 * @param {Mixed} value The value to validate
39367 * @return {Boolean} True if the value is valid, else false
39369 validateValue : function(value){
39370 if(value.length < 1) { // if it's blank
39371 if(this.allowBlank){
39372 this.clearInvalid();
39375 this.markInvalid(this.blankText);
39379 if(value.length < this.minLength){
39380 this.markInvalid(String.format(this.minLengthText, this.minLength));
39383 if(value.length > this.maxLength){
39384 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39388 var vt = Roo.form.VTypes;
39389 if(!vt[this.vtype](value, this)){
39390 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39394 if(typeof this.validator == "function"){
39395 var msg = this.validator(value);
39397 this.markInvalid(msg);
39401 if(this.regex && !this.regex.test(value)){
39402 this.markInvalid(this.regexText);
39409 * Selects text in this field
39410 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39411 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39413 selectText : function(start, end){
39414 var v = this.getRawValue();
39416 start = start === undefined ? 0 : start;
39417 end = end === undefined ? v.length : end;
39418 var d = this.el.dom;
39419 if(d.setSelectionRange){
39420 d.setSelectionRange(start, end);
39421 }else if(d.createTextRange){
39422 var range = d.createTextRange();
39423 range.moveStart("character", start);
39424 range.moveEnd("character", v.length-end);
39431 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39432 * This only takes effect if grow = true, and fires the autosize event.
39434 autoSize : function(){
39435 if(!this.grow || !this.rendered){
39439 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39442 var v = el.dom.value;
39443 var d = document.createElement('div');
39444 d.appendChild(document.createTextNode(v));
39448 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39449 this.el.setWidth(w);
39450 this.fireEvent("autosize", this, w);
39454 SafariOnKeyDown : function(event)
39456 // this is a workaround for a password hang bug on chrome/ webkit.
39458 var isSelectAll = false;
39460 if(this.el.dom.selectionEnd > 0){
39461 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39463 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39464 event.preventDefault();
39469 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39471 event.preventDefault();
39472 // this is very hacky as keydown always get's upper case.
39474 var cc = String.fromCharCode(event.getCharCode());
39477 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39485 * Ext JS Library 1.1.1
39486 * Copyright(c) 2006-2007, Ext JS, LLC.
39488 * Originally Released Under LGPL - original licence link has changed is not relivant.
39491 * <script type="text/javascript">
39495 * @class Roo.form.Hidden
39496 * @extends Roo.form.TextField
39497 * Simple Hidden element used on forms
39499 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39502 * Creates a new Hidden form element.
39503 * @param {Object} config Configuration options
39508 // easy hidden field...
39509 Roo.form.Hidden = function(config){
39510 Roo.form.Hidden.superclass.constructor.call(this, config);
39513 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39515 inputType: 'hidden',
39518 labelSeparator: '',
39520 itemCls : 'x-form-item-display-none'
39528 * Ext JS Library 1.1.1
39529 * Copyright(c) 2006-2007, Ext JS, LLC.
39531 * Originally Released Under LGPL - original licence link has changed is not relivant.
39534 * <script type="text/javascript">
39538 * @class Roo.form.TriggerField
39539 * @extends Roo.form.TextField
39540 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39541 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39542 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39543 * for which you can provide a custom implementation. For example:
39545 var trigger = new Roo.form.TriggerField();
39546 trigger.onTriggerClick = myTriggerFn;
39547 trigger.applyTo('my-field');
39550 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39551 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39552 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39553 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39555 * Create a new TriggerField.
39556 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39557 * to the base TextField)
39559 Roo.form.TriggerField = function(config){
39560 this.mimicing = false;
39561 Roo.form.TriggerField.superclass.constructor.call(this, config);
39564 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39566 * @cfg {String} triggerClass A CSS class to apply to the trigger
39569 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39570 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39572 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39574 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39578 /** @cfg {Boolean} grow @hide */
39579 /** @cfg {Number} growMin @hide */
39580 /** @cfg {Number} growMax @hide */
39586 autoSize: Roo.emptyFn,
39590 deferHeight : true,
39593 actionMode : 'wrap',
39595 onResize : function(w, h){
39596 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39597 if(typeof w == 'number'){
39598 var x = w - this.trigger.getWidth();
39599 this.el.setWidth(this.adjustWidth('input', x));
39600 this.trigger.setStyle('left', x+'px');
39605 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39608 getResizeEl : function(){
39613 getPositionEl : function(){
39618 alignErrorIcon : function(){
39619 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39623 onRender : function(ct, position){
39624 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39625 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39626 this.trigger = this.wrap.createChild(this.triggerConfig ||
39627 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39628 if(this.hideTrigger){
39629 this.trigger.setDisplayed(false);
39631 this.initTrigger();
39633 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39638 initTrigger : function(){
39639 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39640 this.trigger.addClassOnOver('x-form-trigger-over');
39641 this.trigger.addClassOnClick('x-form-trigger-click');
39645 onDestroy : function(){
39647 this.trigger.removeAllListeners();
39648 this.trigger.remove();
39651 this.wrap.remove();
39653 Roo.form.TriggerField.superclass.onDestroy.call(this);
39657 onFocus : function(){
39658 Roo.form.TriggerField.superclass.onFocus.call(this);
39659 if(!this.mimicing){
39660 this.wrap.addClass('x-trigger-wrap-focus');
39661 this.mimicing = true;
39662 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39663 if(this.monitorTab){
39664 this.el.on("keydown", this.checkTab, this);
39670 checkTab : function(e){
39671 if(e.getKey() == e.TAB){
39672 this.triggerBlur();
39677 onBlur : function(){
39682 mimicBlur : function(e, t){
39683 if(!this.wrap.contains(t) && this.validateBlur()){
39684 this.triggerBlur();
39689 triggerBlur : function(){
39690 this.mimicing = false;
39691 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39692 if(this.monitorTab){
39693 this.el.un("keydown", this.checkTab, this);
39695 this.wrap.removeClass('x-trigger-wrap-focus');
39696 Roo.form.TriggerField.superclass.onBlur.call(this);
39700 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39701 validateBlur : function(e, t){
39706 onDisable : function(){
39707 Roo.form.TriggerField.superclass.onDisable.call(this);
39709 this.wrap.addClass('x-item-disabled');
39714 onEnable : function(){
39715 Roo.form.TriggerField.superclass.onEnable.call(this);
39717 this.wrap.removeClass('x-item-disabled');
39722 onShow : function(){
39723 var ae = this.getActionEl();
39726 ae.dom.style.display = '';
39727 ae.dom.style.visibility = 'visible';
39733 onHide : function(){
39734 var ae = this.getActionEl();
39735 ae.dom.style.display = 'none';
39739 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39740 * by an implementing function.
39742 * @param {EventObject} e
39744 onTriggerClick : Roo.emptyFn
39747 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39748 // to be extended by an implementing class. For an example of implementing this class, see the custom
39749 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39750 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39751 initComponent : function(){
39752 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39754 this.triggerConfig = {
39755 tag:'span', cls:'x-form-twin-triggers', cn:[
39756 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39757 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39761 getTrigger : function(index){
39762 return this.triggers[index];
39765 initTrigger : function(){
39766 var ts = this.trigger.select('.x-form-trigger', true);
39767 this.wrap.setStyle('overflow', 'hidden');
39768 var triggerField = this;
39769 ts.each(function(t, all, index){
39770 t.hide = function(){
39771 var w = triggerField.wrap.getWidth();
39772 this.dom.style.display = 'none';
39773 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39775 t.show = function(){
39776 var w = triggerField.wrap.getWidth();
39777 this.dom.style.display = '';
39778 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39780 var triggerIndex = 'Trigger'+(index+1);
39782 if(this['hide'+triggerIndex]){
39783 t.dom.style.display = 'none';
39785 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39786 t.addClassOnOver('x-form-trigger-over');
39787 t.addClassOnClick('x-form-trigger-click');
39789 this.triggers = ts.elements;
39792 onTrigger1Click : Roo.emptyFn,
39793 onTrigger2Click : Roo.emptyFn
39796 * Ext JS Library 1.1.1
39797 * Copyright(c) 2006-2007, Ext JS, LLC.
39799 * Originally Released Under LGPL - original licence link has changed is not relivant.
39802 * <script type="text/javascript">
39806 * @class Roo.form.TextArea
39807 * @extends Roo.form.TextField
39808 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39809 * support for auto-sizing.
39811 * Creates a new TextArea
39812 * @param {Object} config Configuration options
39814 Roo.form.TextArea = function(config){
39815 Roo.form.TextArea.superclass.constructor.call(this, config);
39816 // these are provided exchanges for backwards compat
39817 // minHeight/maxHeight were replaced by growMin/growMax to be
39818 // compatible with TextField growing config values
39819 if(this.minHeight !== undefined){
39820 this.growMin = this.minHeight;
39822 if(this.maxHeight !== undefined){
39823 this.growMax = this.maxHeight;
39827 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39829 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39833 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39837 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39838 * in the field (equivalent to setting overflow: hidden, defaults to false)
39840 preventScrollbars: false,
39842 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39843 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39847 onRender : function(ct, position){
39849 this.defaultAutoCreate = {
39851 style:"width:300px;height:60px;",
39852 autocomplete: "new-password"
39855 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39857 this.textSizeEl = Roo.DomHelper.append(document.body, {
39858 tag: "pre", cls: "x-form-grow-sizer"
39860 if(this.preventScrollbars){
39861 this.el.setStyle("overflow", "hidden");
39863 this.el.setHeight(this.growMin);
39867 onDestroy : function(){
39868 if(this.textSizeEl){
39869 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39871 Roo.form.TextArea.superclass.onDestroy.call(this);
39875 onKeyUp : function(e){
39876 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39882 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39883 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39885 autoSize : function(){
39886 if(!this.grow || !this.textSizeEl){
39890 var v = el.dom.value;
39891 var ts = this.textSizeEl;
39894 ts.appendChild(document.createTextNode(v));
39897 Roo.fly(ts).setWidth(this.el.getWidth());
39899 v = "  ";
39902 v = v.replace(/\n/g, '<p> </p>');
39904 v += " \n ";
39907 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39908 if(h != this.lastHeight){
39909 this.lastHeight = h;
39910 this.el.setHeight(h);
39911 this.fireEvent("autosize", this, h);
39916 * Ext JS Library 1.1.1
39917 * Copyright(c) 2006-2007, Ext JS, LLC.
39919 * Originally Released Under LGPL - original licence link has changed is not relivant.
39922 * <script type="text/javascript">
39927 * @class Roo.form.NumberField
39928 * @extends Roo.form.TextField
39929 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39931 * Creates a new NumberField
39932 * @param {Object} config Configuration options
39934 Roo.form.NumberField = function(config){
39935 Roo.form.NumberField.superclass.constructor.call(this, config);
39938 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39940 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39942 fieldClass: "x-form-field x-form-num-field",
39944 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39946 allowDecimals : true,
39948 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39950 decimalSeparator : ".",
39952 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39954 decimalPrecision : 2,
39956 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39958 allowNegative : true,
39960 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39962 minValue : Number.NEGATIVE_INFINITY,
39964 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39966 maxValue : Number.MAX_VALUE,
39968 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39970 minText : "The minimum value for this field is {0}",
39972 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39974 maxText : "The maximum value for this field is {0}",
39976 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39977 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39979 nanText : "{0} is not a valid number",
39982 initEvents : function(){
39983 Roo.form.NumberField.superclass.initEvents.call(this);
39984 var allowed = "0123456789";
39985 if(this.allowDecimals){
39986 allowed += this.decimalSeparator;
39988 if(this.allowNegative){
39991 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39992 var keyPress = function(e){
39993 var k = e.getKey();
39994 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39997 var c = e.getCharCode();
39998 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40002 this.el.on("keypress", keyPress, this);
40006 validateValue : function(value){
40007 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40010 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40013 var num = this.parseValue(value);
40015 this.markInvalid(String.format(this.nanText, value));
40018 if(num < this.minValue){
40019 this.markInvalid(String.format(this.minText, this.minValue));
40022 if(num > this.maxValue){
40023 this.markInvalid(String.format(this.maxText, this.maxValue));
40029 getValue : function(){
40030 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40034 parseValue : function(value){
40035 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40036 return isNaN(value) ? '' : value;
40040 fixPrecision : function(value){
40041 var nan = isNaN(value);
40042 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40043 return nan ? '' : value;
40045 return parseFloat(value).toFixed(this.decimalPrecision);
40048 setValue : function(v){
40049 v = this.fixPrecision(v);
40050 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40054 decimalPrecisionFcn : function(v){
40055 return Math.floor(v);
40058 beforeBlur : function(){
40059 var v = this.parseValue(this.getRawValue());
40066 * Ext JS Library 1.1.1
40067 * Copyright(c) 2006-2007, Ext JS, LLC.
40069 * Originally Released Under LGPL - original licence link has changed is not relivant.
40072 * <script type="text/javascript">
40076 * @class Roo.form.DateField
40077 * @extends Roo.form.TriggerField
40078 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40080 * Create a new DateField
40081 * @param {Object} config
40083 Roo.form.DateField = function(config){
40084 Roo.form.DateField.superclass.constructor.call(this, config);
40090 * Fires when a date is selected
40091 * @param {Roo.form.DateField} combo This combo box
40092 * @param {Date} date The date selected
40099 if(typeof this.minValue == "string") {
40100 this.minValue = this.parseDate(this.minValue);
40102 if(typeof this.maxValue == "string") {
40103 this.maxValue = this.parseDate(this.maxValue);
40105 this.ddMatch = null;
40106 if(this.disabledDates){
40107 var dd = this.disabledDates;
40109 for(var i = 0; i < dd.length; i++){
40111 if(i != dd.length-1) {
40115 this.ddMatch = new RegExp(re + ")");
40119 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40121 * @cfg {String} format
40122 * The default date format string which can be overriden for localization support. The format must be
40123 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40127 * @cfg {String} altFormats
40128 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40129 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40131 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40133 * @cfg {Array} disabledDays
40134 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40136 disabledDays : null,
40138 * @cfg {String} disabledDaysText
40139 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40141 disabledDaysText : "Disabled",
40143 * @cfg {Array} disabledDates
40144 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40145 * expression so they are very powerful. Some examples:
40147 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40148 * <li>["03/08", "09/16"] would disable those days for every year</li>
40149 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40150 * <li>["03/../2006"] would disable every day in March 2006</li>
40151 * <li>["^03"] would disable every day in every March</li>
40153 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40154 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40156 disabledDates : null,
40158 * @cfg {String} disabledDatesText
40159 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40161 disabledDatesText : "Disabled",
40163 * @cfg {Date/String} minValue
40164 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40165 * valid format (defaults to null).
40169 * @cfg {Date/String} maxValue
40170 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40171 * valid format (defaults to null).
40175 * @cfg {String} minText
40176 * The error text to display when the date in the cell is before minValue (defaults to
40177 * 'The date in this field must be after {minValue}').
40179 minText : "The date in this field must be equal to or after {0}",
40181 * @cfg {String} maxText
40182 * The error text to display when the date in the cell is after maxValue (defaults to
40183 * 'The date in this field must be before {maxValue}').
40185 maxText : "The date in this field must be equal to or before {0}",
40187 * @cfg {String} invalidText
40188 * The error text to display when the date in the field is invalid (defaults to
40189 * '{value} is not a valid date - it must be in the format {format}').
40191 invalidText : "{0} is not a valid date - it must be in the format {1}",
40193 * @cfg {String} triggerClass
40194 * An additional CSS class used to style the trigger button. The trigger will always get the
40195 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40196 * which displays a calendar icon).
40198 triggerClass : 'x-form-date-trigger',
40202 * @cfg {Boolean} useIso
40203 * if enabled, then the date field will use a hidden field to store the
40204 * real value as iso formated date. default (false)
40208 * @cfg {String/Object} autoCreate
40209 * A DomHelper element spec, or true for a default element spec (defaults to
40210 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40213 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40216 hiddenField: false,
40218 onRender : function(ct, position)
40220 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40222 //this.el.dom.removeAttribute('name');
40223 Roo.log("Changing name?");
40224 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40225 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40227 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40228 // prevent input submission
40229 this.hiddenName = this.name;
40236 validateValue : function(value)
40238 value = this.formatDate(value);
40239 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40240 Roo.log('super failed');
40243 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40246 var svalue = value;
40247 value = this.parseDate(value);
40249 Roo.log('parse date failed' + svalue);
40250 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40253 var time = value.getTime();
40254 if(this.minValue && time < this.minValue.getTime()){
40255 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40258 if(this.maxValue && time > this.maxValue.getTime()){
40259 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40262 if(this.disabledDays){
40263 var day = value.getDay();
40264 for(var i = 0; i < this.disabledDays.length; i++) {
40265 if(day === this.disabledDays[i]){
40266 this.markInvalid(this.disabledDaysText);
40271 var fvalue = this.formatDate(value);
40272 if(this.ddMatch && this.ddMatch.test(fvalue)){
40273 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40280 // Provides logic to override the default TriggerField.validateBlur which just returns true
40281 validateBlur : function(){
40282 return !this.menu || !this.menu.isVisible();
40285 getName: function()
40287 // returns hidden if it's set..
40288 if (!this.rendered) {return ''};
40289 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40294 * Returns the current date value of the date field.
40295 * @return {Date} The date value
40297 getValue : function(){
40299 return this.hiddenField ?
40300 this.hiddenField.value :
40301 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40305 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40306 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40307 * (the default format used is "m/d/y").
40310 //All of these calls set the same date value (May 4, 2006)
40312 //Pass a date object:
40313 var dt = new Date('5/4/06');
40314 dateField.setValue(dt);
40316 //Pass a date string (default format):
40317 dateField.setValue('5/4/06');
40319 //Pass a date string (custom format):
40320 dateField.format = 'Y-m-d';
40321 dateField.setValue('2006-5-4');
40323 * @param {String/Date} date The date or valid date string
40325 setValue : function(date){
40326 if (this.hiddenField) {
40327 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40329 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40330 // make sure the value field is always stored as a date..
40331 this.value = this.parseDate(date);
40337 parseDate : function(value){
40338 if(!value || value instanceof Date){
40341 var v = Date.parseDate(value, this.format);
40342 if (!v && this.useIso) {
40343 v = Date.parseDate(value, 'Y-m-d');
40345 if(!v && this.altFormats){
40346 if(!this.altFormatsArray){
40347 this.altFormatsArray = this.altFormats.split("|");
40349 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40350 v = Date.parseDate(value, this.altFormatsArray[i]);
40357 formatDate : function(date, fmt){
40358 return (!date || !(date instanceof Date)) ?
40359 date : date.dateFormat(fmt || this.format);
40364 select: function(m, d){
40367 this.fireEvent('select', this, d);
40369 show : function(){ // retain focus styling
40373 this.focus.defer(10, this);
40374 var ml = this.menuListeners;
40375 this.menu.un("select", ml.select, this);
40376 this.menu.un("show", ml.show, this);
40377 this.menu.un("hide", ml.hide, this);
40382 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40383 onTriggerClick : function(){
40387 if(this.menu == null){
40388 this.menu = new Roo.menu.DateMenu();
40390 Roo.apply(this.menu.picker, {
40391 showClear: this.allowBlank,
40392 minDate : this.minValue,
40393 maxDate : this.maxValue,
40394 disabledDatesRE : this.ddMatch,
40395 disabledDatesText : this.disabledDatesText,
40396 disabledDays : this.disabledDays,
40397 disabledDaysText : this.disabledDaysText,
40398 format : this.useIso ? 'Y-m-d' : this.format,
40399 minText : String.format(this.minText, this.formatDate(this.minValue)),
40400 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40402 this.menu.on(Roo.apply({}, this.menuListeners, {
40405 this.menu.picker.setValue(this.getValue() || new Date());
40406 this.menu.show(this.el, "tl-bl?");
40409 beforeBlur : function(){
40410 var v = this.parseDate(this.getRawValue());
40420 isDirty : function() {
40421 if(this.disabled) {
40425 if(typeof(this.startValue) === 'undefined'){
40429 return String(this.getValue()) !== String(this.startValue);
40434 * Ext JS Library 1.1.1
40435 * Copyright(c) 2006-2007, Ext JS, LLC.
40437 * Originally Released Under LGPL - original licence link has changed is not relivant.
40440 * <script type="text/javascript">
40444 * @class Roo.form.MonthField
40445 * @extends Roo.form.TriggerField
40446 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40448 * Create a new MonthField
40449 * @param {Object} config
40451 Roo.form.MonthField = function(config){
40453 Roo.form.MonthField.superclass.constructor.call(this, config);
40459 * Fires when a date is selected
40460 * @param {Roo.form.MonthFieeld} combo This combo box
40461 * @param {Date} date The date selected
40468 if(typeof this.minValue == "string") {
40469 this.minValue = this.parseDate(this.minValue);
40471 if(typeof this.maxValue == "string") {
40472 this.maxValue = this.parseDate(this.maxValue);
40474 this.ddMatch = null;
40475 if(this.disabledDates){
40476 var dd = this.disabledDates;
40478 for(var i = 0; i < dd.length; i++){
40480 if(i != dd.length-1) {
40484 this.ddMatch = new RegExp(re + ")");
40488 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40490 * @cfg {String} format
40491 * The default date format string which can be overriden for localization support. The format must be
40492 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40496 * @cfg {String} altFormats
40497 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40498 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40500 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40502 * @cfg {Array} disabledDays
40503 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40505 disabledDays : [0,1,2,3,4,5,6],
40507 * @cfg {String} disabledDaysText
40508 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40510 disabledDaysText : "Disabled",
40512 * @cfg {Array} disabledDates
40513 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40514 * expression so they are very powerful. Some examples:
40516 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40517 * <li>["03/08", "09/16"] would disable those days for every year</li>
40518 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40519 * <li>["03/../2006"] would disable every day in March 2006</li>
40520 * <li>["^03"] would disable every day in every March</li>
40522 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40523 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40525 disabledDates : null,
40527 * @cfg {String} disabledDatesText
40528 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40530 disabledDatesText : "Disabled",
40532 * @cfg {Date/String} minValue
40533 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40534 * valid format (defaults to null).
40538 * @cfg {Date/String} maxValue
40539 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40540 * valid format (defaults to null).
40544 * @cfg {String} minText
40545 * The error text to display when the date in the cell is before minValue (defaults to
40546 * 'The date in this field must be after {minValue}').
40548 minText : "The date in this field must be equal to or after {0}",
40550 * @cfg {String} maxTextf
40551 * The error text to display when the date in the cell is after maxValue (defaults to
40552 * 'The date in this field must be before {maxValue}').
40554 maxText : "The date in this field must be equal to or before {0}",
40556 * @cfg {String} invalidText
40557 * The error text to display when the date in the field is invalid (defaults to
40558 * '{value} is not a valid date - it must be in the format {format}').
40560 invalidText : "{0} is not a valid date - it must be in the format {1}",
40562 * @cfg {String} triggerClass
40563 * An additional CSS class used to style the trigger button. The trigger will always get the
40564 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40565 * which displays a calendar icon).
40567 triggerClass : 'x-form-date-trigger',
40571 * @cfg {Boolean} useIso
40572 * if enabled, then the date field will use a hidden field to store the
40573 * real value as iso formated date. default (true)
40577 * @cfg {String/Object} autoCreate
40578 * A DomHelper element spec, or true for a default element spec (defaults to
40579 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40582 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40585 hiddenField: false,
40587 hideMonthPicker : false,
40589 onRender : function(ct, position)
40591 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40593 this.el.dom.removeAttribute('name');
40594 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40596 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40597 // prevent input submission
40598 this.hiddenName = this.name;
40605 validateValue : function(value)
40607 value = this.formatDate(value);
40608 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40611 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40614 var svalue = value;
40615 value = this.parseDate(value);
40617 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40620 var time = value.getTime();
40621 if(this.minValue && time < this.minValue.getTime()){
40622 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40625 if(this.maxValue && time > this.maxValue.getTime()){
40626 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40629 /*if(this.disabledDays){
40630 var day = value.getDay();
40631 for(var i = 0; i < this.disabledDays.length; i++) {
40632 if(day === this.disabledDays[i]){
40633 this.markInvalid(this.disabledDaysText);
40639 var fvalue = this.formatDate(value);
40640 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40641 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40649 // Provides logic to override the default TriggerField.validateBlur which just returns true
40650 validateBlur : function(){
40651 return !this.menu || !this.menu.isVisible();
40655 * Returns the current date value of the date field.
40656 * @return {Date} The date value
40658 getValue : function(){
40662 return this.hiddenField ?
40663 this.hiddenField.value :
40664 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40668 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40669 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40670 * (the default format used is "m/d/y").
40673 //All of these calls set the same date value (May 4, 2006)
40675 //Pass a date object:
40676 var dt = new Date('5/4/06');
40677 monthField.setValue(dt);
40679 //Pass a date string (default format):
40680 monthField.setValue('5/4/06');
40682 //Pass a date string (custom format):
40683 monthField.format = 'Y-m-d';
40684 monthField.setValue('2006-5-4');
40686 * @param {String/Date} date The date or valid date string
40688 setValue : function(date){
40689 Roo.log('month setValue' + date);
40690 // can only be first of month..
40692 var val = this.parseDate(date);
40694 if (this.hiddenField) {
40695 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40697 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40698 this.value = this.parseDate(date);
40702 parseDate : function(value){
40703 if(!value || value instanceof Date){
40704 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40707 var v = Date.parseDate(value, this.format);
40708 if (!v && this.useIso) {
40709 v = Date.parseDate(value, 'Y-m-d');
40713 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40717 if(!v && this.altFormats){
40718 if(!this.altFormatsArray){
40719 this.altFormatsArray = this.altFormats.split("|");
40721 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40722 v = Date.parseDate(value, this.altFormatsArray[i]);
40729 formatDate : function(date, fmt){
40730 return (!date || !(date instanceof Date)) ?
40731 date : date.dateFormat(fmt || this.format);
40736 select: function(m, d){
40738 this.fireEvent('select', this, d);
40740 show : function(){ // retain focus styling
40744 this.focus.defer(10, this);
40745 var ml = this.menuListeners;
40746 this.menu.un("select", ml.select, this);
40747 this.menu.un("show", ml.show, this);
40748 this.menu.un("hide", ml.hide, this);
40752 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40753 onTriggerClick : function(){
40757 if(this.menu == null){
40758 this.menu = new Roo.menu.DateMenu();
40762 Roo.apply(this.menu.picker, {
40764 showClear: this.allowBlank,
40765 minDate : this.minValue,
40766 maxDate : this.maxValue,
40767 disabledDatesRE : this.ddMatch,
40768 disabledDatesText : this.disabledDatesText,
40770 format : this.useIso ? 'Y-m-d' : this.format,
40771 minText : String.format(this.minText, this.formatDate(this.minValue)),
40772 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40775 this.menu.on(Roo.apply({}, this.menuListeners, {
40783 // hide month picker get's called when we called by 'before hide';
40785 var ignorehide = true;
40786 p.hideMonthPicker = function(disableAnim){
40790 if(this.monthPicker){
40791 Roo.log("hideMonthPicker called");
40792 if(disableAnim === true){
40793 this.monthPicker.hide();
40795 this.monthPicker.slideOut('t', {duration:.2});
40796 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40797 p.fireEvent("select", this, this.value);
40803 Roo.log('picker set value');
40804 Roo.log(this.getValue());
40805 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40806 m.show(this.el, 'tl-bl?');
40807 ignorehide = false;
40808 // this will trigger hideMonthPicker..
40811 // hidden the day picker
40812 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40818 p.showMonthPicker.defer(100, p);
40824 beforeBlur : function(){
40825 var v = this.parseDate(this.getRawValue());
40831 /** @cfg {Boolean} grow @hide */
40832 /** @cfg {Number} growMin @hide */
40833 /** @cfg {Number} growMax @hide */
40840 * Ext JS Library 1.1.1
40841 * Copyright(c) 2006-2007, Ext JS, LLC.
40843 * Originally Released Under LGPL - original licence link has changed is not relivant.
40846 * <script type="text/javascript">
40851 * @class Roo.form.ComboBox
40852 * @extends Roo.form.TriggerField
40853 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40855 * Create a new ComboBox.
40856 * @param {Object} config Configuration options
40858 Roo.form.ComboBox = function(config){
40859 Roo.form.ComboBox.superclass.constructor.call(this, config);
40863 * Fires when the dropdown list is expanded
40864 * @param {Roo.form.ComboBox} combo This combo box
40869 * Fires when the dropdown list is collapsed
40870 * @param {Roo.form.ComboBox} combo This combo box
40874 * @event beforeselect
40875 * Fires before a list item is selected. Return false to cancel the selection.
40876 * @param {Roo.form.ComboBox} combo This combo box
40877 * @param {Roo.data.Record} record The data record returned from the underlying store
40878 * @param {Number} index The index of the selected item in the dropdown list
40880 'beforeselect' : true,
40883 * Fires when a list item is selected
40884 * @param {Roo.form.ComboBox} combo This combo box
40885 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40886 * @param {Number} index The index of the selected item in the dropdown list
40890 * @event beforequery
40891 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40892 * The event object passed has these properties:
40893 * @param {Roo.form.ComboBox} combo This combo box
40894 * @param {String} query The query
40895 * @param {Boolean} forceAll true to force "all" query
40896 * @param {Boolean} cancel true to cancel the query
40897 * @param {Object} e The query event object
40899 'beforequery': true,
40902 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40903 * @param {Roo.form.ComboBox} combo This combo box
40908 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40909 * @param {Roo.form.ComboBox} combo This combo box
40910 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40916 if(this.transform){
40917 this.allowDomMove = false;
40918 var s = Roo.getDom(this.transform);
40919 if(!this.hiddenName){
40920 this.hiddenName = s.name;
40923 this.mode = 'local';
40924 var d = [], opts = s.options;
40925 for(var i = 0, len = opts.length;i < len; i++){
40927 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40929 this.value = value;
40931 d.push([value, o.text]);
40933 this.store = new Roo.data.SimpleStore({
40935 fields: ['value', 'text'],
40938 this.valueField = 'value';
40939 this.displayField = 'text';
40941 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40942 if(!this.lazyRender){
40943 this.target = true;
40944 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40945 s.parentNode.removeChild(s); // remove it
40946 this.render(this.el.parentNode);
40948 s.parentNode.removeChild(s); // remove it
40953 this.store = Roo.factory(this.store, Roo.data);
40956 this.selectedIndex = -1;
40957 if(this.mode == 'local'){
40958 if(config.queryDelay === undefined){
40959 this.queryDelay = 10;
40961 if(config.minChars === undefined){
40967 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40969 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40972 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40973 * rendering into an Roo.Editor, defaults to false)
40976 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40977 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40980 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40983 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40984 * the dropdown list (defaults to undefined, with no header element)
40988 * @cfg {String/Roo.Template} tpl The template to use to render the output
40992 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40994 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40996 listWidth: undefined,
40998 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40999 * mode = 'remote' or 'text' if mode = 'local')
41001 displayField: undefined,
41003 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41004 * mode = 'remote' or 'value' if mode = 'local').
41005 * Note: use of a valueField requires the user make a selection
41006 * in order for a value to be mapped.
41008 valueField: undefined,
41012 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41013 * field's data value (defaults to the underlying DOM element's name)
41015 hiddenName: undefined,
41017 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41021 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41023 selectedClass: 'x-combo-selected',
41025 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41026 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41027 * which displays a downward arrow icon).
41029 triggerClass : 'x-form-arrow-trigger',
41031 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41035 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41036 * anchor positions (defaults to 'tl-bl')
41038 listAlign: 'tl-bl?',
41040 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41044 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41045 * query specified by the allQuery config option (defaults to 'query')
41047 triggerAction: 'query',
41049 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41050 * (defaults to 4, does not apply if editable = false)
41054 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41055 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41059 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41060 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41064 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41065 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41069 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41070 * when editable = true (defaults to false)
41072 selectOnFocus:false,
41074 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41076 queryParam: 'query',
41078 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41079 * when mode = 'remote' (defaults to 'Loading...')
41081 loadingText: 'Loading...',
41083 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41087 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41091 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41092 * traditional select (defaults to true)
41096 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41100 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41104 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41105 * listWidth has a higher value)
41109 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41110 * allow the user to set arbitrary text into the field (defaults to false)
41112 forceSelection:false,
41114 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41115 * if typeAhead = true (defaults to 250)
41117 typeAheadDelay : 250,
41119 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41120 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41122 valueNotFoundText : undefined,
41124 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41126 blockFocus : false,
41129 * @cfg {Boolean} disableClear Disable showing of clear button.
41131 disableClear : false,
41133 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41135 alwaysQuery : false,
41141 // element that contains real text value.. (when hidden is used..)
41144 onRender : function(ct, position){
41145 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41146 if(this.hiddenName){
41147 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41149 this.hiddenField.value =
41150 this.hiddenValue !== undefined ? this.hiddenValue :
41151 this.value !== undefined ? this.value : '';
41153 // prevent input submission
41154 this.el.dom.removeAttribute('name');
41159 this.el.dom.setAttribute('autocomplete', 'off');
41162 var cls = 'x-combo-list';
41164 this.list = new Roo.Layer({
41165 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41168 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41169 this.list.setWidth(lw);
41170 this.list.swallowEvent('mousewheel');
41171 this.assetHeight = 0;
41174 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41175 this.assetHeight += this.header.getHeight();
41178 this.innerList = this.list.createChild({cls:cls+'-inner'});
41179 this.innerList.on('mouseover', this.onViewOver, this);
41180 this.innerList.on('mousemove', this.onViewMove, this);
41181 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41183 if(this.allowBlank && !this.pageSize && !this.disableClear){
41184 this.footer = this.list.createChild({cls:cls+'-ft'});
41185 this.pageTb = new Roo.Toolbar(this.footer);
41189 this.footer = this.list.createChild({cls:cls+'-ft'});
41190 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41191 {pageSize: this.pageSize});
41195 if (this.pageTb && this.allowBlank && !this.disableClear) {
41197 this.pageTb.add(new Roo.Toolbar.Fill(), {
41198 cls: 'x-btn-icon x-btn-clear',
41200 handler: function()
41203 _this.clearValue();
41204 _this.onSelect(false, -1);
41209 this.assetHeight += this.footer.getHeight();
41214 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41217 this.view = new Roo.View(this.innerList, this.tpl, {
41218 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41221 this.view.on('click', this.onViewClick, this);
41223 this.store.on('beforeload', this.onBeforeLoad, this);
41224 this.store.on('load', this.onLoad, this);
41225 this.store.on('loadexception', this.onLoadException, this);
41227 if(this.resizable){
41228 this.resizer = new Roo.Resizable(this.list, {
41229 pinned:true, handles:'se'
41231 this.resizer.on('resize', function(r, w, h){
41232 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41233 this.listWidth = w;
41234 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41235 this.restrictHeight();
41237 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41239 if(!this.editable){
41240 this.editable = true;
41241 this.setEditable(false);
41245 if (typeof(this.events.add.listeners) != 'undefined') {
41247 this.addicon = this.wrap.createChild(
41248 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41250 this.addicon.on('click', function(e) {
41251 this.fireEvent('add', this);
41254 if (typeof(this.events.edit.listeners) != 'undefined') {
41256 this.editicon = this.wrap.createChild(
41257 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41258 if (this.addicon) {
41259 this.editicon.setStyle('margin-left', '40px');
41261 this.editicon.on('click', function(e) {
41263 // we fire even if inothing is selected..
41264 this.fireEvent('edit', this, this.lastData );
41274 initEvents : function(){
41275 Roo.form.ComboBox.superclass.initEvents.call(this);
41277 this.keyNav = new Roo.KeyNav(this.el, {
41278 "up" : function(e){
41279 this.inKeyMode = true;
41283 "down" : function(e){
41284 if(!this.isExpanded()){
41285 this.onTriggerClick();
41287 this.inKeyMode = true;
41292 "enter" : function(e){
41293 this.onViewClick();
41297 "esc" : function(e){
41301 "tab" : function(e){
41302 this.onViewClick(false);
41303 this.fireEvent("specialkey", this, e);
41309 doRelay : function(foo, bar, hname){
41310 if(hname == 'down' || this.scope.isExpanded()){
41311 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41318 this.queryDelay = Math.max(this.queryDelay || 10,
41319 this.mode == 'local' ? 10 : 250);
41320 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41321 if(this.typeAhead){
41322 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41324 if(this.editable !== false){
41325 this.el.on("keyup", this.onKeyUp, this);
41327 if(this.forceSelection){
41328 this.on('blur', this.doForce, this);
41332 onDestroy : function(){
41334 this.view.setStore(null);
41335 this.view.el.removeAllListeners();
41336 this.view.el.remove();
41337 this.view.purgeListeners();
41340 this.list.destroy();
41343 this.store.un('beforeload', this.onBeforeLoad, this);
41344 this.store.un('load', this.onLoad, this);
41345 this.store.un('loadexception', this.onLoadException, this);
41347 Roo.form.ComboBox.superclass.onDestroy.call(this);
41351 fireKey : function(e){
41352 if(e.isNavKeyPress() && !this.list.isVisible()){
41353 this.fireEvent("specialkey", this, e);
41358 onResize: function(w, h){
41359 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41361 if(typeof w != 'number'){
41362 // we do not handle it!?!?
41365 var tw = this.trigger.getWidth();
41366 tw += this.addicon ? this.addicon.getWidth() : 0;
41367 tw += this.editicon ? this.editicon.getWidth() : 0;
41369 this.el.setWidth( this.adjustWidth('input', x));
41371 this.trigger.setStyle('left', x+'px');
41373 if(this.list && this.listWidth === undefined){
41374 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41375 this.list.setWidth(lw);
41376 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41384 * Allow or prevent the user from directly editing the field text. If false is passed,
41385 * the user will only be able to select from the items defined in the dropdown list. This method
41386 * is the runtime equivalent of setting the 'editable' config option at config time.
41387 * @param {Boolean} value True to allow the user to directly edit the field text
41389 setEditable : function(value){
41390 if(value == this.editable){
41393 this.editable = value;
41395 this.el.dom.setAttribute('readOnly', true);
41396 this.el.on('mousedown', this.onTriggerClick, this);
41397 this.el.addClass('x-combo-noedit');
41399 this.el.dom.setAttribute('readOnly', false);
41400 this.el.un('mousedown', this.onTriggerClick, this);
41401 this.el.removeClass('x-combo-noedit');
41406 onBeforeLoad : function(){
41407 if(!this.hasFocus){
41410 this.innerList.update(this.loadingText ?
41411 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41412 this.restrictHeight();
41413 this.selectedIndex = -1;
41417 onLoad : function(){
41418 if(!this.hasFocus){
41421 if(this.store.getCount() > 0){
41423 this.restrictHeight();
41424 if(this.lastQuery == this.allQuery){
41426 this.el.dom.select();
41428 if(!this.selectByValue(this.value, true)){
41429 this.select(0, true);
41433 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41434 this.taTask.delay(this.typeAheadDelay);
41438 this.onEmptyResults();
41443 onLoadException : function()
41446 Roo.log(this.store.reader.jsonData);
41447 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41448 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41454 onTypeAhead : function(){
41455 if(this.store.getCount() > 0){
41456 var r = this.store.getAt(0);
41457 var newValue = r.data[this.displayField];
41458 var len = newValue.length;
41459 var selStart = this.getRawValue().length;
41460 if(selStart != len){
41461 this.setRawValue(newValue);
41462 this.selectText(selStart, newValue.length);
41468 onSelect : function(record, index){
41469 if(this.fireEvent('beforeselect', this, record, index) !== false){
41470 this.setFromData(index > -1 ? record.data : false);
41472 this.fireEvent('select', this, record, index);
41477 * Returns the currently selected field value or empty string if no value is set.
41478 * @return {String} value The selected value
41480 getValue : function(){
41481 if(this.valueField){
41482 return typeof this.value != 'undefined' ? this.value : '';
41484 return Roo.form.ComboBox.superclass.getValue.call(this);
41488 * Clears any text/value currently set in the field
41490 clearValue : function(){
41491 if(this.hiddenField){
41492 this.hiddenField.value = '';
41495 this.setRawValue('');
41496 this.lastSelectionText = '';
41501 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41502 * will be displayed in the field. If the value does not match the data value of an existing item,
41503 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41504 * Otherwise the field will be blank (although the value will still be set).
41505 * @param {String} value The value to match
41507 setValue : function(v){
41509 if(this.valueField){
41510 var r = this.findRecord(this.valueField, v);
41512 text = r.data[this.displayField];
41513 }else if(this.valueNotFoundText !== undefined){
41514 text = this.valueNotFoundText;
41517 this.lastSelectionText = text;
41518 if(this.hiddenField){
41519 this.hiddenField.value = v;
41521 Roo.form.ComboBox.superclass.setValue.call(this, text);
41525 * @property {Object} the last set data for the element
41530 * Sets the value of the field based on a object which is related to the record format for the store.
41531 * @param {Object} value the value to set as. or false on reset?
41533 setFromData : function(o){
41534 var dv = ''; // display value
41535 var vv = ''; // value value..
41537 if (this.displayField) {
41538 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41540 // this is an error condition!!!
41541 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41544 if(this.valueField){
41545 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41547 if(this.hiddenField){
41548 this.hiddenField.value = vv;
41550 this.lastSelectionText = dv;
41551 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41555 // no hidden field.. - we store the value in 'value', but still display
41556 // display field!!!!
41557 this.lastSelectionText = dv;
41558 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41564 reset : function(){
41565 // overridden so that last data is reset..
41566 this.setValue(this.resetValue);
41567 this.clearInvalid();
41568 this.lastData = false;
41570 this.view.clearSelections();
41574 findRecord : function(prop, value){
41576 if(this.store.getCount() > 0){
41577 this.store.each(function(r){
41578 if(r.data[prop] == value){
41588 getName: function()
41590 // returns hidden if it's set..
41591 if (!this.rendered) {return ''};
41592 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41596 onViewMove : function(e, t){
41597 this.inKeyMode = false;
41601 onViewOver : function(e, t){
41602 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41605 var item = this.view.findItemFromChild(t);
41607 var index = this.view.indexOf(item);
41608 this.select(index, false);
41613 onViewClick : function(doFocus)
41615 var index = this.view.getSelectedIndexes()[0];
41616 var r = this.store.getAt(index);
41618 this.onSelect(r, index);
41620 if(doFocus !== false && !this.blockFocus){
41626 restrictHeight : function(){
41627 this.innerList.dom.style.height = '';
41628 var inner = this.innerList.dom;
41629 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41630 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41631 this.list.beginUpdate();
41632 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41633 this.list.alignTo(this.el, this.listAlign);
41634 this.list.endUpdate();
41638 onEmptyResults : function(){
41643 * Returns true if the dropdown list is expanded, else false.
41645 isExpanded : function(){
41646 return this.list.isVisible();
41650 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41651 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41652 * @param {String} value The data value of the item to select
41653 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41654 * selected item if it is not currently in view (defaults to true)
41655 * @return {Boolean} True if the value matched an item in the list, else false
41657 selectByValue : function(v, scrollIntoView){
41658 if(v !== undefined && v !== null){
41659 var r = this.findRecord(this.valueField || this.displayField, v);
41661 this.select(this.store.indexOf(r), scrollIntoView);
41669 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41670 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41671 * @param {Number} index The zero-based index of the list item to select
41672 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41673 * selected item if it is not currently in view (defaults to true)
41675 select : function(index, scrollIntoView){
41676 this.selectedIndex = index;
41677 this.view.select(index);
41678 if(scrollIntoView !== false){
41679 var el = this.view.getNode(index);
41681 this.innerList.scrollChildIntoView(el, false);
41687 selectNext : function(){
41688 var ct = this.store.getCount();
41690 if(this.selectedIndex == -1){
41692 }else if(this.selectedIndex < ct-1){
41693 this.select(this.selectedIndex+1);
41699 selectPrev : function(){
41700 var ct = this.store.getCount();
41702 if(this.selectedIndex == -1){
41704 }else if(this.selectedIndex != 0){
41705 this.select(this.selectedIndex-1);
41711 onKeyUp : function(e){
41712 if(this.editable !== false && !e.isSpecialKey()){
41713 this.lastKey = e.getKey();
41714 this.dqTask.delay(this.queryDelay);
41719 validateBlur : function(){
41720 return !this.list || !this.list.isVisible();
41724 initQuery : function(){
41725 this.doQuery(this.getRawValue());
41729 doForce : function(){
41730 if(this.el.dom.value.length > 0){
41731 this.el.dom.value =
41732 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41738 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41739 * query allowing the query action to be canceled if needed.
41740 * @param {String} query The SQL query to execute
41741 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41742 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41743 * saved in the current store (defaults to false)
41745 doQuery : function(q, forceAll){
41746 if(q === undefined || q === null){
41751 forceAll: forceAll,
41755 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41759 forceAll = qe.forceAll;
41760 if(forceAll === true || (q.length >= this.minChars)){
41761 if(this.lastQuery != q || this.alwaysQuery){
41762 this.lastQuery = q;
41763 if(this.mode == 'local'){
41764 this.selectedIndex = -1;
41766 this.store.clearFilter();
41768 this.store.filter(this.displayField, q);
41772 this.store.baseParams[this.queryParam] = q;
41774 params: this.getParams(q)
41779 this.selectedIndex = -1;
41786 getParams : function(q){
41788 //p[this.queryParam] = q;
41791 p.limit = this.pageSize;
41797 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41799 collapse : function(){
41800 if(!this.isExpanded()){
41804 Roo.get(document).un('mousedown', this.collapseIf, this);
41805 Roo.get(document).un('mousewheel', this.collapseIf, this);
41806 if (!this.editable) {
41807 Roo.get(document).un('keydown', this.listKeyPress, this);
41809 this.fireEvent('collapse', this);
41813 collapseIf : function(e){
41814 if(!e.within(this.wrap) && !e.within(this.list)){
41820 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41822 expand : function(){
41823 if(this.isExpanded() || !this.hasFocus){
41826 this.list.alignTo(this.el, this.listAlign);
41828 Roo.get(document).on('mousedown', this.collapseIf, this);
41829 Roo.get(document).on('mousewheel', this.collapseIf, this);
41830 if (!this.editable) {
41831 Roo.get(document).on('keydown', this.listKeyPress, this);
41834 this.fireEvent('expand', this);
41838 // Implements the default empty TriggerField.onTriggerClick function
41839 onTriggerClick : function(){
41843 if(this.isExpanded()){
41845 if (!this.blockFocus) {
41850 this.hasFocus = true;
41851 if(this.triggerAction == 'all') {
41852 this.doQuery(this.allQuery, true);
41854 this.doQuery(this.getRawValue());
41856 if (!this.blockFocus) {
41861 listKeyPress : function(e)
41863 //Roo.log('listkeypress');
41864 // scroll to first matching element based on key pres..
41865 if (e.isSpecialKey()) {
41868 var k = String.fromCharCode(e.getKey()).toUpperCase();
41871 var csel = this.view.getSelectedNodes();
41872 var cselitem = false;
41874 var ix = this.view.indexOf(csel[0]);
41875 cselitem = this.store.getAt(ix);
41876 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41882 this.store.each(function(v) {
41884 // start at existing selection.
41885 if (cselitem.id == v.id) {
41891 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41892 match = this.store.indexOf(v);
41897 if (match === false) {
41898 return true; // no more action?
41901 this.view.select(match);
41902 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41903 sn.scrollIntoView(sn.dom.parentNode, false);
41907 * @cfg {Boolean} grow
41911 * @cfg {Number} growMin
41915 * @cfg {Number} growMax
41923 * Copyright(c) 2010-2012, Roo J Solutions Limited
41930 * @class Roo.form.ComboBoxArray
41931 * @extends Roo.form.TextField
41932 * A facebook style adder... for lists of email / people / countries etc...
41933 * pick multiple items from a combo box, and shows each one.
41935 * Fred [x] Brian [x] [Pick another |v]
41938 * For this to work: it needs various extra information
41939 * - normal combo problay has
41941 * + displayField, valueField
41943 * For our purpose...
41946 * If we change from 'extends' to wrapping...
41953 * Create a new ComboBoxArray.
41954 * @param {Object} config Configuration options
41958 Roo.form.ComboBoxArray = function(config)
41962 * @event beforeremove
41963 * Fires before remove the value from the list
41964 * @param {Roo.form.ComboBoxArray} _self This combo box array
41965 * @param {Roo.form.ComboBoxArray.Item} item removed item
41967 'beforeremove' : true,
41970 * Fires when remove the value from the list
41971 * @param {Roo.form.ComboBoxArray} _self This combo box array
41972 * @param {Roo.form.ComboBoxArray.Item} item removed item
41979 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41981 this.items = new Roo.util.MixedCollection(false);
41983 // construct the child combo...
41993 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41996 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42001 // behavies liek a hiddne field
42002 inputType: 'hidden',
42004 * @cfg {Number} width The width of the box that displays the selected element
42011 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42015 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42017 hiddenName : false,
42020 // private the array of items that are displayed..
42022 // private - the hidden field el.
42024 // private - the filed el..
42027 //validateValue : function() { return true; }, // all values are ok!
42028 //onAddClick: function() { },
42030 onRender : function(ct, position)
42033 // create the standard hidden element
42034 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42037 // give fake names to child combo;
42038 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42039 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42041 this.combo = Roo.factory(this.combo, Roo.form);
42042 this.combo.onRender(ct, position);
42043 if (typeof(this.combo.width) != 'undefined') {
42044 this.combo.onResize(this.combo.width,0);
42047 this.combo.initEvents();
42049 // assigned so form know we need to do this..
42050 this.store = this.combo.store;
42051 this.valueField = this.combo.valueField;
42052 this.displayField = this.combo.displayField ;
42055 this.combo.wrap.addClass('x-cbarray-grp');
42057 var cbwrap = this.combo.wrap.createChild(
42058 {tag: 'div', cls: 'x-cbarray-cb'},
42063 this.hiddenEl = this.combo.wrap.createChild({
42064 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42066 this.el = this.combo.wrap.createChild({
42067 tag: 'input', type:'hidden' , name: this.name, value : ''
42069 // this.el.dom.removeAttribute("name");
42072 this.outerWrap = this.combo.wrap;
42073 this.wrap = cbwrap;
42075 this.outerWrap.setWidth(this.width);
42076 this.outerWrap.dom.removeChild(this.el.dom);
42078 this.wrap.dom.appendChild(this.el.dom);
42079 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42080 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42082 this.combo.trigger.setStyle('position','relative');
42083 this.combo.trigger.setStyle('left', '0px');
42084 this.combo.trigger.setStyle('top', '2px');
42086 this.combo.el.setStyle('vertical-align', 'text-bottom');
42088 //this.trigger.setStyle('vertical-align', 'top');
42090 // this should use the code from combo really... on('add' ....)
42094 this.adder = this.outerWrap.createChild(
42095 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42097 this.adder.on('click', function(e) {
42098 _t.fireEvent('adderclick', this, e);
42102 //this.adder.on('click', this.onAddClick, _t);
42105 this.combo.on('select', function(cb, rec, ix) {
42106 this.addItem(rec.data);
42109 cb.el.dom.value = '';
42110 //cb.lastData = rec.data;
42119 getName: function()
42121 // returns hidden if it's set..
42122 if (!this.rendered) {return ''};
42123 return this.hiddenName ? this.hiddenName : this.name;
42128 onResize: function(w, h){
42131 // not sure if this is needed..
42132 //this.combo.onResize(w,h);
42134 if(typeof w != 'number'){
42135 // we do not handle it!?!?
42138 var tw = this.combo.trigger.getWidth();
42139 tw += this.addicon ? this.addicon.getWidth() : 0;
42140 tw += this.editicon ? this.editicon.getWidth() : 0;
42142 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42144 this.combo.trigger.setStyle('left', '0px');
42146 if(this.list && this.listWidth === undefined){
42147 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42148 this.list.setWidth(lw);
42149 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42156 addItem: function(rec)
42158 var valueField = this.combo.valueField;
42159 var displayField = this.combo.displayField;
42160 if (this.items.indexOfKey(rec[valueField]) > -1) {
42161 //console.log("GOT " + rec.data.id);
42165 var x = new Roo.form.ComboBoxArray.Item({
42166 //id : rec[this.idField],
42168 displayField : displayField ,
42169 tipField : displayField ,
42173 this.items.add(rec[valueField],x);
42174 // add it before the element..
42175 this.updateHiddenEl();
42176 x.render(this.outerWrap, this.wrap.dom);
42177 // add the image handler..
42180 updateHiddenEl : function()
42183 if (!this.hiddenEl) {
42187 var idField = this.combo.valueField;
42189 this.items.each(function(f) {
42190 ar.push(f.data[idField]);
42193 this.hiddenEl.dom.value = ar.join(',');
42199 this.items.clear();
42201 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42205 this.el.dom.value = '';
42206 if (this.hiddenEl) {
42207 this.hiddenEl.dom.value = '';
42211 getValue: function()
42213 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42215 setValue: function(v) // not a valid action - must use addItems..
42222 if (this.store.isLocal && (typeof(v) == 'string')) {
42223 // then we can use the store to find the values..
42224 // comma seperated at present.. this needs to allow JSON based encoding..
42225 this.hiddenEl.value = v;
42227 Roo.each(v.split(','), function(k) {
42228 Roo.log("CHECK " + this.valueField + ',' + k);
42229 var li = this.store.query(this.valueField, k);
42234 add[this.valueField] = k;
42235 add[this.displayField] = li.item(0).data[this.displayField];
42241 if (typeof(v) == 'object' ) {
42242 // then let's assume it's an array of objects..
42243 Roo.each(v, function(l) {
42251 setFromData: function(v)
42253 // this recieves an object, if setValues is called.
42255 this.el.dom.value = v[this.displayField];
42256 this.hiddenEl.dom.value = v[this.valueField];
42257 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42260 var kv = v[this.valueField];
42261 var dv = v[this.displayField];
42262 kv = typeof(kv) != 'string' ? '' : kv;
42263 dv = typeof(dv) != 'string' ? '' : dv;
42266 var keys = kv.split(',');
42267 var display = dv.split(',');
42268 for (var i = 0 ; i < keys.length; i++) {
42271 add[this.valueField] = keys[i];
42272 add[this.displayField] = display[i];
42280 * Validates the combox array value
42281 * @return {Boolean} True if the value is valid, else false
42283 validate : function(){
42284 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42285 this.clearInvalid();
42291 validateValue : function(value){
42292 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42300 isDirty : function() {
42301 if(this.disabled) {
42306 var d = Roo.decode(String(this.originalValue));
42308 return String(this.getValue()) !== String(this.originalValue);
42311 var originalValue = [];
42313 for (var i = 0; i < d.length; i++){
42314 originalValue.push(d[i][this.valueField]);
42317 return String(this.getValue()) !== String(originalValue.join(','));
42326 * @class Roo.form.ComboBoxArray.Item
42327 * @extends Roo.BoxComponent
42328 * A selected item in the list
42329 * Fred [x] Brian [x] [Pick another |v]
42332 * Create a new item.
42333 * @param {Object} config Configuration options
42336 Roo.form.ComboBoxArray.Item = function(config) {
42337 config.id = Roo.id();
42338 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42341 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42344 displayField : false,
42348 defaultAutoCreate : {
42350 cls: 'x-cbarray-item',
42357 src : Roo.BLANK_IMAGE_URL ,
42365 onRender : function(ct, position)
42367 Roo.form.Field.superclass.onRender.call(this, ct, position);
42370 var cfg = this.getAutoCreate();
42371 this.el = ct.createChild(cfg, position);
42374 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42376 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42377 this.cb.renderer(this.data) :
42378 String.format('{0}',this.data[this.displayField]);
42381 this.el.child('div').dom.setAttribute('qtip',
42382 String.format('{0}',this.data[this.tipField])
42385 this.el.child('img').on('click', this.remove, this);
42389 remove : function()
42391 if(this.cb.disabled){
42395 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42396 this.cb.items.remove(this);
42397 this.el.child('img').un('click', this.remove, this);
42399 this.cb.updateHiddenEl();
42401 this.cb.fireEvent('remove', this.cb, this);
42407 * Ext JS Library 1.1.1
42408 * Copyright(c) 2006-2007, Ext JS, LLC.
42410 * Originally Released Under LGPL - original licence link has changed is not relivant.
42413 * <script type="text/javascript">
42416 * @class Roo.form.Checkbox
42417 * @extends Roo.form.Field
42418 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42420 * Creates a new Checkbox
42421 * @param {Object} config Configuration options
42423 Roo.form.Checkbox = function(config){
42424 Roo.form.Checkbox.superclass.constructor.call(this, config);
42428 * Fires when the checkbox is checked or unchecked.
42429 * @param {Roo.form.Checkbox} this This checkbox
42430 * @param {Boolean} checked The new checked value
42436 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42438 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42440 focusClass : undefined,
42442 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42444 fieldClass: "x-form-field",
42446 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42450 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42451 * {tag: "input", type: "checkbox", autocomplete: "off"})
42453 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42455 * @cfg {String} boxLabel The text that appears beside the checkbox
42459 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42463 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42465 valueOff: '0', // value when not checked..
42467 actionMode : 'viewEl',
42470 itemCls : 'x-menu-check-item x-form-item',
42471 groupClass : 'x-menu-group-item',
42472 inputType : 'hidden',
42475 inSetChecked: false, // check that we are not calling self...
42477 inputElement: false, // real input element?
42478 basedOn: false, // ????
42480 isFormField: true, // not sure where this is needed!!!!
42482 onResize : function(){
42483 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42484 if(!this.boxLabel){
42485 this.el.alignTo(this.wrap, 'c-c');
42489 initEvents : function(){
42490 Roo.form.Checkbox.superclass.initEvents.call(this);
42491 this.el.on("click", this.onClick, this);
42492 this.el.on("change", this.onClick, this);
42496 getResizeEl : function(){
42500 getPositionEl : function(){
42505 onRender : function(ct, position){
42506 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42508 if(this.inputValue !== undefined){
42509 this.el.dom.value = this.inputValue;
42512 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42513 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42514 var viewEl = this.wrap.createChild({
42515 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42516 this.viewEl = viewEl;
42517 this.wrap.on('click', this.onClick, this);
42519 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42520 this.el.on('propertychange', this.setFromHidden, this); //ie
42525 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42526 // viewEl.on('click', this.onClick, this);
42528 //if(this.checked){
42529 this.setChecked(this.checked);
42531 //this.checked = this.el.dom;
42537 initValue : Roo.emptyFn,
42540 * Returns the checked state of the checkbox.
42541 * @return {Boolean} True if checked, else false
42543 getValue : function(){
42545 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42547 return this.valueOff;
42552 onClick : function(){
42553 if (this.disabled) {
42556 this.setChecked(!this.checked);
42558 //if(this.el.dom.checked != this.checked){
42559 // this.setValue(this.el.dom.checked);
42564 * Sets the checked state of the checkbox.
42565 * On is always based on a string comparison between inputValue and the param.
42566 * @param {Boolean/String} value - the value to set
42567 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42569 setValue : function(v,suppressEvent){
42572 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42573 //if(this.el && this.el.dom){
42574 // this.el.dom.checked = this.checked;
42575 // this.el.dom.defaultChecked = this.checked;
42577 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42578 //this.fireEvent("check", this, this.checked);
42581 setChecked : function(state,suppressEvent)
42583 if (this.inSetChecked) {
42584 this.checked = state;
42590 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42592 this.checked = state;
42593 if(suppressEvent !== true){
42594 this.fireEvent('check', this, state);
42596 this.inSetChecked = true;
42597 this.el.dom.value = state ? this.inputValue : this.valueOff;
42598 this.inSetChecked = false;
42601 // handle setting of hidden value by some other method!!?!?
42602 setFromHidden: function()
42607 //console.log("SET FROM HIDDEN");
42608 //alert('setFrom hidden');
42609 this.setValue(this.el.dom.value);
42612 onDestroy : function()
42615 Roo.get(this.viewEl).remove();
42618 Roo.form.Checkbox.superclass.onDestroy.call(this);
42621 setBoxLabel : function(str)
42623 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42628 * Ext JS Library 1.1.1
42629 * Copyright(c) 2006-2007, Ext JS, LLC.
42631 * Originally Released Under LGPL - original licence link has changed is not relivant.
42634 * <script type="text/javascript">
42638 * @class Roo.form.Radio
42639 * @extends Roo.form.Checkbox
42640 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42641 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42643 * Creates a new Radio
42644 * @param {Object} config Configuration options
42646 Roo.form.Radio = function(){
42647 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42649 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42650 inputType: 'radio',
42653 * If this radio is part of a group, it will return the selected value
42656 getGroupValue : function(){
42657 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42661 onRender : function(ct, position){
42662 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42664 if(this.inputValue !== undefined){
42665 this.el.dom.value = this.inputValue;
42668 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42669 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42670 //var viewEl = this.wrap.createChild({
42671 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42672 //this.viewEl = viewEl;
42673 //this.wrap.on('click', this.onClick, this);
42675 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42676 //this.el.on('propertychange', this.setFromHidden, this); //ie
42681 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42682 // viewEl.on('click', this.onClick, this);
42685 this.el.dom.checked = 'checked' ;
42691 });//<script type="text/javascript">
42694 * Based Ext JS Library 1.1.1
42695 * Copyright(c) 2006-2007, Ext JS, LLC.
42701 * @class Roo.HtmlEditorCore
42702 * @extends Roo.Component
42703 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42705 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42708 Roo.HtmlEditorCore = function(config){
42711 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42716 * @event initialize
42717 * Fires when the editor is fully initialized (including the iframe)
42718 * @param {Roo.HtmlEditorCore} this
42723 * Fires when the editor is first receives the focus. Any insertion must wait
42724 * until after this event.
42725 * @param {Roo.HtmlEditorCore} this
42729 * @event beforesync
42730 * Fires before the textarea is updated with content from the editor iframe. Return false
42731 * to cancel the sync.
42732 * @param {Roo.HtmlEditorCore} this
42733 * @param {String} html
42737 * @event beforepush
42738 * Fires before the iframe editor is updated with content from the textarea. Return false
42739 * to cancel the push.
42740 * @param {Roo.HtmlEditorCore} this
42741 * @param {String} html
42746 * Fires when the textarea is updated with content from the editor iframe.
42747 * @param {Roo.HtmlEditorCore} this
42748 * @param {String} html
42753 * Fires when the iframe editor is updated with content from the textarea.
42754 * @param {Roo.HtmlEditorCore} this
42755 * @param {String} html
42760 * @event editorevent
42761 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42762 * @param {Roo.HtmlEditorCore} this
42768 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42770 // defaults : white / black...
42771 this.applyBlacklists();
42778 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42782 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42788 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42793 * @cfg {Number} height (in pixels)
42797 * @cfg {Number} width (in pixels)
42802 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42805 stylesheets: false,
42810 // private properties
42811 validationEvent : false,
42813 initialized : false,
42815 sourceEditMode : false,
42816 onFocus : Roo.emptyFn,
42818 hideMode:'offsets',
42822 // blacklist + whitelisted elements..
42829 * Protected method that will not generally be called directly. It
42830 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42831 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42833 getDocMarkup : function(){
42837 // inherit styels from page...??
42838 if (this.stylesheets === false) {
42840 Roo.get(document.head).select('style').each(function(node) {
42841 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42844 Roo.get(document.head).select('link').each(function(node) {
42845 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42848 } else if (!this.stylesheets.length) {
42850 st = '<style type="text/css">' +
42851 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42857 st += '<style type="text/css">' +
42858 'IMG { cursor: pointer } ' +
42862 return '<html><head>' + st +
42863 //<style type="text/css">' +
42864 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42866 ' </head><body class="roo-htmleditor-body"></body></html>';
42870 onRender : function(ct, position)
42873 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42874 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42877 this.el.dom.style.border = '0 none';
42878 this.el.dom.setAttribute('tabIndex', -1);
42879 this.el.addClass('x-hidden hide');
42883 if(Roo.isIE){ // fix IE 1px bogus margin
42884 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42888 this.frameId = Roo.id();
42892 var iframe = this.owner.wrap.createChild({
42894 cls: 'form-control', // bootstrap..
42896 name: this.frameId,
42897 frameBorder : 'no',
42898 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42903 this.iframe = iframe.dom;
42905 this.assignDocWin();
42907 this.doc.designMode = 'on';
42910 this.doc.write(this.getDocMarkup());
42914 var task = { // must defer to wait for browser to be ready
42916 //console.log("run task?" + this.doc.readyState);
42917 this.assignDocWin();
42918 if(this.doc.body || this.doc.readyState == 'complete'){
42920 this.doc.designMode="on";
42924 Roo.TaskMgr.stop(task);
42925 this.initEditor.defer(10, this);
42932 Roo.TaskMgr.start(task);
42937 onResize : function(w, h)
42939 Roo.log('resize: ' +w + ',' + h );
42940 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42944 if(typeof w == 'number'){
42946 this.iframe.style.width = w + 'px';
42948 if(typeof h == 'number'){
42950 this.iframe.style.height = h + 'px';
42952 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42959 * Toggles the editor between standard and source edit mode.
42960 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42962 toggleSourceEdit : function(sourceEditMode){
42964 this.sourceEditMode = sourceEditMode === true;
42966 if(this.sourceEditMode){
42968 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42971 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42972 //this.iframe.className = '';
42975 //this.setSize(this.owner.wrap.getSize());
42976 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42983 * Protected method that will not generally be called directly. If you need/want
42984 * custom HTML cleanup, this is the method you should override.
42985 * @param {String} html The HTML to be cleaned
42986 * return {String} The cleaned HTML
42988 cleanHtml : function(html){
42989 html = String(html);
42990 if(html.length > 5){
42991 if(Roo.isSafari){ // strip safari nonsense
42992 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42995 if(html == ' '){
43002 * HTML Editor -> Textarea
43003 * Protected method that will not generally be called directly. Syncs the contents
43004 * of the editor iframe with the textarea.
43006 syncValue : function(){
43007 if(this.initialized){
43008 var bd = (this.doc.body || this.doc.documentElement);
43009 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43010 var html = bd.innerHTML;
43012 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43013 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43015 html = '<div style="'+m[0]+'">' + html + '</div>';
43018 html = this.cleanHtml(html);
43019 // fix up the special chars.. normaly like back quotes in word...
43020 // however we do not want to do this with chinese..
43021 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43022 var cc = b.charCodeAt();
43024 (cc >= 0x4E00 && cc < 0xA000 ) ||
43025 (cc >= 0x3400 && cc < 0x4E00 ) ||
43026 (cc >= 0xf900 && cc < 0xfb00 )
43032 if(this.owner.fireEvent('beforesync', this, html) !== false){
43033 this.el.dom.value = html;
43034 this.owner.fireEvent('sync', this, html);
43040 * Protected method that will not generally be called directly. Pushes the value of the textarea
43041 * into the iframe editor.
43043 pushValue : function(){
43044 if(this.initialized){
43045 var v = this.el.dom.value.trim();
43047 // if(v.length < 1){
43051 if(this.owner.fireEvent('beforepush', this, v) !== false){
43052 var d = (this.doc.body || this.doc.documentElement);
43054 this.cleanUpPaste();
43055 this.el.dom.value = d.innerHTML;
43056 this.owner.fireEvent('push', this, v);
43062 deferFocus : function(){
43063 this.focus.defer(10, this);
43067 focus : function(){
43068 if(this.win && !this.sourceEditMode){
43075 assignDocWin: function()
43077 var iframe = this.iframe;
43080 this.doc = iframe.contentWindow.document;
43081 this.win = iframe.contentWindow;
43083 // if (!Roo.get(this.frameId)) {
43086 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43087 // this.win = Roo.get(this.frameId).dom.contentWindow;
43089 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43093 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43094 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43099 initEditor : function(){
43100 //console.log("INIT EDITOR");
43101 this.assignDocWin();
43105 this.doc.designMode="on";
43107 this.doc.write(this.getDocMarkup());
43110 var dbody = (this.doc.body || this.doc.documentElement);
43111 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43112 // this copies styles from the containing element into thsi one..
43113 // not sure why we need all of this..
43114 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43116 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43117 //ss['background-attachment'] = 'fixed'; // w3c
43118 dbody.bgProperties = 'fixed'; // ie
43119 //Roo.DomHelper.applyStyles(dbody, ss);
43120 Roo.EventManager.on(this.doc, {
43121 //'mousedown': this.onEditorEvent,
43122 'mouseup': this.onEditorEvent,
43123 'dblclick': this.onEditorEvent,
43124 'click': this.onEditorEvent,
43125 'keyup': this.onEditorEvent,
43130 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43132 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43133 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43135 this.initialized = true;
43137 this.owner.fireEvent('initialize', this);
43142 onDestroy : function(){
43148 //for (var i =0; i < this.toolbars.length;i++) {
43149 // // fixme - ask toolbars for heights?
43150 // this.toolbars[i].onDestroy();
43153 //this.wrap.dom.innerHTML = '';
43154 //this.wrap.remove();
43159 onFirstFocus : function(){
43161 this.assignDocWin();
43164 this.activated = true;
43167 if(Roo.isGecko){ // prevent silly gecko errors
43169 var s = this.win.getSelection();
43170 if(!s.focusNode || s.focusNode.nodeType != 3){
43171 var r = s.getRangeAt(0);
43172 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43177 this.execCmd('useCSS', true);
43178 this.execCmd('styleWithCSS', false);
43181 this.owner.fireEvent('activate', this);
43185 adjustFont: function(btn){
43186 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43187 //if(Roo.isSafari){ // safari
43190 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43191 if(Roo.isSafari){ // safari
43192 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43193 v = (v < 10) ? 10 : v;
43194 v = (v > 48) ? 48 : v;
43195 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43200 v = Math.max(1, v+adjust);
43202 this.execCmd('FontSize', v );
43205 onEditorEvent : function(e)
43207 this.owner.fireEvent('editorevent', this, e);
43208 // this.updateToolbar();
43209 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43212 insertTag : function(tg)
43214 // could be a bit smarter... -> wrap the current selected tRoo..
43215 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43217 range = this.createRange(this.getSelection());
43218 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43219 wrappingNode.appendChild(range.extractContents());
43220 range.insertNode(wrappingNode);
43227 this.execCmd("formatblock", tg);
43231 insertText : function(txt)
43235 var range = this.createRange();
43236 range.deleteContents();
43237 //alert(Sender.getAttribute('label'));
43239 range.insertNode(this.doc.createTextNode(txt));
43245 * Executes a Midas editor command on the editor document and performs necessary focus and
43246 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43247 * @param {String} cmd The Midas command
43248 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43250 relayCmd : function(cmd, value){
43252 this.execCmd(cmd, value);
43253 this.owner.fireEvent('editorevent', this);
43254 //this.updateToolbar();
43255 this.owner.deferFocus();
43259 * Executes a Midas editor command directly on the editor document.
43260 * For visual commands, you should use {@link #relayCmd} instead.
43261 * <b>This should only be called after the editor is initialized.</b>
43262 * @param {String} cmd The Midas command
43263 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43265 execCmd : function(cmd, value){
43266 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43273 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43275 * @param {String} text | dom node..
43277 insertAtCursor : function(text)
43280 if(!this.activated){
43286 var r = this.doc.selection.createRange();
43297 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43301 // from jquery ui (MIT licenced)
43303 var win = this.win;
43305 if (win.getSelection && win.getSelection().getRangeAt) {
43306 range = win.getSelection().getRangeAt(0);
43307 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43308 range.insertNode(node);
43309 } else if (win.document.selection && win.document.selection.createRange) {
43310 // no firefox support
43311 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43312 win.document.selection.createRange().pasteHTML(txt);
43314 // no firefox support
43315 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43316 this.execCmd('InsertHTML', txt);
43325 mozKeyPress : function(e){
43327 var c = e.getCharCode(), cmd;
43330 c = String.fromCharCode(c).toLowerCase();
43344 this.cleanUpPaste.defer(100, this);
43352 e.preventDefault();
43360 fixKeys : function(){ // load time branching for fastest keydown performance
43362 return function(e){
43363 var k = e.getKey(), r;
43366 r = this.doc.selection.createRange();
43369 r.pasteHTML('    ');
43376 r = this.doc.selection.createRange();
43378 var target = r.parentElement();
43379 if(!target || target.tagName.toLowerCase() != 'li'){
43381 r.pasteHTML('<br />');
43387 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43388 this.cleanUpPaste.defer(100, this);
43394 }else if(Roo.isOpera){
43395 return function(e){
43396 var k = e.getKey();
43400 this.execCmd('InsertHTML','    ');
43403 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43404 this.cleanUpPaste.defer(100, this);
43409 }else if(Roo.isSafari){
43410 return function(e){
43411 var k = e.getKey();
43415 this.execCmd('InsertText','\t');
43419 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43420 this.cleanUpPaste.defer(100, this);
43428 getAllAncestors: function()
43430 var p = this.getSelectedNode();
43433 a.push(p); // push blank onto stack..
43434 p = this.getParentElement();
43438 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43442 a.push(this.doc.body);
43446 lastSelNode : false,
43449 getSelection : function()
43451 this.assignDocWin();
43452 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43455 getSelectedNode: function()
43457 // this may only work on Gecko!!!
43459 // should we cache this!!!!
43464 var range = this.createRange(this.getSelection()).cloneRange();
43467 var parent = range.parentElement();
43469 var testRange = range.duplicate();
43470 testRange.moveToElementText(parent);
43471 if (testRange.inRange(range)) {
43474 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43477 parent = parent.parentElement;
43482 // is ancestor a text element.
43483 var ac = range.commonAncestorContainer;
43484 if (ac.nodeType == 3) {
43485 ac = ac.parentNode;
43488 var ar = ac.childNodes;
43491 var other_nodes = [];
43492 var has_other_nodes = false;
43493 for (var i=0;i<ar.length;i++) {
43494 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43497 // fullly contained node.
43499 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43504 // probably selected..
43505 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43506 other_nodes.push(ar[i]);
43510 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43515 has_other_nodes = true;
43517 if (!nodes.length && other_nodes.length) {
43518 nodes= other_nodes;
43520 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43526 createRange: function(sel)
43528 // this has strange effects when using with
43529 // top toolbar - not sure if it's a great idea.
43530 //this.editor.contentWindow.focus();
43531 if (typeof sel != "undefined") {
43533 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43535 return this.doc.createRange();
43538 return this.doc.createRange();
43541 getParentElement: function()
43544 this.assignDocWin();
43545 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43547 var range = this.createRange(sel);
43550 var p = range.commonAncestorContainer;
43551 while (p.nodeType == 3) { // text node
43562 * Range intersection.. the hard stuff...
43566 * [ -- selected range --- ]
43570 * if end is before start or hits it. fail.
43571 * if start is after end or hits it fail.
43573 * if either hits (but other is outside. - then it's not
43579 // @see http://www.thismuchiknow.co.uk/?p=64.
43580 rangeIntersectsNode : function(range, node)
43582 var nodeRange = node.ownerDocument.createRange();
43584 nodeRange.selectNode(node);
43586 nodeRange.selectNodeContents(node);
43589 var rangeStartRange = range.cloneRange();
43590 rangeStartRange.collapse(true);
43592 var rangeEndRange = range.cloneRange();
43593 rangeEndRange.collapse(false);
43595 var nodeStartRange = nodeRange.cloneRange();
43596 nodeStartRange.collapse(true);
43598 var nodeEndRange = nodeRange.cloneRange();
43599 nodeEndRange.collapse(false);
43601 return rangeStartRange.compareBoundaryPoints(
43602 Range.START_TO_START, nodeEndRange) == -1 &&
43603 rangeEndRange.compareBoundaryPoints(
43604 Range.START_TO_START, nodeStartRange) == 1;
43608 rangeCompareNode : function(range, node)
43610 var nodeRange = node.ownerDocument.createRange();
43612 nodeRange.selectNode(node);
43614 nodeRange.selectNodeContents(node);
43618 range.collapse(true);
43620 nodeRange.collapse(true);
43622 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43623 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43625 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43627 var nodeIsBefore = ss == 1;
43628 var nodeIsAfter = ee == -1;
43630 if (nodeIsBefore && nodeIsAfter) {
43633 if (!nodeIsBefore && nodeIsAfter) {
43634 return 1; //right trailed.
43637 if (nodeIsBefore && !nodeIsAfter) {
43638 return 2; // left trailed.
43644 // private? - in a new class?
43645 cleanUpPaste : function()
43647 // cleans up the whole document..
43648 Roo.log('cleanuppaste');
43650 this.cleanUpChildren(this.doc.body);
43651 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43652 if (clean != this.doc.body.innerHTML) {
43653 this.doc.body.innerHTML = clean;
43658 cleanWordChars : function(input) {// change the chars to hex code
43659 var he = Roo.HtmlEditorCore;
43661 var output = input;
43662 Roo.each(he.swapCodes, function(sw) {
43663 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43665 output = output.replace(swapper, sw[1]);
43672 cleanUpChildren : function (n)
43674 if (!n.childNodes.length) {
43677 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43678 this.cleanUpChild(n.childNodes[i]);
43685 cleanUpChild : function (node)
43688 //console.log(node);
43689 if (node.nodeName == "#text") {
43690 // clean up silly Windows -- stuff?
43693 if (node.nodeName == "#comment") {
43694 node.parentNode.removeChild(node);
43695 // clean up silly Windows -- stuff?
43698 var lcname = node.tagName.toLowerCase();
43699 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43700 // whitelist of tags..
43702 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43704 node.parentNode.removeChild(node);
43709 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43711 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43712 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43714 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43715 // remove_keep_children = true;
43718 if (remove_keep_children) {
43719 this.cleanUpChildren(node);
43720 // inserts everything just before this node...
43721 while (node.childNodes.length) {
43722 var cn = node.childNodes[0];
43723 node.removeChild(cn);
43724 node.parentNode.insertBefore(cn, node);
43726 node.parentNode.removeChild(node);
43730 if (!node.attributes || !node.attributes.length) {
43731 this.cleanUpChildren(node);
43735 function cleanAttr(n,v)
43738 if (v.match(/^\./) || v.match(/^\//)) {
43741 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43744 if (v.match(/^#/)) {
43747 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43748 node.removeAttribute(n);
43752 var cwhite = this.cwhite;
43753 var cblack = this.cblack;
43755 function cleanStyle(n,v)
43757 if (v.match(/expression/)) { //XSS?? should we even bother..
43758 node.removeAttribute(n);
43762 var parts = v.split(/;/);
43765 Roo.each(parts, function(p) {
43766 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43770 var l = p.split(':').shift().replace(/\s+/g,'');
43771 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43773 if ( cwhite.length && cblack.indexOf(l) > -1) {
43774 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43775 //node.removeAttribute(n);
43779 // only allow 'c whitelisted system attributes'
43780 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43781 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43782 //node.removeAttribute(n);
43792 if (clean.length) {
43793 node.setAttribute(n, clean.join(';'));
43795 node.removeAttribute(n);
43801 for (var i = node.attributes.length-1; i > -1 ; i--) {
43802 var a = node.attributes[i];
43805 if (a.name.toLowerCase().substr(0,2)=='on') {
43806 node.removeAttribute(a.name);
43809 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43810 node.removeAttribute(a.name);
43813 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43814 cleanAttr(a.name,a.value); // fixme..
43817 if (a.name == 'style') {
43818 cleanStyle(a.name,a.value);
43821 /// clean up MS crap..
43822 // tecnically this should be a list of valid class'es..
43825 if (a.name == 'class') {
43826 if (a.value.match(/^Mso/)) {
43827 node.className = '';
43830 if (a.value.match(/^body$/)) {
43831 node.className = '';
43842 this.cleanUpChildren(node);
43848 * Clean up MS wordisms...
43850 cleanWord : function(node)
43855 this.cleanWord(this.doc.body);
43858 if (node.nodeName == "#text") {
43859 // clean up silly Windows -- stuff?
43862 if (node.nodeName == "#comment") {
43863 node.parentNode.removeChild(node);
43864 // clean up silly Windows -- stuff?
43868 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43869 node.parentNode.removeChild(node);
43873 // remove - but keep children..
43874 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43875 while (node.childNodes.length) {
43876 var cn = node.childNodes[0];
43877 node.removeChild(cn);
43878 node.parentNode.insertBefore(cn, node);
43880 node.parentNode.removeChild(node);
43881 this.iterateChildren(node, this.cleanWord);
43885 if (node.className.length) {
43887 var cn = node.className.split(/\W+/);
43889 Roo.each(cn, function(cls) {
43890 if (cls.match(/Mso[a-zA-Z]+/)) {
43895 node.className = cna.length ? cna.join(' ') : '';
43897 node.removeAttribute("class");
43901 if (node.hasAttribute("lang")) {
43902 node.removeAttribute("lang");
43905 if (node.hasAttribute("style")) {
43907 var styles = node.getAttribute("style").split(";");
43909 Roo.each(styles, function(s) {
43910 if (!s.match(/:/)) {
43913 var kv = s.split(":");
43914 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43917 // what ever is left... we allow.
43920 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43921 if (!nstyle.length) {
43922 node.removeAttribute('style');
43925 this.iterateChildren(node, this.cleanWord);
43931 * iterateChildren of a Node, calling fn each time, using this as the scole..
43932 * @param {DomNode} node node to iterate children of.
43933 * @param {Function} fn method of this class to call on each item.
43935 iterateChildren : function(node, fn)
43937 if (!node.childNodes.length) {
43940 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43941 fn.call(this, node.childNodes[i])
43947 * cleanTableWidths.
43949 * Quite often pasting from word etc.. results in tables with column and widths.
43950 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43953 cleanTableWidths : function(node)
43958 this.cleanTableWidths(this.doc.body);
43963 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43966 Roo.log(node.tagName);
43967 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43968 this.iterateChildren(node, this.cleanTableWidths);
43971 if (node.hasAttribute('width')) {
43972 node.removeAttribute('width');
43976 if (node.hasAttribute("style")) {
43979 var styles = node.getAttribute("style").split(";");
43981 Roo.each(styles, function(s) {
43982 if (!s.match(/:/)) {
43985 var kv = s.split(":");
43986 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43989 // what ever is left... we allow.
43992 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43993 if (!nstyle.length) {
43994 node.removeAttribute('style');
43998 this.iterateChildren(node, this.cleanTableWidths);
44006 domToHTML : function(currentElement, depth, nopadtext) {
44008 depth = depth || 0;
44009 nopadtext = nopadtext || false;
44011 if (!currentElement) {
44012 return this.domToHTML(this.doc.body);
44015 //Roo.log(currentElement);
44017 var allText = false;
44018 var nodeName = currentElement.nodeName;
44019 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44021 if (nodeName == '#text') {
44023 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44028 if (nodeName != 'BODY') {
44031 // Prints the node tagName, such as <A>, <IMG>, etc
44034 for(i = 0; i < currentElement.attributes.length;i++) {
44036 var aname = currentElement.attributes.item(i).name;
44037 if (!currentElement.attributes.item(i).value.length) {
44040 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44043 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44052 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44055 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44060 // Traverse the tree
44062 var currentElementChild = currentElement.childNodes.item(i);
44063 var allText = true;
44064 var innerHTML = '';
44066 while (currentElementChild) {
44067 // Formatting code (indent the tree so it looks nice on the screen)
44068 var nopad = nopadtext;
44069 if (lastnode == 'SPAN') {
44073 if (currentElementChild.nodeName == '#text') {
44074 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44075 toadd = nopadtext ? toadd : toadd.trim();
44076 if (!nopad && toadd.length > 80) {
44077 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44079 innerHTML += toadd;
44082 currentElementChild = currentElement.childNodes.item(i);
44088 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44090 // Recursively traverse the tree structure of the child node
44091 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44092 lastnode = currentElementChild.nodeName;
44094 currentElementChild=currentElement.childNodes.item(i);
44100 // The remaining code is mostly for formatting the tree
44101 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44106 ret+= "</"+tagName+">";
44112 applyBlacklists : function()
44114 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44115 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44119 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44120 if (b.indexOf(tag) > -1) {
44123 this.white.push(tag);
44127 Roo.each(w, function(tag) {
44128 if (b.indexOf(tag) > -1) {
44131 if (this.white.indexOf(tag) > -1) {
44134 this.white.push(tag);
44139 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44140 if (w.indexOf(tag) > -1) {
44143 this.black.push(tag);
44147 Roo.each(b, function(tag) {
44148 if (w.indexOf(tag) > -1) {
44151 if (this.black.indexOf(tag) > -1) {
44154 this.black.push(tag);
44159 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44160 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44164 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44165 if (b.indexOf(tag) > -1) {
44168 this.cwhite.push(tag);
44172 Roo.each(w, function(tag) {
44173 if (b.indexOf(tag) > -1) {
44176 if (this.cwhite.indexOf(tag) > -1) {
44179 this.cwhite.push(tag);
44184 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44185 if (w.indexOf(tag) > -1) {
44188 this.cblack.push(tag);
44192 Roo.each(b, function(tag) {
44193 if (w.indexOf(tag) > -1) {
44196 if (this.cblack.indexOf(tag) > -1) {
44199 this.cblack.push(tag);
44204 setStylesheets : function(stylesheets)
44206 if(typeof(stylesheets) == 'string'){
44207 Roo.get(this.iframe.contentDocument.head).createChild({
44209 rel : 'stylesheet',
44218 Roo.each(stylesheets, function(s) {
44223 Roo.get(_this.iframe.contentDocument.head).createChild({
44225 rel : 'stylesheet',
44234 removeStylesheets : function()
44238 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44243 // hide stuff that is not compatible
44257 * @event specialkey
44261 * @cfg {String} fieldClass @hide
44264 * @cfg {String} focusClass @hide
44267 * @cfg {String} autoCreate @hide
44270 * @cfg {String} inputType @hide
44273 * @cfg {String} invalidClass @hide
44276 * @cfg {String} invalidText @hide
44279 * @cfg {String} msgFx @hide
44282 * @cfg {String} validateOnBlur @hide
44286 Roo.HtmlEditorCore.white = [
44287 'area', 'br', 'img', 'input', 'hr', 'wbr',
44289 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44290 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44291 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44292 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44293 'table', 'ul', 'xmp',
44295 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44298 'dir', 'menu', 'ol', 'ul', 'dl',
44304 Roo.HtmlEditorCore.black = [
44305 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44307 'base', 'basefont', 'bgsound', 'blink', 'body',
44308 'frame', 'frameset', 'head', 'html', 'ilayer',
44309 'iframe', 'layer', 'link', 'meta', 'object',
44310 'script', 'style' ,'title', 'xml' // clean later..
44312 Roo.HtmlEditorCore.clean = [
44313 'script', 'style', 'title', 'xml'
44315 Roo.HtmlEditorCore.remove = [
44320 Roo.HtmlEditorCore.ablack = [
44324 Roo.HtmlEditorCore.aclean = [
44325 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44329 Roo.HtmlEditorCore.pwhite= [
44330 'http', 'https', 'mailto'
44333 // white listed style attributes.
44334 Roo.HtmlEditorCore.cwhite= [
44335 // 'text-align', /// default is to allow most things..
44341 // black listed style attributes.
44342 Roo.HtmlEditorCore.cblack= [
44343 // 'font-size' -- this can be set by the project
44347 Roo.HtmlEditorCore.swapCodes =[
44358 //<script type="text/javascript">
44361 * Ext JS Library 1.1.1
44362 * Copyright(c) 2006-2007, Ext JS, LLC.
44368 Roo.form.HtmlEditor = function(config){
44372 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44374 if (!this.toolbars) {
44375 this.toolbars = [];
44377 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44383 * @class Roo.form.HtmlEditor
44384 * @extends Roo.form.Field
44385 * Provides a lightweight HTML Editor component.
44387 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44389 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44390 * supported by this editor.</b><br/><br/>
44391 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44392 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44394 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44396 * @cfg {Boolean} clearUp
44400 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44405 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44410 * @cfg {Number} height (in pixels)
44414 * @cfg {Number} width (in pixels)
44419 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44422 stylesheets: false,
44426 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44431 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44437 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44442 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44450 // private properties
44451 validationEvent : false,
44453 initialized : false,
44456 onFocus : Roo.emptyFn,
44458 hideMode:'offsets',
44460 actionMode : 'container', // defaults to hiding it...
44462 defaultAutoCreate : { // modified by initCompnoent..
44464 style:"width:500px;height:300px;",
44465 autocomplete: "new-password"
44469 initComponent : function(){
44472 * @event initialize
44473 * Fires when the editor is fully initialized (including the iframe)
44474 * @param {HtmlEditor} this
44479 * Fires when the editor is first receives the focus. Any insertion must wait
44480 * until after this event.
44481 * @param {HtmlEditor} this
44485 * @event beforesync
44486 * Fires before the textarea is updated with content from the editor iframe. Return false
44487 * to cancel the sync.
44488 * @param {HtmlEditor} this
44489 * @param {String} html
44493 * @event beforepush
44494 * Fires before the iframe editor is updated with content from the textarea. Return false
44495 * to cancel the push.
44496 * @param {HtmlEditor} this
44497 * @param {String} html
44502 * Fires when the textarea is updated with content from the editor iframe.
44503 * @param {HtmlEditor} this
44504 * @param {String} html
44509 * Fires when the iframe editor is updated with content from the textarea.
44510 * @param {HtmlEditor} this
44511 * @param {String} html
44515 * @event editmodechange
44516 * Fires when the editor switches edit modes
44517 * @param {HtmlEditor} this
44518 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44520 editmodechange: true,
44522 * @event editorevent
44523 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44524 * @param {HtmlEditor} this
44528 * @event firstfocus
44529 * Fires when on first focus - needed by toolbars..
44530 * @param {HtmlEditor} this
44535 * Auto save the htmlEditor value as a file into Events
44536 * @param {HtmlEditor} this
44540 * @event savedpreview
44541 * preview the saved version of htmlEditor
44542 * @param {HtmlEditor} this
44544 savedpreview: true,
44547 * @event stylesheetsclick
44548 * Fires when press the Sytlesheets button
44549 * @param {Roo.HtmlEditorCore} this
44551 stylesheetsclick: true
44553 this.defaultAutoCreate = {
44555 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44556 autocomplete: "new-password"
44561 * Protected method that will not generally be called directly. It
44562 * is called when the editor creates its toolbar. Override this method if you need to
44563 * add custom toolbar buttons.
44564 * @param {HtmlEditor} editor
44566 createToolbar : function(editor){
44567 Roo.log("create toolbars");
44568 if (!editor.toolbars || !editor.toolbars.length) {
44569 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44572 for (var i =0 ; i < editor.toolbars.length;i++) {
44573 editor.toolbars[i] = Roo.factory(
44574 typeof(editor.toolbars[i]) == 'string' ?
44575 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44576 Roo.form.HtmlEditor);
44577 editor.toolbars[i].init(editor);
44585 onRender : function(ct, position)
44588 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44590 this.wrap = this.el.wrap({
44591 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44594 this.editorcore.onRender(ct, position);
44596 if (this.resizable) {
44597 this.resizeEl = new Roo.Resizable(this.wrap, {
44601 minHeight : this.height,
44602 height: this.height,
44603 handles : this.resizable,
44606 resize : function(r, w, h) {
44607 _t.onResize(w,h); // -something
44613 this.createToolbar(this);
44617 this.setSize(this.wrap.getSize());
44619 if (this.resizeEl) {
44620 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44621 // should trigger onReize..
44624 this.keyNav = new Roo.KeyNav(this.el, {
44626 "tab" : function(e){
44627 e.preventDefault();
44629 var value = this.getValue();
44631 var start = this.el.dom.selectionStart;
44632 var end = this.el.dom.selectionEnd;
44636 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44637 this.el.dom.setSelectionRange(end + 1, end + 1);
44641 var f = value.substring(0, start).split("\t");
44643 if(f.pop().length != 0){
44647 this.setValue(f.join("\t") + value.substring(end));
44648 this.el.dom.setSelectionRange(start - 1, start - 1);
44652 "home" : function(e){
44653 e.preventDefault();
44655 var curr = this.el.dom.selectionStart;
44656 var lines = this.getValue().split("\n");
44663 this.el.dom.setSelectionRange(0, 0);
44669 for (var i = 0; i < lines.length;i++) {
44670 pos += lines[i].length;
44680 pos -= lines[i].length;
44686 this.el.dom.setSelectionRange(pos, pos);
44690 this.el.dom.selectionStart = pos;
44691 this.el.dom.selectionEnd = curr;
44694 "end" : function(e){
44695 e.preventDefault();
44697 var curr = this.el.dom.selectionStart;
44698 var lines = this.getValue().split("\n");
44705 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44711 for (var i = 0; i < lines.length;i++) {
44713 pos += lines[i].length;
44727 this.el.dom.setSelectionRange(pos, pos);
44731 this.el.dom.selectionStart = curr;
44732 this.el.dom.selectionEnd = pos;
44737 doRelay : function(foo, bar, hname){
44738 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44744 // if(this.autosave && this.w){
44745 // this.autoSaveFn = setInterval(this.autosave, 1000);
44750 onResize : function(w, h)
44752 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44757 if(typeof w == 'number'){
44758 var aw = w - this.wrap.getFrameWidth('lr');
44759 this.el.setWidth(this.adjustWidth('textarea', aw));
44762 if(typeof h == 'number'){
44764 for (var i =0; i < this.toolbars.length;i++) {
44765 // fixme - ask toolbars for heights?
44766 tbh += this.toolbars[i].tb.el.getHeight();
44767 if (this.toolbars[i].footer) {
44768 tbh += this.toolbars[i].footer.el.getHeight();
44775 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44776 ah -= 5; // knock a few pixes off for look..
44778 this.el.setHeight(this.adjustWidth('textarea', ah));
44782 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44783 this.editorcore.onResize(ew,eh);
44788 * Toggles the editor between standard and source edit mode.
44789 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44791 toggleSourceEdit : function(sourceEditMode)
44793 this.editorcore.toggleSourceEdit(sourceEditMode);
44795 if(this.editorcore.sourceEditMode){
44796 Roo.log('editor - showing textarea');
44799 // Roo.log(this.syncValue());
44800 this.editorcore.syncValue();
44801 this.el.removeClass('x-hidden');
44802 this.el.dom.removeAttribute('tabIndex');
44805 for (var i = 0; i < this.toolbars.length; i++) {
44806 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44807 this.toolbars[i].tb.hide();
44808 this.toolbars[i].footer.hide();
44813 Roo.log('editor - hiding textarea');
44815 // Roo.log(this.pushValue());
44816 this.editorcore.pushValue();
44818 this.el.addClass('x-hidden');
44819 this.el.dom.setAttribute('tabIndex', -1);
44821 for (var i = 0; i < this.toolbars.length; i++) {
44822 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44823 this.toolbars[i].tb.show();
44824 this.toolbars[i].footer.show();
44828 //this.deferFocus();
44831 this.setSize(this.wrap.getSize());
44832 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44834 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44837 // private (for BoxComponent)
44838 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44840 // private (for BoxComponent)
44841 getResizeEl : function(){
44845 // private (for BoxComponent)
44846 getPositionEl : function(){
44851 initEvents : function(){
44852 this.originalValue = this.getValue();
44856 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44859 markInvalid : Roo.emptyFn,
44861 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44864 clearInvalid : Roo.emptyFn,
44866 setValue : function(v){
44867 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44868 this.editorcore.pushValue();
44873 deferFocus : function(){
44874 this.focus.defer(10, this);
44878 focus : function(){
44879 this.editorcore.focus();
44885 onDestroy : function(){
44891 for (var i =0; i < this.toolbars.length;i++) {
44892 // fixme - ask toolbars for heights?
44893 this.toolbars[i].onDestroy();
44896 this.wrap.dom.innerHTML = '';
44897 this.wrap.remove();
44902 onFirstFocus : function(){
44903 //Roo.log("onFirstFocus");
44904 this.editorcore.onFirstFocus();
44905 for (var i =0; i < this.toolbars.length;i++) {
44906 this.toolbars[i].onFirstFocus();
44912 syncValue : function()
44914 this.editorcore.syncValue();
44917 pushValue : function()
44919 this.editorcore.pushValue();
44922 setStylesheets : function(stylesheets)
44924 this.editorcore.setStylesheets(stylesheets);
44927 removeStylesheets : function()
44929 this.editorcore.removeStylesheets();
44933 // hide stuff that is not compatible
44947 * @event specialkey
44951 * @cfg {String} fieldClass @hide
44954 * @cfg {String} focusClass @hide
44957 * @cfg {String} autoCreate @hide
44960 * @cfg {String} inputType @hide
44963 * @cfg {String} invalidClass @hide
44966 * @cfg {String} invalidText @hide
44969 * @cfg {String} msgFx @hide
44972 * @cfg {String} validateOnBlur @hide
44976 // <script type="text/javascript">
44979 * Ext JS Library 1.1.1
44980 * Copyright(c) 2006-2007, Ext JS, LLC.
44986 * @class Roo.form.HtmlEditorToolbar1
44991 new Roo.form.HtmlEditor({
44994 new Roo.form.HtmlEditorToolbar1({
44995 disable : { fonts: 1 , format: 1, ..., ... , ...],
45001 * @cfg {Object} disable List of elements to disable..
45002 * @cfg {Array} btns List of additional buttons.
45006 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45009 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45012 Roo.apply(this, config);
45014 // default disabled, based on 'good practice'..
45015 this.disable = this.disable || {};
45016 Roo.applyIf(this.disable, {
45019 specialElements : true
45023 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45024 // dont call parent... till later.
45027 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45034 editorcore : false,
45036 * @cfg {Object} disable List of toolbar elements to disable
45043 * @cfg {String} createLinkText The default text for the create link prompt
45045 createLinkText : 'Please enter the URL for the link:',
45047 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45049 defaultLinkValue : 'http:/'+'/',
45053 * @cfg {Array} fontFamilies An array of available font families
45071 // "á" , ?? a acute?
45076 "°" // , // degrees
45078 // "é" , // e ecute
45079 // "ú" , // u ecute?
45082 specialElements : [
45084 text: "Insert Table",
45087 ihtml : '<table><tr><td>Cell</td></tr></table>'
45091 text: "Insert Image",
45094 ihtml : '<img src="about:blank"/>'
45103 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45104 "input:submit", "input:button", "select", "textarea", "label" ],
45107 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45109 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45117 * @cfg {String} defaultFont default font to use.
45119 defaultFont: 'tahoma',
45121 fontSelect : false,
45124 formatCombo : false,
45126 init : function(editor)
45128 this.editor = editor;
45129 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45130 var editorcore = this.editorcore;
45134 var fid = editorcore.frameId;
45136 function btn(id, toggle, handler){
45137 var xid = fid + '-'+ id ;
45141 cls : 'x-btn-icon x-edit-'+id,
45142 enableToggle:toggle !== false,
45143 scope: _t, // was editor...
45144 handler:handler||_t.relayBtnCmd,
45145 clickEvent:'mousedown',
45146 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45153 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45155 // stop form submits
45156 tb.el.on('click', function(e){
45157 e.preventDefault(); // what does this do?
45160 if(!this.disable.font) { // && !Roo.isSafari){
45161 /* why no safari for fonts
45162 editor.fontSelect = tb.el.createChild({
45165 cls:'x-font-select',
45166 html: this.createFontOptions()
45169 editor.fontSelect.on('change', function(){
45170 var font = editor.fontSelect.dom.value;
45171 editor.relayCmd('fontname', font);
45172 editor.deferFocus();
45176 editor.fontSelect.dom,
45182 if(!this.disable.formats){
45183 this.formatCombo = new Roo.form.ComboBox({
45184 store: new Roo.data.SimpleStore({
45187 data : this.formats // from states.js
45191 //autoCreate : {tag: "div", size: "20"},
45192 displayField:'tag',
45196 triggerAction: 'all',
45197 emptyText:'Add tag',
45198 selectOnFocus:true,
45201 'select': function(c, r, i) {
45202 editorcore.insertTag(r.get('tag'));
45208 tb.addField(this.formatCombo);
45212 if(!this.disable.format){
45217 btn('strikethrough')
45220 if(!this.disable.fontSize){
45225 btn('increasefontsize', false, editorcore.adjustFont),
45226 btn('decreasefontsize', false, editorcore.adjustFont)
45231 if(!this.disable.colors){
45234 id:editorcore.frameId +'-forecolor',
45235 cls:'x-btn-icon x-edit-forecolor',
45236 clickEvent:'mousedown',
45237 tooltip: this.buttonTips['forecolor'] || undefined,
45239 menu : new Roo.menu.ColorMenu({
45240 allowReselect: true,
45241 focus: Roo.emptyFn,
45244 selectHandler: function(cp, color){
45245 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45246 editor.deferFocus();
45249 clickEvent:'mousedown'
45252 id:editorcore.frameId +'backcolor',
45253 cls:'x-btn-icon x-edit-backcolor',
45254 clickEvent:'mousedown',
45255 tooltip: this.buttonTips['backcolor'] || undefined,
45257 menu : new Roo.menu.ColorMenu({
45258 focus: Roo.emptyFn,
45261 allowReselect: true,
45262 selectHandler: function(cp, color){
45264 editorcore.execCmd('useCSS', false);
45265 editorcore.execCmd('hilitecolor', color);
45266 editorcore.execCmd('useCSS', true);
45267 editor.deferFocus();
45269 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45270 Roo.isSafari || Roo.isIE ? '#'+color : color);
45271 editor.deferFocus();
45275 clickEvent:'mousedown'
45280 // now add all the items...
45283 if(!this.disable.alignments){
45286 btn('justifyleft'),
45287 btn('justifycenter'),
45288 btn('justifyright')
45292 //if(!Roo.isSafari){
45293 if(!this.disable.links){
45296 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45300 if(!this.disable.lists){
45303 btn('insertorderedlist'),
45304 btn('insertunorderedlist')
45307 if(!this.disable.sourceEdit){
45310 btn('sourceedit', true, function(btn){
45311 this.toggleSourceEdit(btn.pressed);
45318 // special menu.. - needs to be tidied up..
45319 if (!this.disable.special) {
45322 cls: 'x-edit-none',
45328 for (var i =0; i < this.specialChars.length; i++) {
45329 smenu.menu.items.push({
45331 html: this.specialChars[i],
45332 handler: function(a,b) {
45333 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45334 //editor.insertAtCursor(a.html);
45348 if (!this.disable.cleanStyles) {
45350 cls: 'x-btn-icon x-btn-clear',
45356 for (var i =0; i < this.cleanStyles.length; i++) {
45357 cmenu.menu.items.push({
45358 actiontype : this.cleanStyles[i],
45359 html: 'Remove ' + this.cleanStyles[i],
45360 handler: function(a,b) {
45363 var c = Roo.get(editorcore.doc.body);
45364 c.select('[style]').each(function(s) {
45365 s.dom.style.removeProperty(a.actiontype);
45367 editorcore.syncValue();
45372 cmenu.menu.items.push({
45373 actiontype : 'tablewidths',
45374 html: 'Remove Table Widths',
45375 handler: function(a,b) {
45376 editorcore.cleanTableWidths();
45377 editorcore.syncValue();
45381 cmenu.menu.items.push({
45382 actiontype : 'word',
45383 html: 'Remove MS Word Formating',
45384 handler: function(a,b) {
45385 editorcore.cleanWord();
45386 editorcore.syncValue();
45391 cmenu.menu.items.push({
45392 actiontype : 'all',
45393 html: 'Remove All Styles',
45394 handler: function(a,b) {
45396 var c = Roo.get(editorcore.doc.body);
45397 c.select('[style]').each(function(s) {
45398 s.dom.removeAttribute('style');
45400 editorcore.syncValue();
45405 cmenu.menu.items.push({
45406 actiontype : 'all',
45407 html: 'Remove All CSS Classes',
45408 handler: function(a,b) {
45410 var c = Roo.get(editorcore.doc.body);
45411 c.select('[class]').each(function(s) {
45412 s.dom.className = '';
45414 editorcore.syncValue();
45419 cmenu.menu.items.push({
45420 actiontype : 'tidy',
45421 html: 'Tidy HTML Source',
45422 handler: function(a,b) {
45423 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45424 editorcore.syncValue();
45433 if (!this.disable.specialElements) {
45436 cls: 'x-edit-none',
45441 for (var i =0; i < this.specialElements.length; i++) {
45442 semenu.menu.items.push(
45444 handler: function(a,b) {
45445 editor.insertAtCursor(this.ihtml);
45447 }, this.specialElements[i])
45459 for(var i =0; i< this.btns.length;i++) {
45460 var b = Roo.factory(this.btns[i],Roo.form);
45461 b.cls = 'x-edit-none';
45463 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45464 b.cls += ' x-init-enable';
45467 b.scope = editorcore;
45475 // disable everything...
45477 this.tb.items.each(function(item){
45480 item.id != editorcore.frameId+ '-sourceedit' &&
45481 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45487 this.rendered = true;
45489 // the all the btns;
45490 editor.on('editorevent', this.updateToolbar, this);
45491 // other toolbars need to implement this..
45492 //editor.on('editmodechange', this.updateToolbar, this);
45496 relayBtnCmd : function(btn) {
45497 this.editorcore.relayCmd(btn.cmd);
45499 // private used internally
45500 createLink : function(){
45501 Roo.log("create link?");
45502 var url = prompt(this.createLinkText, this.defaultLinkValue);
45503 if(url && url != 'http:/'+'/'){
45504 this.editorcore.relayCmd('createlink', url);
45510 * Protected method that will not generally be called directly. It triggers
45511 * a toolbar update by reading the markup state of the current selection in the editor.
45513 updateToolbar: function(){
45515 if(!this.editorcore.activated){
45516 this.editor.onFirstFocus();
45520 var btns = this.tb.items.map,
45521 doc = this.editorcore.doc,
45522 frameId = this.editorcore.frameId;
45524 if(!this.disable.font && !Roo.isSafari){
45526 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45527 if(name != this.fontSelect.dom.value){
45528 this.fontSelect.dom.value = name;
45532 if(!this.disable.format){
45533 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45534 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45535 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45536 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45538 if(!this.disable.alignments){
45539 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45540 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45541 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45543 if(!Roo.isSafari && !this.disable.lists){
45544 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45545 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45548 var ans = this.editorcore.getAllAncestors();
45549 if (this.formatCombo) {
45552 var store = this.formatCombo.store;
45553 this.formatCombo.setValue("");
45554 for (var i =0; i < ans.length;i++) {
45555 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45557 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45565 // hides menus... - so this cant be on a menu...
45566 Roo.menu.MenuMgr.hideAll();
45568 //this.editorsyncValue();
45572 createFontOptions : function(){
45573 var buf = [], fs = this.fontFamilies, ff, lc;
45577 for(var i = 0, len = fs.length; i< len; i++){
45579 lc = ff.toLowerCase();
45581 '<option value="',lc,'" style="font-family:',ff,';"',
45582 (this.defaultFont == lc ? ' selected="true">' : '>'),
45587 return buf.join('');
45590 toggleSourceEdit : function(sourceEditMode){
45592 Roo.log("toolbar toogle");
45593 if(sourceEditMode === undefined){
45594 sourceEditMode = !this.sourceEditMode;
45596 this.sourceEditMode = sourceEditMode === true;
45597 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45598 // just toggle the button?
45599 if(btn.pressed !== this.sourceEditMode){
45600 btn.toggle(this.sourceEditMode);
45604 if(sourceEditMode){
45605 Roo.log("disabling buttons");
45606 this.tb.items.each(function(item){
45607 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45613 Roo.log("enabling buttons");
45614 if(this.editorcore.initialized){
45615 this.tb.items.each(function(item){
45621 Roo.log("calling toggole on editor");
45622 // tell the editor that it's been pressed..
45623 this.editor.toggleSourceEdit(sourceEditMode);
45627 * Object collection of toolbar tooltips for the buttons in the editor. The key
45628 * is the command id associated with that button and the value is a valid QuickTips object.
45633 title: 'Bold (Ctrl+B)',
45634 text: 'Make the selected text bold.',
45635 cls: 'x-html-editor-tip'
45638 title: 'Italic (Ctrl+I)',
45639 text: 'Make the selected text italic.',
45640 cls: 'x-html-editor-tip'
45648 title: 'Bold (Ctrl+B)',
45649 text: 'Make the selected text bold.',
45650 cls: 'x-html-editor-tip'
45653 title: 'Italic (Ctrl+I)',
45654 text: 'Make the selected text italic.',
45655 cls: 'x-html-editor-tip'
45658 title: 'Underline (Ctrl+U)',
45659 text: 'Underline the selected text.',
45660 cls: 'x-html-editor-tip'
45663 title: 'Strikethrough',
45664 text: 'Strikethrough the selected text.',
45665 cls: 'x-html-editor-tip'
45667 increasefontsize : {
45668 title: 'Grow Text',
45669 text: 'Increase the font size.',
45670 cls: 'x-html-editor-tip'
45672 decreasefontsize : {
45673 title: 'Shrink Text',
45674 text: 'Decrease the font size.',
45675 cls: 'x-html-editor-tip'
45678 title: 'Text Highlight Color',
45679 text: 'Change the background color of the selected text.',
45680 cls: 'x-html-editor-tip'
45683 title: 'Font Color',
45684 text: 'Change the color of the selected text.',
45685 cls: 'x-html-editor-tip'
45688 title: 'Align Text Left',
45689 text: 'Align text to the left.',
45690 cls: 'x-html-editor-tip'
45693 title: 'Center Text',
45694 text: 'Center text in the editor.',
45695 cls: 'x-html-editor-tip'
45698 title: 'Align Text Right',
45699 text: 'Align text to the right.',
45700 cls: 'x-html-editor-tip'
45702 insertunorderedlist : {
45703 title: 'Bullet List',
45704 text: 'Start a bulleted list.',
45705 cls: 'x-html-editor-tip'
45707 insertorderedlist : {
45708 title: 'Numbered List',
45709 text: 'Start a numbered list.',
45710 cls: 'x-html-editor-tip'
45713 title: 'Hyperlink',
45714 text: 'Make the selected text a hyperlink.',
45715 cls: 'x-html-editor-tip'
45718 title: 'Source Edit',
45719 text: 'Switch to source editing mode.',
45720 cls: 'x-html-editor-tip'
45724 onDestroy : function(){
45727 this.tb.items.each(function(item){
45729 item.menu.removeAll();
45731 item.menu.el.destroy();
45739 onFirstFocus: function() {
45740 this.tb.items.each(function(item){
45749 // <script type="text/javascript">
45752 * Ext JS Library 1.1.1
45753 * Copyright(c) 2006-2007, Ext JS, LLC.
45760 * @class Roo.form.HtmlEditor.ToolbarContext
45765 new Roo.form.HtmlEditor({
45768 { xtype: 'ToolbarStandard', styles : {} }
45769 { xtype: 'ToolbarContext', disable : {} }
45775 * @config : {Object} disable List of elements to disable.. (not done yet.)
45776 * @config : {Object} styles Map of styles available.
45780 Roo.form.HtmlEditor.ToolbarContext = function(config)
45783 Roo.apply(this, config);
45784 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45785 // dont call parent... till later.
45786 this.styles = this.styles || {};
45791 Roo.form.HtmlEditor.ToolbarContext.types = {
45803 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45869 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45874 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45884 style : 'fontFamily',
45885 displayField: 'display',
45886 optname : 'font-family',
45935 // should we really allow this??
45936 // should this just be
45947 style : 'fontFamily',
45948 displayField: 'display',
45949 optname : 'font-family',
45956 style : 'fontFamily',
45957 displayField: 'display',
45958 optname : 'font-family',
45965 style : 'fontFamily',
45966 displayField: 'display',
45967 optname : 'font-family',
45978 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45979 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45981 Roo.form.HtmlEditor.ToolbarContext.options = {
45983 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45984 [ 'Courier New', 'Courier New'],
45985 [ 'Tahoma', 'Tahoma'],
45986 [ 'Times New Roman,serif', 'Times'],
45987 [ 'Verdana','Verdana' ]
45991 // fixme - these need to be configurable..
45994 //Roo.form.HtmlEditor.ToolbarContext.types
45997 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46004 editorcore : false,
46006 * @cfg {Object} disable List of toolbar elements to disable
46011 * @cfg {Object} styles List of styles
46012 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46014 * These must be defined in the page, so they get rendered correctly..
46025 init : function(editor)
46027 this.editor = editor;
46028 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46029 var editorcore = this.editorcore;
46031 var fid = editorcore.frameId;
46033 function btn(id, toggle, handler){
46034 var xid = fid + '-'+ id ;
46038 cls : 'x-btn-icon x-edit-'+id,
46039 enableToggle:toggle !== false,
46040 scope: editorcore, // was editor...
46041 handler:handler||editorcore.relayBtnCmd,
46042 clickEvent:'mousedown',
46043 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46047 // create a new element.
46048 var wdiv = editor.wrap.createChild({
46050 }, editor.wrap.dom.firstChild.nextSibling, true);
46052 // can we do this more than once??
46054 // stop form submits
46057 // disable everything...
46058 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46059 this.toolbars = {};
46061 for (var i in ty) {
46063 this.toolbars[i] = this.buildToolbar(ty[i],i);
46065 this.tb = this.toolbars.BODY;
46067 this.buildFooter();
46068 this.footer.show();
46069 editor.on('hide', function( ) { this.footer.hide() }, this);
46070 editor.on('show', function( ) { this.footer.show() }, this);
46073 this.rendered = true;
46075 // the all the btns;
46076 editor.on('editorevent', this.updateToolbar, this);
46077 // other toolbars need to implement this..
46078 //editor.on('editmodechange', this.updateToolbar, this);
46084 * Protected method that will not generally be called directly. It triggers
46085 * a toolbar update by reading the markup state of the current selection in the editor.
46087 * Note you can force an update by calling on('editorevent', scope, false)
46089 updateToolbar: function(editor,ev,sel){
46092 // capture mouse up - this is handy for selecting images..
46093 // perhaps should go somewhere else...
46094 if(!this.editorcore.activated){
46095 this.editor.onFirstFocus();
46101 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46102 // selectNode - might want to handle IE?
46104 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46105 ev.target && ev.target.tagName == 'IMG') {
46106 // they have click on an image...
46107 // let's see if we can change the selection...
46110 var nodeRange = sel.ownerDocument.createRange();
46112 nodeRange.selectNode(sel);
46114 nodeRange.selectNodeContents(sel);
46116 //nodeRange.collapse(true);
46117 var s = this.editorcore.win.getSelection();
46118 s.removeAllRanges();
46119 s.addRange(nodeRange);
46123 var updateFooter = sel ? false : true;
46126 var ans = this.editorcore.getAllAncestors();
46129 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46132 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46133 sel = sel ? sel : this.editorcore.doc.body;
46134 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46137 // pick a menu that exists..
46138 var tn = sel.tagName.toUpperCase();
46139 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46141 tn = sel.tagName.toUpperCase();
46143 var lastSel = this.tb.selectedNode;
46145 this.tb.selectedNode = sel;
46147 // if current menu does not match..
46149 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46152 ///console.log("show: " + tn);
46153 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46156 this.tb.items.first().el.innerHTML = tn + ': ';
46159 // update attributes
46160 if (this.tb.fields) {
46161 this.tb.fields.each(function(e) {
46163 e.setValue(sel.style[e.stylename]);
46166 e.setValue(sel.getAttribute(e.attrname));
46170 var hasStyles = false;
46171 for(var i in this.styles) {
46178 var st = this.tb.fields.item(0);
46180 st.store.removeAll();
46183 var cn = sel.className.split(/\s+/);
46186 if (this.styles['*']) {
46188 Roo.each(this.styles['*'], function(v) {
46189 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46192 if (this.styles[tn]) {
46193 Roo.each(this.styles[tn], function(v) {
46194 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46198 st.store.loadData(avs);
46202 // flag our selected Node.
46203 this.tb.selectedNode = sel;
46206 Roo.menu.MenuMgr.hideAll();
46210 if (!updateFooter) {
46211 //this.footDisp.dom.innerHTML = '';
46214 // update the footer
46218 this.footerEls = ans.reverse();
46219 Roo.each(this.footerEls, function(a,i) {
46220 if (!a) { return; }
46221 html += html.length ? ' > ' : '';
46223 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46228 var sz = this.footDisp.up('td').getSize();
46229 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46230 this.footDisp.dom.style.marginLeft = '5px';
46232 this.footDisp.dom.style.overflow = 'hidden';
46234 this.footDisp.dom.innerHTML = html;
46236 //this.editorsyncValue();
46243 onDestroy : function(){
46246 this.tb.items.each(function(item){
46248 item.menu.removeAll();
46250 item.menu.el.destroy();
46258 onFirstFocus: function() {
46259 // need to do this for all the toolbars..
46260 this.tb.items.each(function(item){
46264 buildToolbar: function(tlist, nm)
46266 var editor = this.editor;
46267 var editorcore = this.editorcore;
46268 // create a new element.
46269 var wdiv = editor.wrap.createChild({
46271 }, editor.wrap.dom.firstChild.nextSibling, true);
46274 var tb = new Roo.Toolbar(wdiv);
46277 tb.add(nm+ ": ");
46280 for(var i in this.styles) {
46285 if (styles && styles.length) {
46287 // this needs a multi-select checkbox...
46288 tb.addField( new Roo.form.ComboBox({
46289 store: new Roo.data.SimpleStore({
46291 fields: ['val', 'selected'],
46294 name : '-roo-edit-className',
46295 attrname : 'className',
46296 displayField: 'val',
46300 triggerAction: 'all',
46301 emptyText:'Select Style',
46302 selectOnFocus:true,
46305 'select': function(c, r, i) {
46306 // initial support only for on class per el..
46307 tb.selectedNode.className = r ? r.get('val') : '';
46308 editorcore.syncValue();
46315 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46316 var tbops = tbc.options;
46318 for (var i in tlist) {
46320 var item = tlist[i];
46321 tb.add(item.title + ": ");
46324 //optname == used so you can configure the options available..
46325 var opts = item.opts ? item.opts : false;
46326 if (item.optname) {
46327 opts = tbops[item.optname];
46332 // opts == pulldown..
46333 tb.addField( new Roo.form.ComboBox({
46334 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46336 fields: ['val', 'display'],
46339 name : '-roo-edit-' + i,
46341 stylename : item.style ? item.style : false,
46342 displayField: item.displayField ? item.displayField : 'val',
46343 valueField : 'val',
46345 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46347 triggerAction: 'all',
46348 emptyText:'Select',
46349 selectOnFocus:true,
46350 width: item.width ? item.width : 130,
46352 'select': function(c, r, i) {
46354 tb.selectedNode.style[c.stylename] = r.get('val');
46357 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46366 tb.addField( new Roo.form.TextField({
46369 //allowBlank:false,
46374 tb.addField( new Roo.form.TextField({
46375 name: '-roo-edit-' + i,
46382 'change' : function(f, nv, ov) {
46383 tb.selectedNode.setAttribute(f.attrname, nv);
46384 editorcore.syncValue();
46397 text: 'Stylesheets',
46400 click : function ()
46402 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46410 text: 'Remove Tag',
46413 click : function ()
46416 // undo does not work.
46418 var sn = tb.selectedNode;
46420 var pn = sn.parentNode;
46422 var stn = sn.childNodes[0];
46423 var en = sn.childNodes[sn.childNodes.length - 1 ];
46424 while (sn.childNodes.length) {
46425 var node = sn.childNodes[0];
46426 sn.removeChild(node);
46428 pn.insertBefore(node, sn);
46431 pn.removeChild(sn);
46432 var range = editorcore.createRange();
46434 range.setStart(stn,0);
46435 range.setEnd(en,0); //????
46436 //range.selectNode(sel);
46439 var selection = editorcore.getSelection();
46440 selection.removeAllRanges();
46441 selection.addRange(range);
46445 //_this.updateToolbar(null, null, pn);
46446 _this.updateToolbar(null, null, null);
46447 _this.footDisp.dom.innerHTML = '';
46457 tb.el.on('click', function(e){
46458 e.preventDefault(); // what does this do?
46460 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46463 // dont need to disable them... as they will get hidden
46468 buildFooter : function()
46471 var fel = this.editor.wrap.createChild();
46472 this.footer = new Roo.Toolbar(fel);
46473 // toolbar has scrolly on left / right?
46474 var footDisp= new Roo.Toolbar.Fill();
46480 handler : function() {
46481 _t.footDisp.scrollTo('left',0,true)
46485 this.footer.add( footDisp );
46490 handler : function() {
46492 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46496 var fel = Roo.get(footDisp.el);
46497 fel.addClass('x-editor-context');
46498 this.footDispWrap = fel;
46499 this.footDispWrap.overflow = 'hidden';
46501 this.footDisp = fel.createChild();
46502 this.footDispWrap.on('click', this.onContextClick, this)
46506 onContextClick : function (ev,dom)
46508 ev.preventDefault();
46509 var cn = dom.className;
46511 if (!cn.match(/x-ed-loc-/)) {
46514 var n = cn.split('-').pop();
46515 var ans = this.footerEls;
46519 var range = this.editorcore.createRange();
46521 range.selectNodeContents(sel);
46522 //range.selectNode(sel);
46525 var selection = this.editorcore.getSelection();
46526 selection.removeAllRanges();
46527 selection.addRange(range);
46531 this.updateToolbar(null, null, sel);
46548 * Ext JS Library 1.1.1
46549 * Copyright(c) 2006-2007, Ext JS, LLC.
46551 * Originally Released Under LGPL - original licence link has changed is not relivant.
46554 * <script type="text/javascript">
46558 * @class Roo.form.BasicForm
46559 * @extends Roo.util.Observable
46560 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46562 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46563 * @param {Object} config Configuration options
46565 Roo.form.BasicForm = function(el, config){
46566 this.allItems = [];
46567 this.childForms = [];
46568 Roo.apply(this, config);
46570 * The Roo.form.Field items in this form.
46571 * @type MixedCollection
46575 this.items = new Roo.util.MixedCollection(false, function(o){
46576 return o.id || (o.id = Roo.id());
46580 * @event beforeaction
46581 * Fires before any action is performed. Return false to cancel the action.
46582 * @param {Form} this
46583 * @param {Action} action The action to be performed
46585 beforeaction: true,
46587 * @event actionfailed
46588 * Fires when an action fails.
46589 * @param {Form} this
46590 * @param {Action} action The action that failed
46592 actionfailed : true,
46594 * @event actioncomplete
46595 * Fires when an action is completed.
46596 * @param {Form} this
46597 * @param {Action} action The action that completed
46599 actioncomplete : true
46604 Roo.form.BasicForm.superclass.constructor.call(this);
46607 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46609 * @cfg {String} method
46610 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46613 * @cfg {DataReader} reader
46614 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46615 * This is optional as there is built-in support for processing JSON.
46618 * @cfg {DataReader} errorReader
46619 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46620 * This is completely optional as there is built-in support for processing JSON.
46623 * @cfg {String} url
46624 * The URL to use for form actions if one isn't supplied in the action options.
46627 * @cfg {Boolean} fileUpload
46628 * Set to true if this form is a file upload.
46632 * @cfg {Object} baseParams
46633 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46638 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46643 activeAction : null,
46646 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46647 * or setValues() data instead of when the form was first created.
46649 trackResetOnLoad : false,
46653 * childForms - used for multi-tab forms
46656 childForms : false,
46659 * allItems - full list of fields.
46665 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46666 * element by passing it or its id or mask the form itself by passing in true.
46669 waitMsgTarget : false,
46672 initEl : function(el){
46673 this.el = Roo.get(el);
46674 this.id = this.el.id || Roo.id();
46675 this.el.on('submit', this.onSubmit, this);
46676 this.el.addClass('x-form');
46680 onSubmit : function(e){
46685 * Returns true if client-side validation on the form is successful.
46688 isValid : function(){
46690 this.items.each(function(f){
46699 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46702 isDirty : function(){
46704 this.items.each(function(f){
46714 * Returns true if any fields in this form have changed since their original load. (New version)
46718 hasChanged : function()
46721 this.items.each(function(f){
46722 if(f.hasChanged()){
46731 * Resets all hasChanged to 'false' -
46732 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46733 * So hasChanged storage is only to be used for this purpose
46736 resetHasChanged : function()
46738 this.items.each(function(f){
46739 f.resetHasChanged();
46746 * Performs a predefined action (submit or load) or custom actions you define on this form.
46747 * @param {String} actionName The name of the action type
46748 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46749 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46750 * accept other config options):
46752 Property Type Description
46753 ---------------- --------------- ----------------------------------------------------------------------------------
46754 url String The url for the action (defaults to the form's url)
46755 method String The form method to use (defaults to the form's method, or POST if not defined)
46756 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46757 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46758 validate the form on the client (defaults to false)
46760 * @return {BasicForm} this
46762 doAction : function(action, options){
46763 if(typeof action == 'string'){
46764 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46766 if(this.fireEvent('beforeaction', this, action) !== false){
46767 this.beforeAction(action);
46768 action.run.defer(100, action);
46774 * Shortcut to do a submit action.
46775 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46776 * @return {BasicForm} this
46778 submit : function(options){
46779 this.doAction('submit', options);
46784 * Shortcut to do a load action.
46785 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46786 * @return {BasicForm} this
46788 load : function(options){
46789 this.doAction('load', options);
46794 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46795 * @param {Record} record The record to edit
46796 * @return {BasicForm} this
46798 updateRecord : function(record){
46799 record.beginEdit();
46800 var fs = record.fields;
46801 fs.each(function(f){
46802 var field = this.findField(f.name);
46804 record.set(f.name, field.getValue());
46812 * Loads an Roo.data.Record into this form.
46813 * @param {Record} record The record to load
46814 * @return {BasicForm} this
46816 loadRecord : function(record){
46817 this.setValues(record.data);
46822 beforeAction : function(action){
46823 var o = action.options;
46826 if(this.waitMsgTarget === true){
46827 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46828 }else if(this.waitMsgTarget){
46829 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46830 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46832 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46838 afterAction : function(action, success){
46839 this.activeAction = null;
46840 var o = action.options;
46842 if(this.waitMsgTarget === true){
46844 }else if(this.waitMsgTarget){
46845 this.waitMsgTarget.unmask();
46847 Roo.MessageBox.updateProgress(1);
46848 Roo.MessageBox.hide();
46855 Roo.callback(o.success, o.scope, [this, action]);
46856 this.fireEvent('actioncomplete', this, action);
46860 // failure condition..
46861 // we have a scenario where updates need confirming.
46862 // eg. if a locking scenario exists..
46863 // we look for { errors : { needs_confirm : true }} in the response.
46865 (typeof(action.result) != 'undefined') &&
46866 (typeof(action.result.errors) != 'undefined') &&
46867 (typeof(action.result.errors.needs_confirm) != 'undefined')
46870 Roo.MessageBox.confirm(
46871 "Change requires confirmation",
46872 action.result.errorMsg,
46877 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46887 Roo.callback(o.failure, o.scope, [this, action]);
46888 // show an error message if no failed handler is set..
46889 if (!this.hasListener('actionfailed')) {
46890 Roo.MessageBox.alert("Error",
46891 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46892 action.result.errorMsg :
46893 "Saving Failed, please check your entries or try again"
46897 this.fireEvent('actionfailed', this, action);
46903 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46904 * @param {String} id The value to search for
46907 findField : function(id){
46908 var field = this.items.get(id);
46910 this.items.each(function(f){
46911 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46917 return field || null;
46921 * Add a secondary form to this one,
46922 * Used to provide tabbed forms. One form is primary, with hidden values
46923 * which mirror the elements from the other forms.
46925 * @param {Roo.form.Form} form to add.
46928 addForm : function(form)
46931 if (this.childForms.indexOf(form) > -1) {
46935 this.childForms.push(form);
46937 Roo.each(form.allItems, function (fe) {
46939 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46940 if (this.findField(n)) { // already added..
46943 var add = new Roo.form.Hidden({
46946 add.render(this.el);
46953 * Mark fields in this form invalid in bulk.
46954 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46955 * @return {BasicForm} this
46957 markInvalid : function(errors){
46958 if(errors instanceof Array){
46959 for(var i = 0, len = errors.length; i < len; i++){
46960 var fieldError = errors[i];
46961 var f = this.findField(fieldError.id);
46963 f.markInvalid(fieldError.msg);
46969 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46970 field.markInvalid(errors[id]);
46974 Roo.each(this.childForms || [], function (f) {
46975 f.markInvalid(errors);
46982 * Set values for fields in this form in bulk.
46983 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46984 * @return {BasicForm} this
46986 setValues : function(values){
46987 if(values instanceof Array){ // array of objects
46988 for(var i = 0, len = values.length; i < len; i++){
46990 var f = this.findField(v.id);
46992 f.setValue(v.value);
46993 if(this.trackResetOnLoad){
46994 f.originalValue = f.getValue();
46998 }else{ // object hash
47001 if(typeof values[id] != 'function' && (field = this.findField(id))){
47003 if (field.setFromData &&
47004 field.valueField &&
47005 field.displayField &&
47006 // combos' with local stores can
47007 // be queried via setValue()
47008 // to set their value..
47009 (field.store && !field.store.isLocal)
47013 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47014 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47015 field.setFromData(sd);
47018 field.setValue(values[id]);
47022 if(this.trackResetOnLoad){
47023 field.originalValue = field.getValue();
47028 this.resetHasChanged();
47031 Roo.each(this.childForms || [], function (f) {
47032 f.setValues(values);
47033 f.resetHasChanged();
47040 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47041 * they are returned as an array.
47042 * @param {Boolean} asString
47045 getValues : function(asString){
47046 if (this.childForms) {
47047 // copy values from the child forms
47048 Roo.each(this.childForms, function (f) {
47049 this.setValues(f.getValues());
47055 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47056 if(asString === true){
47059 return Roo.urlDecode(fs);
47063 * Returns the fields in this form as an object with key/value pairs.
47064 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47067 getFieldValues : function(with_hidden)
47069 if (this.childForms) {
47070 // copy values from the child forms
47071 // should this call getFieldValues - probably not as we do not currently copy
47072 // hidden fields when we generate..
47073 Roo.each(this.childForms, function (f) {
47074 this.setValues(f.getValues());
47079 this.items.each(function(f){
47080 if (!f.getName()) {
47083 var v = f.getValue();
47084 if (f.inputType =='radio') {
47085 if (typeof(ret[f.getName()]) == 'undefined') {
47086 ret[f.getName()] = ''; // empty..
47089 if (!f.el.dom.checked) {
47093 v = f.el.dom.value;
47097 // not sure if this supported any more..
47098 if ((typeof(v) == 'object') && f.getRawValue) {
47099 v = f.getRawValue() ; // dates..
47101 // combo boxes where name != hiddenName...
47102 if (f.name != f.getName()) {
47103 ret[f.name] = f.getRawValue();
47105 ret[f.getName()] = v;
47112 * Clears all invalid messages in this form.
47113 * @return {BasicForm} this
47115 clearInvalid : function(){
47116 this.items.each(function(f){
47120 Roo.each(this.childForms || [], function (f) {
47129 * Resets this form.
47130 * @return {BasicForm} this
47132 reset : function(){
47133 this.items.each(function(f){
47137 Roo.each(this.childForms || [], function (f) {
47140 this.resetHasChanged();
47146 * Add Roo.form components to this form.
47147 * @param {Field} field1
47148 * @param {Field} field2 (optional)
47149 * @param {Field} etc (optional)
47150 * @return {BasicForm} this
47153 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47159 * Removes a field from the items collection (does NOT remove its markup).
47160 * @param {Field} field
47161 * @return {BasicForm} this
47163 remove : function(field){
47164 this.items.remove(field);
47169 * Looks at the fields in this form, checks them for an id attribute,
47170 * and calls applyTo on the existing dom element with that id.
47171 * @return {BasicForm} this
47173 render : function(){
47174 this.items.each(function(f){
47175 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47183 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47184 * @param {Object} values
47185 * @return {BasicForm} this
47187 applyToFields : function(o){
47188 this.items.each(function(f){
47195 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47196 * @param {Object} values
47197 * @return {BasicForm} this
47199 applyIfToFields : function(o){
47200 this.items.each(function(f){
47208 Roo.BasicForm = Roo.form.BasicForm;/*
47210 * Ext JS Library 1.1.1
47211 * Copyright(c) 2006-2007, Ext JS, LLC.
47213 * Originally Released Under LGPL - original licence link has changed is not relivant.
47216 * <script type="text/javascript">
47220 * @class Roo.form.Form
47221 * @extends Roo.form.BasicForm
47222 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47224 * @param {Object} config Configuration options
47226 Roo.form.Form = function(config){
47228 if (config.items) {
47229 xitems = config.items;
47230 delete config.items;
47234 Roo.form.Form.superclass.constructor.call(this, null, config);
47235 this.url = this.url || this.action;
47237 this.root = new Roo.form.Layout(Roo.applyIf({
47241 this.active = this.root;
47243 * Array of all the buttons that have been added to this form via {@link addButton}
47247 this.allItems = [];
47250 * @event clientvalidation
47251 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47252 * @param {Form} this
47253 * @param {Boolean} valid true if the form has passed client-side validation
47255 clientvalidation: true,
47258 * Fires when the form is rendered
47259 * @param {Roo.form.Form} form
47264 if (this.progressUrl) {
47265 // push a hidden field onto the list of fields..
47269 name : 'UPLOAD_IDENTIFIER'
47274 Roo.each(xitems, this.addxtype, this);
47280 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47282 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47285 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47288 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47290 buttonAlign:'center',
47293 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47298 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47299 * This property cascades to child containers if not set.
47304 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47305 * fires a looping event with that state. This is required to bind buttons to the valid
47306 * state using the config value formBind:true on the button.
47308 monitorValid : false,
47311 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47316 * @cfg {String} progressUrl - Url to return progress data
47319 progressUrl : false,
47322 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47323 * fields are added and the column is closed. If no fields are passed the column remains open
47324 * until end() is called.
47325 * @param {Object} config The config to pass to the column
47326 * @param {Field} field1 (optional)
47327 * @param {Field} field2 (optional)
47328 * @param {Field} etc (optional)
47329 * @return Column The column container object
47331 column : function(c){
47332 var col = new Roo.form.Column(c);
47334 if(arguments.length > 1){ // duplicate code required because of Opera
47335 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47342 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47343 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47344 * until end() is called.
47345 * @param {Object} config The config to pass to the fieldset
47346 * @param {Field} field1 (optional)
47347 * @param {Field} field2 (optional)
47348 * @param {Field} etc (optional)
47349 * @return FieldSet The fieldset container object
47351 fieldset : function(c){
47352 var fs = new Roo.form.FieldSet(c);
47354 if(arguments.length > 1){ // duplicate code required because of Opera
47355 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47362 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47363 * fields are added and the container is closed. If no fields are passed the container remains open
47364 * until end() is called.
47365 * @param {Object} config The config to pass to the Layout
47366 * @param {Field} field1 (optional)
47367 * @param {Field} field2 (optional)
47368 * @param {Field} etc (optional)
47369 * @return Layout The container object
47371 container : function(c){
47372 var l = new Roo.form.Layout(c);
47374 if(arguments.length > 1){ // duplicate code required because of Opera
47375 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47382 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47383 * @param {Object} container A Roo.form.Layout or subclass of Layout
47384 * @return {Form} this
47386 start : function(c){
47387 // cascade label info
47388 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47389 this.active.stack.push(c);
47390 c.ownerCt = this.active;
47396 * Closes the current open container
47397 * @return {Form} this
47400 if(this.active == this.root){
47403 this.active = this.active.ownerCt;
47408 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47409 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47410 * as the label of the field.
47411 * @param {Field} field1
47412 * @param {Field} field2 (optional)
47413 * @param {Field} etc. (optional)
47414 * @return {Form} this
47417 this.active.stack.push.apply(this.active.stack, arguments);
47418 this.allItems.push.apply(this.allItems,arguments);
47420 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47421 if(a[i].isFormField){
47426 Roo.form.Form.superclass.add.apply(this, r);
47436 * Find any element that has been added to a form, using it's ID or name
47437 * This can include framesets, columns etc. along with regular fields..
47438 * @param {String} id - id or name to find.
47440 * @return {Element} e - or false if nothing found.
47442 findbyId : function(id)
47448 Roo.each(this.allItems, function(f){
47449 if (f.id == id || f.name == id ){
47460 * Render this form into the passed container. This should only be called once!
47461 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47462 * @return {Form} this
47464 render : function(ct)
47470 var o = this.autoCreate || {
47472 method : this.method || 'POST',
47473 id : this.id || Roo.id()
47475 this.initEl(ct.createChild(o));
47477 this.root.render(this.el);
47481 this.items.each(function(f){
47482 f.render('x-form-el-'+f.id);
47485 if(this.buttons.length > 0){
47486 // tables are required to maintain order and for correct IE layout
47487 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47488 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47489 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47491 var tr = tb.getElementsByTagName('tr')[0];
47492 for(var i = 0, len = this.buttons.length; i < len; i++) {
47493 var b = this.buttons[i];
47494 var td = document.createElement('td');
47495 td.className = 'x-form-btn-td';
47496 b.render(tr.appendChild(td));
47499 if(this.monitorValid){ // initialize after render
47500 this.startMonitoring();
47502 this.fireEvent('rendered', this);
47507 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47508 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47509 * object or a valid Roo.DomHelper element config
47510 * @param {Function} handler The function called when the button is clicked
47511 * @param {Object} scope (optional) The scope of the handler function
47512 * @return {Roo.Button}
47514 addButton : function(config, handler, scope){
47518 minWidth: this.minButtonWidth,
47521 if(typeof config == "string"){
47524 Roo.apply(bc, config);
47526 var btn = new Roo.Button(null, bc);
47527 this.buttons.push(btn);
47532 * Adds a series of form elements (using the xtype property as the factory method.
47533 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47534 * @param {Object} config
47537 addxtype : function()
47539 var ar = Array.prototype.slice.call(arguments, 0);
47541 for(var i = 0; i < ar.length; i++) {
47543 continue; // skip -- if this happends something invalid got sent, we
47544 // should ignore it, as basically that interface element will not show up
47545 // and that should be pretty obvious!!
47548 if (Roo.form[ar[i].xtype]) {
47550 var fe = Roo.factory(ar[i], Roo.form);
47556 fe.store.form = this;
47561 this.allItems.push(fe);
47562 if (fe.items && fe.addxtype) {
47563 fe.addxtype.apply(fe, fe.items);
47573 // console.log('adding ' + ar[i].xtype);
47575 if (ar[i].xtype == 'Button') {
47576 //console.log('adding button');
47577 //console.log(ar[i]);
47578 this.addButton(ar[i]);
47579 this.allItems.push(fe);
47583 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47584 alert('end is not supported on xtype any more, use items');
47586 // //console.log('adding end');
47594 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47595 * option "monitorValid"
47597 startMonitoring : function(){
47600 Roo.TaskMgr.start({
47601 run : this.bindHandler,
47602 interval : this.monitorPoll || 200,
47609 * Stops monitoring of the valid state of this form
47611 stopMonitoring : function(){
47612 this.bound = false;
47616 bindHandler : function(){
47618 return false; // stops binding
47621 this.items.each(function(f){
47622 if(!f.isValid(true)){
47627 for(var i = 0, len = this.buttons.length; i < len; i++){
47628 var btn = this.buttons[i];
47629 if(btn.formBind === true && btn.disabled === valid){
47630 btn.setDisabled(!valid);
47633 this.fireEvent('clientvalidation', this, valid);
47647 Roo.Form = Roo.form.Form;
47650 * Ext JS Library 1.1.1
47651 * Copyright(c) 2006-2007, Ext JS, LLC.
47653 * Originally Released Under LGPL - original licence link has changed is not relivant.
47656 * <script type="text/javascript">
47659 // as we use this in bootstrap.
47660 Roo.namespace('Roo.form');
47662 * @class Roo.form.Action
47663 * Internal Class used to handle form actions
47665 * @param {Roo.form.BasicForm} el The form element or its id
47666 * @param {Object} config Configuration options
47671 // define the action interface
47672 Roo.form.Action = function(form, options){
47674 this.options = options || {};
47677 * Client Validation Failed
47680 Roo.form.Action.CLIENT_INVALID = 'client';
47682 * Server Validation Failed
47685 Roo.form.Action.SERVER_INVALID = 'server';
47687 * Connect to Server Failed
47690 Roo.form.Action.CONNECT_FAILURE = 'connect';
47692 * Reading Data from Server Failed
47695 Roo.form.Action.LOAD_FAILURE = 'load';
47697 Roo.form.Action.prototype = {
47699 failureType : undefined,
47700 response : undefined,
47701 result : undefined,
47703 // interface method
47704 run : function(options){
47708 // interface method
47709 success : function(response){
47713 // interface method
47714 handleResponse : function(response){
47718 // default connection failure
47719 failure : function(response){
47721 this.response = response;
47722 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47723 this.form.afterAction(this, false);
47726 processResponse : function(response){
47727 this.response = response;
47728 if(!response.responseText){
47731 this.result = this.handleResponse(response);
47732 return this.result;
47735 // utility functions used internally
47736 getUrl : function(appendParams){
47737 var url = this.options.url || this.form.url || this.form.el.dom.action;
47739 var p = this.getParams();
47741 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47747 getMethod : function(){
47748 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47751 getParams : function(){
47752 var bp = this.form.baseParams;
47753 var p = this.options.params;
47755 if(typeof p == "object"){
47756 p = Roo.urlEncode(Roo.applyIf(p, bp));
47757 }else if(typeof p == 'string' && bp){
47758 p += '&' + Roo.urlEncode(bp);
47761 p = Roo.urlEncode(bp);
47766 createCallback : function(){
47768 success: this.success,
47769 failure: this.failure,
47771 timeout: (this.form.timeout*1000),
47772 upload: this.form.fileUpload ? this.success : undefined
47777 Roo.form.Action.Submit = function(form, options){
47778 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47781 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47784 haveProgress : false,
47785 uploadComplete : false,
47787 // uploadProgress indicator.
47788 uploadProgress : function()
47790 if (!this.form.progressUrl) {
47794 if (!this.haveProgress) {
47795 Roo.MessageBox.progress("Uploading", "Uploading");
47797 if (this.uploadComplete) {
47798 Roo.MessageBox.hide();
47802 this.haveProgress = true;
47804 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47806 var c = new Roo.data.Connection();
47808 url : this.form.progressUrl,
47813 success : function(req){
47814 //console.log(data);
47818 rdata = Roo.decode(req.responseText)
47820 Roo.log("Invalid data from server..");
47824 if (!rdata || !rdata.success) {
47826 Roo.MessageBox.alert(Roo.encode(rdata));
47829 var data = rdata.data;
47831 if (this.uploadComplete) {
47832 Roo.MessageBox.hide();
47837 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47838 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47841 this.uploadProgress.defer(2000,this);
47844 failure: function(data) {
47845 Roo.log('progress url failed ');
47856 // run get Values on the form, so it syncs any secondary forms.
47857 this.form.getValues();
47859 var o = this.options;
47860 var method = this.getMethod();
47861 var isPost = method == 'POST';
47862 if(o.clientValidation === false || this.form.isValid()){
47864 if (this.form.progressUrl) {
47865 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47866 (new Date() * 1) + '' + Math.random());
47871 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47872 form:this.form.el.dom,
47873 url:this.getUrl(!isPost),
47875 params:isPost ? this.getParams() : null,
47876 isUpload: this.form.fileUpload
47879 this.uploadProgress();
47881 }else if (o.clientValidation !== false){ // client validation failed
47882 this.failureType = Roo.form.Action.CLIENT_INVALID;
47883 this.form.afterAction(this, false);
47887 success : function(response)
47889 this.uploadComplete= true;
47890 if (this.haveProgress) {
47891 Roo.MessageBox.hide();
47895 var result = this.processResponse(response);
47896 if(result === true || result.success){
47897 this.form.afterAction(this, true);
47901 this.form.markInvalid(result.errors);
47902 this.failureType = Roo.form.Action.SERVER_INVALID;
47904 this.form.afterAction(this, false);
47906 failure : function(response)
47908 this.uploadComplete= true;
47909 if (this.haveProgress) {
47910 Roo.MessageBox.hide();
47913 this.response = response;
47914 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47915 this.form.afterAction(this, false);
47918 handleResponse : function(response){
47919 if(this.form.errorReader){
47920 var rs = this.form.errorReader.read(response);
47923 for(var i = 0, len = rs.records.length; i < len; i++) {
47924 var r = rs.records[i];
47925 errors[i] = r.data;
47928 if(errors.length < 1){
47932 success : rs.success,
47938 ret = Roo.decode(response.responseText);
47942 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47952 Roo.form.Action.Load = function(form, options){
47953 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47954 this.reader = this.form.reader;
47957 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47962 Roo.Ajax.request(Roo.apply(
47963 this.createCallback(), {
47964 method:this.getMethod(),
47965 url:this.getUrl(false),
47966 params:this.getParams()
47970 success : function(response){
47972 var result = this.processResponse(response);
47973 if(result === true || !result.success || !result.data){
47974 this.failureType = Roo.form.Action.LOAD_FAILURE;
47975 this.form.afterAction(this, false);
47978 this.form.clearInvalid();
47979 this.form.setValues(result.data);
47980 this.form.afterAction(this, true);
47983 handleResponse : function(response){
47984 if(this.form.reader){
47985 var rs = this.form.reader.read(response);
47986 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47988 success : rs.success,
47992 return Roo.decode(response.responseText);
47996 Roo.form.Action.ACTION_TYPES = {
47997 'load' : Roo.form.Action.Load,
47998 'submit' : Roo.form.Action.Submit
48001 * Ext JS Library 1.1.1
48002 * Copyright(c) 2006-2007, Ext JS, LLC.
48004 * Originally Released Under LGPL - original licence link has changed is not relivant.
48007 * <script type="text/javascript">
48011 * @class Roo.form.Layout
48012 * @extends Roo.Component
48013 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48015 * @param {Object} config Configuration options
48017 Roo.form.Layout = function(config){
48019 if (config.items) {
48020 xitems = config.items;
48021 delete config.items;
48023 Roo.form.Layout.superclass.constructor.call(this, config);
48025 Roo.each(xitems, this.addxtype, this);
48029 Roo.extend(Roo.form.Layout, Roo.Component, {
48031 * @cfg {String/Object} autoCreate
48032 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48035 * @cfg {String/Object/Function} style
48036 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48037 * a function which returns such a specification.
48040 * @cfg {String} labelAlign
48041 * Valid values are "left," "top" and "right" (defaults to "left")
48044 * @cfg {Number} labelWidth
48045 * Fixed width in pixels of all field labels (defaults to undefined)
48048 * @cfg {Boolean} clear
48049 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48053 * @cfg {String} labelSeparator
48054 * The separator to use after field labels (defaults to ':')
48056 labelSeparator : ':',
48058 * @cfg {Boolean} hideLabels
48059 * True to suppress the display of field labels in this layout (defaults to false)
48061 hideLabels : false,
48064 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48069 onRender : function(ct, position){
48070 if(this.el){ // from markup
48071 this.el = Roo.get(this.el);
48072 }else { // generate
48073 var cfg = this.getAutoCreate();
48074 this.el = ct.createChild(cfg, position);
48077 this.el.applyStyles(this.style);
48079 if(this.labelAlign){
48080 this.el.addClass('x-form-label-'+this.labelAlign);
48082 if(this.hideLabels){
48083 this.labelStyle = "display:none";
48084 this.elementStyle = "padding-left:0;";
48086 if(typeof this.labelWidth == 'number'){
48087 this.labelStyle = "width:"+this.labelWidth+"px;";
48088 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48090 if(this.labelAlign == 'top'){
48091 this.labelStyle = "width:auto;";
48092 this.elementStyle = "padding-left:0;";
48095 var stack = this.stack;
48096 var slen = stack.length;
48098 if(!this.fieldTpl){
48099 var t = new Roo.Template(
48100 '<div class="x-form-item {5}">',
48101 '<label for="{0}" style="{2}">{1}{4}</label>',
48102 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48104 '</div><div class="x-form-clear-left"></div>'
48106 t.disableFormats = true;
48108 Roo.form.Layout.prototype.fieldTpl = t;
48110 for(var i = 0; i < slen; i++) {
48111 if(stack[i].isFormField){
48112 this.renderField(stack[i]);
48114 this.renderComponent(stack[i]);
48119 this.el.createChild({cls:'x-form-clear'});
48124 renderField : function(f){
48125 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48128 f.labelStyle||this.labelStyle||'', //2
48129 this.elementStyle||'', //3
48130 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48131 f.itemCls||this.itemCls||'' //5
48132 ], true).getPrevSibling());
48136 renderComponent : function(c){
48137 c.render(c.isLayout ? this.el : this.el.createChild());
48140 * Adds a object form elements (using the xtype property as the factory method.)
48141 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48142 * @param {Object} config
48144 addxtype : function(o)
48146 // create the lement.
48147 o.form = this.form;
48148 var fe = Roo.factory(o, Roo.form);
48149 this.form.allItems.push(fe);
48150 this.stack.push(fe);
48152 if (fe.isFormField) {
48153 this.form.items.add(fe);
48161 * @class Roo.form.Column
48162 * @extends Roo.form.Layout
48163 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48165 * @param {Object} config Configuration options
48167 Roo.form.Column = function(config){
48168 Roo.form.Column.superclass.constructor.call(this, config);
48171 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48173 * @cfg {Number/String} width
48174 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48177 * @cfg {String/Object} autoCreate
48178 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48182 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48185 onRender : function(ct, position){
48186 Roo.form.Column.superclass.onRender.call(this, ct, position);
48188 this.el.setWidth(this.width);
48195 * @class Roo.form.Row
48196 * @extends Roo.form.Layout
48197 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48199 * @param {Object} config Configuration options
48203 Roo.form.Row = function(config){
48204 Roo.form.Row.superclass.constructor.call(this, config);
48207 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48209 * @cfg {Number/String} width
48210 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48213 * @cfg {Number/String} height
48214 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48216 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48220 onRender : function(ct, position){
48221 //console.log('row render');
48223 var t = new Roo.Template(
48224 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48225 '<label for="{0}" style="{2}">{1}{4}</label>',
48226 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48230 t.disableFormats = true;
48232 Roo.form.Layout.prototype.rowTpl = t;
48234 this.fieldTpl = this.rowTpl;
48236 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48237 var labelWidth = 100;
48239 if ((this.labelAlign != 'top')) {
48240 if (typeof this.labelWidth == 'number') {
48241 labelWidth = this.labelWidth
48243 this.padWidth = 20 + labelWidth;
48247 Roo.form.Column.superclass.onRender.call(this, ct, position);
48249 this.el.setWidth(this.width);
48252 this.el.setHeight(this.height);
48257 renderField : function(f){
48258 f.fieldEl = this.fieldTpl.append(this.el, [
48259 f.id, f.fieldLabel,
48260 f.labelStyle||this.labelStyle||'',
48261 this.elementStyle||'',
48262 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48263 f.itemCls||this.itemCls||'',
48264 f.width ? f.width + this.padWidth : 160 + this.padWidth
48271 * @class Roo.form.FieldSet
48272 * @extends Roo.form.Layout
48273 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48275 * @param {Object} config Configuration options
48277 Roo.form.FieldSet = function(config){
48278 Roo.form.FieldSet.superclass.constructor.call(this, config);
48281 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48283 * @cfg {String} legend
48284 * The text to display as the legend for the FieldSet (defaults to '')
48287 * @cfg {String/Object} autoCreate
48288 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48292 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48295 onRender : function(ct, position){
48296 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48298 this.setLegend(this.legend);
48303 setLegend : function(text){
48305 this.el.child('legend').update(text);
48310 * Ext JS Library 1.1.1
48311 * Copyright(c) 2006-2007, Ext JS, LLC.
48313 * Originally Released Under LGPL - original licence link has changed is not relivant.
48316 * <script type="text/javascript">
48319 * @class Roo.form.VTypes
48320 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48323 Roo.form.VTypes = function(){
48324 // closure these in so they are only created once.
48325 var alpha = /^[a-zA-Z_]+$/;
48326 var alphanum = /^[a-zA-Z0-9_]+$/;
48327 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48328 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48330 // All these messages and functions are configurable
48333 * The function used to validate email addresses
48334 * @param {String} value The email address
48336 'email' : function(v){
48337 return email.test(v);
48340 * The error text to display when the email validation function returns false
48343 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48345 * The keystroke filter mask to be applied on email input
48348 'emailMask' : /[a-z0-9_\.\-@]/i,
48351 * The function used to validate URLs
48352 * @param {String} value The URL
48354 'url' : function(v){
48355 return url.test(v);
48358 * The error text to display when the url validation function returns false
48361 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48364 * The function used to validate alpha values
48365 * @param {String} value The value
48367 'alpha' : function(v){
48368 return alpha.test(v);
48371 * The error text to display when the alpha validation function returns false
48374 'alphaText' : 'This field should only contain letters and _',
48376 * The keystroke filter mask to be applied on alpha input
48379 'alphaMask' : /[a-z_]/i,
48382 * The function used to validate alphanumeric values
48383 * @param {String} value The value
48385 'alphanum' : function(v){
48386 return alphanum.test(v);
48389 * The error text to display when the alphanumeric validation function returns false
48392 'alphanumText' : 'This field should only contain letters, numbers and _',
48394 * The keystroke filter mask to be applied on alphanumeric input
48397 'alphanumMask' : /[a-z0-9_]/i
48399 }();//<script type="text/javascript">
48402 * @class Roo.form.FCKeditor
48403 * @extends Roo.form.TextArea
48404 * Wrapper around the FCKEditor http://www.fckeditor.net
48406 * Creates a new FCKeditor
48407 * @param {Object} config Configuration options
48409 Roo.form.FCKeditor = function(config){
48410 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48413 * @event editorinit
48414 * Fired when the editor is initialized - you can add extra handlers here..
48415 * @param {FCKeditor} this
48416 * @param {Object} the FCK object.
48423 Roo.form.FCKeditor.editors = { };
48424 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48426 //defaultAutoCreate : {
48427 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48431 * @cfg {Object} fck options - see fck manual for details.
48436 * @cfg {Object} fck toolbar set (Basic or Default)
48438 toolbarSet : 'Basic',
48440 * @cfg {Object} fck BasePath
48442 basePath : '/fckeditor/',
48450 onRender : function(ct, position)
48453 this.defaultAutoCreate = {
48455 style:"width:300px;height:60px;",
48456 autocomplete: "new-password"
48459 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48462 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48463 if(this.preventScrollbars){
48464 this.el.setStyle("overflow", "hidden");
48466 this.el.setHeight(this.growMin);
48469 //console.log('onrender' + this.getId() );
48470 Roo.form.FCKeditor.editors[this.getId()] = this;
48473 this.replaceTextarea() ;
48477 getEditor : function() {
48478 return this.fckEditor;
48481 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48482 * @param {Mixed} value The value to set
48486 setValue : function(value)
48488 //console.log('setValue: ' + value);
48490 if(typeof(value) == 'undefined') { // not sure why this is happending...
48493 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48495 //if(!this.el || !this.getEditor()) {
48496 // this.value = value;
48497 //this.setValue.defer(100,this,[value]);
48501 if(!this.getEditor()) {
48505 this.getEditor().SetData(value);
48512 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48513 * @return {Mixed} value The field value
48515 getValue : function()
48518 if (this.frame && this.frame.dom.style.display == 'none') {
48519 return Roo.form.FCKeditor.superclass.getValue.call(this);
48522 if(!this.el || !this.getEditor()) {
48524 // this.getValue.defer(100,this);
48529 var value=this.getEditor().GetData();
48530 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48531 return Roo.form.FCKeditor.superclass.getValue.call(this);
48537 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48538 * @return {Mixed} value The field value
48540 getRawValue : function()
48542 if (this.frame && this.frame.dom.style.display == 'none') {
48543 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48546 if(!this.el || !this.getEditor()) {
48547 //this.getRawValue.defer(100,this);
48554 var value=this.getEditor().GetData();
48555 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48556 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48560 setSize : function(w,h) {
48564 //if (this.frame && this.frame.dom.style.display == 'none') {
48565 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48568 //if(!this.el || !this.getEditor()) {
48569 // this.setSize.defer(100,this, [w,h]);
48575 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48577 this.frame.dom.setAttribute('width', w);
48578 this.frame.dom.setAttribute('height', h);
48579 this.frame.setSize(w,h);
48583 toggleSourceEdit : function(value) {
48587 this.el.dom.style.display = value ? '' : 'none';
48588 this.frame.dom.style.display = value ? 'none' : '';
48593 focus: function(tag)
48595 if (this.frame.dom.style.display == 'none') {
48596 return Roo.form.FCKeditor.superclass.focus.call(this);
48598 if(!this.el || !this.getEditor()) {
48599 this.focus.defer(100,this, [tag]);
48606 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48607 this.getEditor().Focus();
48609 if (!this.getEditor().Selection.GetSelection()) {
48610 this.focus.defer(100,this, [tag]);
48615 var r = this.getEditor().EditorDocument.createRange();
48616 r.setStart(tgs[0],0);
48617 r.setEnd(tgs[0],0);
48618 this.getEditor().Selection.GetSelection().removeAllRanges();
48619 this.getEditor().Selection.GetSelection().addRange(r);
48620 this.getEditor().Focus();
48627 replaceTextarea : function()
48629 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48632 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48634 // We must check the elements firstly using the Id and then the name.
48635 var oTextarea = document.getElementById( this.getId() );
48637 var colElementsByName = document.getElementsByName( this.getId() ) ;
48639 oTextarea.style.display = 'none' ;
48641 if ( oTextarea.tabIndex ) {
48642 this.TabIndex = oTextarea.tabIndex ;
48645 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48646 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48647 this.frame = Roo.get(this.getId() + '___Frame')
48650 _getConfigHtml : function()
48654 for ( var o in this.fckconfig ) {
48655 sConfig += sConfig.length > 0 ? '&' : '';
48656 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48659 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48663 _getIFrameHtml : function()
48665 var sFile = 'fckeditor.html' ;
48666 /* no idea what this is about..
48669 if ( (/fcksource=true/i).test( window.top.location.search ) )
48670 sFile = 'fckeditor.original.html' ;
48675 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48676 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48679 var html = '<iframe id="' + this.getId() +
48680 '___Frame" src="' + sLink +
48681 '" width="' + this.width +
48682 '" height="' + this.height + '"' +
48683 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48684 ' frameborder="0" scrolling="no"></iframe>' ;
48689 _insertHtmlBefore : function( html, element )
48691 if ( element.insertAdjacentHTML ) {
48693 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48695 var oRange = document.createRange() ;
48696 oRange.setStartBefore( element ) ;
48697 var oFragment = oRange.createContextualFragment( html );
48698 element.parentNode.insertBefore( oFragment, element ) ;
48711 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48713 function FCKeditor_OnComplete(editorInstance){
48714 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48715 f.fckEditor = editorInstance;
48716 //console.log("loaded");
48717 f.fireEvent('editorinit', f, editorInstance);
48737 //<script type="text/javascript">
48739 * @class Roo.form.GridField
48740 * @extends Roo.form.Field
48741 * Embed a grid (or editable grid into a form)
48744 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48746 * xgrid.store = Roo.data.Store
48747 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48748 * xgrid.store.reader = Roo.data.JsonReader
48752 * Creates a new GridField
48753 * @param {Object} config Configuration options
48755 Roo.form.GridField = function(config){
48756 Roo.form.GridField.superclass.constructor.call(this, config);
48760 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48762 * @cfg {Number} width - used to restrict width of grid..
48766 * @cfg {Number} height - used to restrict height of grid..
48770 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48776 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48777 * {tag: "input", type: "checkbox", autocomplete: "off"})
48779 // defaultAutoCreate : { tag: 'div' },
48780 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48782 * @cfg {String} addTitle Text to include for adding a title.
48786 onResize : function(){
48787 Roo.form.Field.superclass.onResize.apply(this, arguments);
48790 initEvents : function(){
48791 // Roo.form.Checkbox.superclass.initEvents.call(this);
48792 // has no events...
48797 getResizeEl : function(){
48801 getPositionEl : function(){
48806 onRender : function(ct, position){
48808 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48809 var style = this.style;
48812 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48813 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48814 this.viewEl = this.wrap.createChild({ tag: 'div' });
48816 this.viewEl.applyStyles(style);
48819 this.viewEl.setWidth(this.width);
48822 this.viewEl.setHeight(this.height);
48824 //if(this.inputValue !== undefined){
48825 //this.setValue(this.value);
48828 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48831 this.grid.render();
48832 this.grid.getDataSource().on('remove', this.refreshValue, this);
48833 this.grid.getDataSource().on('update', this.refreshValue, this);
48834 this.grid.on('afteredit', this.refreshValue, this);
48840 * Sets the value of the item.
48841 * @param {String} either an object or a string..
48843 setValue : function(v){
48845 v = v || []; // empty set..
48846 // this does not seem smart - it really only affects memoryproxy grids..
48847 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48848 var ds = this.grid.getDataSource();
48849 // assumes a json reader..
48851 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48852 ds.loadData( data);
48854 // clear selection so it does not get stale.
48855 if (this.grid.sm) {
48856 this.grid.sm.clearSelections();
48859 Roo.form.GridField.superclass.setValue.call(this, v);
48860 this.refreshValue();
48861 // should load data in the grid really....
48865 refreshValue: function() {
48867 this.grid.getDataSource().each(function(r) {
48870 this.el.dom.value = Roo.encode(val);
48878 * Ext JS Library 1.1.1
48879 * Copyright(c) 2006-2007, Ext JS, LLC.
48881 * Originally Released Under LGPL - original licence link has changed is not relivant.
48884 * <script type="text/javascript">
48887 * @class Roo.form.DisplayField
48888 * @extends Roo.form.Field
48889 * A generic Field to display non-editable data.
48890 * @cfg {Boolean} closable (true|false) default false
48892 * Creates a new Display Field item.
48893 * @param {Object} config Configuration options
48895 Roo.form.DisplayField = function(config){
48896 Roo.form.DisplayField.superclass.constructor.call(this, config);
48901 * Fires after the click the close btn
48902 * @param {Roo.form.DisplayField} this
48908 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48909 inputType: 'hidden',
48915 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48917 focusClass : undefined,
48919 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48921 fieldClass: 'x-form-field',
48924 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48926 valueRenderer: undefined,
48930 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48931 * {tag: "input", type: "checkbox", autocomplete: "off"})
48934 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48938 onResize : function(){
48939 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48943 initEvents : function(){
48944 // Roo.form.Checkbox.superclass.initEvents.call(this);
48945 // has no events...
48948 this.closeEl.on('click', this.onClose, this);
48954 getResizeEl : function(){
48958 getPositionEl : function(){
48963 onRender : function(ct, position){
48965 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48966 //if(this.inputValue !== undefined){
48967 this.wrap = this.el.wrap();
48969 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48972 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48975 if (this.bodyStyle) {
48976 this.viewEl.applyStyles(this.bodyStyle);
48978 //this.viewEl.setStyle('padding', '2px');
48980 this.setValue(this.value);
48985 initValue : Roo.emptyFn,
48990 onClick : function(){
48995 * Sets the checked state of the checkbox.
48996 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48998 setValue : function(v){
49000 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49001 // this might be called before we have a dom element..
49002 if (!this.viewEl) {
49005 this.viewEl.dom.innerHTML = html;
49006 Roo.form.DisplayField.superclass.setValue.call(this, v);
49010 onClose : function(e)
49012 e.preventDefault();
49014 this.fireEvent('close', this);
49023 * @class Roo.form.DayPicker
49024 * @extends Roo.form.Field
49025 * A Day picker show [M] [T] [W] ....
49027 * Creates a new Day Picker
49028 * @param {Object} config Configuration options
49030 Roo.form.DayPicker= function(config){
49031 Roo.form.DayPicker.superclass.constructor.call(this, config);
49035 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49037 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49039 focusClass : undefined,
49041 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49043 fieldClass: "x-form-field",
49046 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49047 * {tag: "input", type: "checkbox", autocomplete: "off"})
49049 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49052 actionMode : 'viewEl',
49056 inputType : 'hidden',
49059 inputElement: false, // real input element?
49060 basedOn: false, // ????
49062 isFormField: true, // not sure where this is needed!!!!
49064 onResize : function(){
49065 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49066 if(!this.boxLabel){
49067 this.el.alignTo(this.wrap, 'c-c');
49071 initEvents : function(){
49072 Roo.form.Checkbox.superclass.initEvents.call(this);
49073 this.el.on("click", this.onClick, this);
49074 this.el.on("change", this.onClick, this);
49078 getResizeEl : function(){
49082 getPositionEl : function(){
49088 onRender : function(ct, position){
49089 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49091 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49093 var r1 = '<table><tr>';
49094 var r2 = '<tr class="x-form-daypick-icons">';
49095 for (var i=0; i < 7; i++) {
49096 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49097 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49100 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49101 viewEl.select('img').on('click', this.onClick, this);
49102 this.viewEl = viewEl;
49105 // this will not work on Chrome!!!
49106 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49107 this.el.on('propertychange', this.setFromHidden, this); //ie
49115 initValue : Roo.emptyFn,
49118 * Returns the checked state of the checkbox.
49119 * @return {Boolean} True if checked, else false
49121 getValue : function(){
49122 return this.el.dom.value;
49127 onClick : function(e){
49128 //this.setChecked(!this.checked);
49129 Roo.get(e.target).toggleClass('x-menu-item-checked');
49130 this.refreshValue();
49131 //if(this.el.dom.checked != this.checked){
49132 // this.setValue(this.el.dom.checked);
49137 refreshValue : function()
49140 this.viewEl.select('img',true).each(function(e,i,n) {
49141 val += e.is(".x-menu-item-checked") ? String(n) : '';
49143 this.setValue(val, true);
49147 * Sets the checked state of the checkbox.
49148 * On is always based on a string comparison between inputValue and the param.
49149 * @param {Boolean/String} value - the value to set
49150 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49152 setValue : function(v,suppressEvent){
49153 if (!this.el.dom) {
49156 var old = this.el.dom.value ;
49157 this.el.dom.value = v;
49158 if (suppressEvent) {
49162 // update display..
49163 this.viewEl.select('img',true).each(function(e,i,n) {
49165 var on = e.is(".x-menu-item-checked");
49166 var newv = v.indexOf(String(n)) > -1;
49168 e.toggleClass('x-menu-item-checked');
49174 this.fireEvent('change', this, v, old);
49179 // handle setting of hidden value by some other method!!?!?
49180 setFromHidden: function()
49185 //console.log("SET FROM HIDDEN");
49186 //alert('setFrom hidden');
49187 this.setValue(this.el.dom.value);
49190 onDestroy : function()
49193 Roo.get(this.viewEl).remove();
49196 Roo.form.DayPicker.superclass.onDestroy.call(this);
49200 * RooJS Library 1.1.1
49201 * Copyright(c) 2008-2011 Alan Knowles
49208 * @class Roo.form.ComboCheck
49209 * @extends Roo.form.ComboBox
49210 * A combobox for multiple select items.
49212 * FIXME - could do with a reset button..
49215 * Create a new ComboCheck
49216 * @param {Object} config Configuration options
49218 Roo.form.ComboCheck = function(config){
49219 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49220 // should verify some data...
49222 // hiddenName = required..
49223 // displayField = required
49224 // valudField == required
49225 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49227 Roo.each(req, function(e) {
49228 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49229 throw "Roo.form.ComboCheck : missing value for: " + e;
49236 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49241 selectedClass: 'x-menu-item-checked',
49244 onRender : function(ct, position){
49250 var cls = 'x-combo-list';
49253 this.tpl = new Roo.Template({
49254 html : '<div class="'+cls+'-item x-menu-check-item">' +
49255 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49256 '<span>{' + this.displayField + '}</span>' +
49263 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49264 this.view.singleSelect = false;
49265 this.view.multiSelect = true;
49266 this.view.toggleSelect = true;
49267 this.pageTb.add(new Roo.Toolbar.Fill(), {
49270 handler: function()
49277 onViewOver : function(e, t){
49283 onViewClick : function(doFocus,index){
49287 select: function () {
49288 //Roo.log("SELECT CALLED");
49291 selectByValue : function(xv, scrollIntoView){
49292 var ar = this.getValueArray();
49295 Roo.each(ar, function(v) {
49296 if(v === undefined || v === null){
49299 var r = this.findRecord(this.valueField, v);
49301 sels.push(this.store.indexOf(r))
49305 this.view.select(sels);
49311 onSelect : function(record, index){
49312 // Roo.log("onselect Called");
49313 // this is only called by the clear button now..
49314 this.view.clearSelections();
49315 this.setValue('[]');
49316 if (this.value != this.valueBefore) {
49317 this.fireEvent('change', this, this.value, this.valueBefore);
49318 this.valueBefore = this.value;
49321 getValueArray : function()
49326 //Roo.log(this.value);
49327 if (typeof(this.value) == 'undefined') {
49330 var ar = Roo.decode(this.value);
49331 return ar instanceof Array ? ar : []; //?? valid?
49334 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49339 expand : function ()
49342 Roo.form.ComboCheck.superclass.expand.call(this);
49343 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49344 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49349 collapse : function(){
49350 Roo.form.ComboCheck.superclass.collapse.call(this);
49351 var sl = this.view.getSelectedIndexes();
49352 var st = this.store;
49356 Roo.each(sl, function(i) {
49358 nv.push(r.get(this.valueField));
49360 this.setValue(Roo.encode(nv));
49361 if (this.value != this.valueBefore) {
49363 this.fireEvent('change', this, this.value, this.valueBefore);
49364 this.valueBefore = this.value;
49369 setValue : function(v){
49373 var vals = this.getValueArray();
49375 Roo.each(vals, function(k) {
49376 var r = this.findRecord(this.valueField, k);
49378 tv.push(r.data[this.displayField]);
49379 }else if(this.valueNotFoundText !== undefined){
49380 tv.push( this.valueNotFoundText );
49385 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49386 this.hiddenField.value = v;
49392 * Ext JS Library 1.1.1
49393 * Copyright(c) 2006-2007, Ext JS, LLC.
49395 * Originally Released Under LGPL - original licence link has changed is not relivant.
49398 * <script type="text/javascript">
49402 * @class Roo.form.Signature
49403 * @extends Roo.form.Field
49407 * @param {Object} config Configuration options
49410 Roo.form.Signature = function(config){
49411 Roo.form.Signature.superclass.constructor.call(this, config);
49413 this.addEvents({// not in used??
49416 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49417 * @param {Roo.form.Signature} combo This combo box
49422 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49423 * @param {Roo.form.ComboBox} combo This combo box
49424 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49430 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49432 * @cfg {Object} labels Label to use when rendering a form.
49436 * confirm : "Confirm"
49441 confirm : "Confirm"
49444 * @cfg {Number} width The signature panel width (defaults to 300)
49448 * @cfg {Number} height The signature panel height (defaults to 100)
49452 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49454 allowBlank : false,
49457 // {Object} signPanel The signature SVG panel element (defaults to {})
49459 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49460 isMouseDown : false,
49461 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49462 isConfirmed : false,
49463 // {String} signatureTmp SVG mapping string (defaults to empty string)
49467 defaultAutoCreate : { // modified by initCompnoent..
49473 onRender : function(ct, position){
49475 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49477 this.wrap = this.el.wrap({
49478 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49481 this.createToolbar(this);
49482 this.signPanel = this.wrap.createChild({
49484 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49488 this.svgID = Roo.id();
49489 this.svgEl = this.signPanel.createChild({
49490 xmlns : 'http://www.w3.org/2000/svg',
49492 id : this.svgID + "-svg",
49494 height: this.height,
49495 viewBox: '0 0 '+this.width+' '+this.height,
49499 id: this.svgID + "-svg-r",
49501 height: this.height,
49506 id: this.svgID + "-svg-l",
49508 y1: (this.height*0.8), // start set the line in 80% of height
49509 x2: this.width, // end
49510 y2: (this.height*0.8), // end set the line in 80% of height
49512 'stroke-width': "1",
49513 'stroke-dasharray': "3",
49514 'shape-rendering': "crispEdges",
49515 'pointer-events': "none"
49519 id: this.svgID + "-svg-p",
49521 'stroke-width': "3",
49523 'pointer-events': 'none'
49528 this.svgBox = this.svgEl.dom.getScreenCTM();
49530 createSVG : function(){
49531 var svg = this.signPanel;
49532 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49535 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49536 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49537 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49538 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49539 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49540 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49541 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49544 isTouchEvent : function(e){
49545 return e.type.match(/^touch/);
49547 getCoords : function (e) {
49548 var pt = this.svgEl.dom.createSVGPoint();
49551 if (this.isTouchEvent(e)) {
49552 pt.x = e.targetTouches[0].clientX;
49553 pt.y = e.targetTouches[0].clientY;
49555 var a = this.svgEl.dom.getScreenCTM();
49556 var b = a.inverse();
49557 var mx = pt.matrixTransform(b);
49558 return mx.x + ',' + mx.y;
49560 //mouse event headler
49561 down : function (e) {
49562 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49563 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49565 this.isMouseDown = true;
49567 e.preventDefault();
49569 move : function (e) {
49570 if (this.isMouseDown) {
49571 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49572 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49575 e.preventDefault();
49577 up : function (e) {
49578 this.isMouseDown = false;
49579 var sp = this.signatureTmp.split(' ');
49582 if(!sp[sp.length-2].match(/^L/)){
49586 this.signatureTmp = sp.join(" ");
49589 if(this.getValue() != this.signatureTmp){
49590 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49591 this.isConfirmed = false;
49593 e.preventDefault();
49597 * Protected method that will not generally be called directly. It
49598 * is called when the editor creates its toolbar. Override this method if you need to
49599 * add custom toolbar buttons.
49600 * @param {HtmlEditor} editor
49602 createToolbar : function(editor){
49603 function btn(id, toggle, handler){
49604 var xid = fid + '-'+ id ;
49608 cls : 'x-btn-icon x-edit-'+id,
49609 enableToggle:toggle !== false,
49610 scope: editor, // was editor...
49611 handler:handler||editor.relayBtnCmd,
49612 clickEvent:'mousedown',
49613 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49619 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49623 cls : ' x-signature-btn x-signature-'+id,
49624 scope: editor, // was editor...
49625 handler: this.reset,
49626 clickEvent:'mousedown',
49627 text: this.labels.clear
49634 cls : ' x-signature-btn x-signature-'+id,
49635 scope: editor, // was editor...
49636 handler: this.confirmHandler,
49637 clickEvent:'mousedown',
49638 text: this.labels.confirm
49645 * when user is clicked confirm then show this image.....
49647 * @return {String} Image Data URI
49649 getImageDataURI : function(){
49650 var svg = this.svgEl.dom.parentNode.innerHTML;
49651 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49656 * @return {Boolean} this.isConfirmed
49658 getConfirmed : function(){
49659 return this.isConfirmed;
49663 * @return {Number} this.width
49665 getWidth : function(){
49670 * @return {Number} this.height
49672 getHeight : function(){
49673 return this.height;
49676 getSignature : function(){
49677 return this.signatureTmp;
49680 reset : function(){
49681 this.signatureTmp = '';
49682 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49683 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49684 this.isConfirmed = false;
49685 Roo.form.Signature.superclass.reset.call(this);
49687 setSignature : function(s){
49688 this.signatureTmp = s;
49689 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49690 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49692 this.isConfirmed = false;
49693 Roo.form.Signature.superclass.reset.call(this);
49696 // Roo.log(this.signPanel.dom.contentWindow.up())
49699 setConfirmed : function(){
49703 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49706 confirmHandler : function(){
49707 if(!this.getSignature()){
49711 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49712 this.setValue(this.getSignature());
49713 this.isConfirmed = true;
49715 this.fireEvent('confirm', this);
49718 // Subclasses should provide the validation implementation by overriding this
49719 validateValue : function(value){
49720 if(this.allowBlank){
49724 if(this.isConfirmed){
49731 * Ext JS Library 1.1.1
49732 * Copyright(c) 2006-2007, Ext JS, LLC.
49734 * Originally Released Under LGPL - original licence link has changed is not relivant.
49737 * <script type="text/javascript">
49742 * @class Roo.form.ComboBox
49743 * @extends Roo.form.TriggerField
49744 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49746 * Create a new ComboBox.
49747 * @param {Object} config Configuration options
49749 Roo.form.Select = function(config){
49750 Roo.form.Select.superclass.constructor.call(this, config);
49754 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49756 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49759 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49760 * rendering into an Roo.Editor, defaults to false)
49763 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49764 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49767 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49770 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49771 * the dropdown list (defaults to undefined, with no header element)
49775 * @cfg {String/Roo.Template} tpl The template to use to render the output
49779 defaultAutoCreate : {tag: "select" },
49781 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49783 listWidth: undefined,
49785 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49786 * mode = 'remote' or 'text' if mode = 'local')
49788 displayField: undefined,
49790 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49791 * mode = 'remote' or 'value' if mode = 'local').
49792 * Note: use of a valueField requires the user make a selection
49793 * in order for a value to be mapped.
49795 valueField: undefined,
49799 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49800 * field's data value (defaults to the underlying DOM element's name)
49802 hiddenName: undefined,
49804 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49808 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49810 selectedClass: 'x-combo-selected',
49812 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49813 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49814 * which displays a downward arrow icon).
49816 triggerClass : 'x-form-arrow-trigger',
49818 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49822 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49823 * anchor positions (defaults to 'tl-bl')
49825 listAlign: 'tl-bl?',
49827 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49831 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49832 * query specified by the allQuery config option (defaults to 'query')
49834 triggerAction: 'query',
49836 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49837 * (defaults to 4, does not apply if editable = false)
49841 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49842 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49846 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49847 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49851 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49852 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49856 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49857 * when editable = true (defaults to false)
49859 selectOnFocus:false,
49861 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49863 queryParam: 'query',
49865 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49866 * when mode = 'remote' (defaults to 'Loading...')
49868 loadingText: 'Loading...',
49870 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49874 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49878 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49879 * traditional select (defaults to true)
49883 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49887 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49891 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49892 * listWidth has a higher value)
49896 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49897 * allow the user to set arbitrary text into the field (defaults to false)
49899 forceSelection:false,
49901 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49902 * if typeAhead = true (defaults to 250)
49904 typeAheadDelay : 250,
49906 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49907 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49909 valueNotFoundText : undefined,
49912 * @cfg {String} defaultValue The value displayed after loading the store.
49917 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49919 blockFocus : false,
49922 * @cfg {Boolean} disableClear Disable showing of clear button.
49924 disableClear : false,
49926 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49928 alwaysQuery : false,
49934 // element that contains real text value.. (when hidden is used..)
49937 onRender : function(ct, position){
49938 Roo.form.Field.prototype.onRender.call(this, ct, position);
49941 this.store.on('beforeload', this.onBeforeLoad, this);
49942 this.store.on('load', this.onLoad, this);
49943 this.store.on('loadexception', this.onLoadException, this);
49944 this.store.load({});
49952 initEvents : function(){
49953 //Roo.form.ComboBox.superclass.initEvents.call(this);
49957 onDestroy : function(){
49960 this.store.un('beforeload', this.onBeforeLoad, this);
49961 this.store.un('load', this.onLoad, this);
49962 this.store.un('loadexception', this.onLoadException, this);
49964 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49968 fireKey : function(e){
49969 if(e.isNavKeyPress() && !this.list.isVisible()){
49970 this.fireEvent("specialkey", this, e);
49975 onResize: function(w, h){
49983 * Allow or prevent the user from directly editing the field text. If false is passed,
49984 * the user will only be able to select from the items defined in the dropdown list. This method
49985 * is the runtime equivalent of setting the 'editable' config option at config time.
49986 * @param {Boolean} value True to allow the user to directly edit the field text
49988 setEditable : function(value){
49993 onBeforeLoad : function(){
49995 Roo.log("Select before load");
49998 this.innerList.update(this.loadingText ?
49999 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50000 //this.restrictHeight();
50001 this.selectedIndex = -1;
50005 onLoad : function(){
50008 var dom = this.el.dom;
50009 dom.innerHTML = '';
50010 var od = dom.ownerDocument;
50012 if (this.emptyText) {
50013 var op = od.createElement('option');
50014 op.setAttribute('value', '');
50015 op.innerHTML = String.format('{0}', this.emptyText);
50016 dom.appendChild(op);
50018 if(this.store.getCount() > 0){
50020 var vf = this.valueField;
50021 var df = this.displayField;
50022 this.store.data.each(function(r) {
50023 // which colmsn to use... testing - cdoe / title..
50024 var op = od.createElement('option');
50025 op.setAttribute('value', r.data[vf]);
50026 op.innerHTML = String.format('{0}', r.data[df]);
50027 dom.appendChild(op);
50029 if (typeof(this.defaultValue != 'undefined')) {
50030 this.setValue(this.defaultValue);
50035 //this.onEmptyResults();
50040 onLoadException : function()
50042 dom.innerHTML = '';
50044 Roo.log("Select on load exception");
50048 Roo.log(this.store.reader.jsonData);
50049 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50050 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50056 onTypeAhead : function(){
50061 onSelect : function(record, index){
50062 Roo.log('on select?');
50064 if(this.fireEvent('beforeselect', this, record, index) !== false){
50065 this.setFromData(index > -1 ? record.data : false);
50067 this.fireEvent('select', this, record, index);
50072 * Returns the currently selected field value or empty string if no value is set.
50073 * @return {String} value The selected value
50075 getValue : function(){
50076 var dom = this.el.dom;
50077 this.value = dom.options[dom.selectedIndex].value;
50083 * Clears any text/value currently set in the field
50085 clearValue : function(){
50087 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50092 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50093 * will be displayed in the field. If the value does not match the data value of an existing item,
50094 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50095 * Otherwise the field will be blank (although the value will still be set).
50096 * @param {String} value The value to match
50098 setValue : function(v){
50099 var d = this.el.dom;
50100 for (var i =0; i < d.options.length;i++) {
50101 if (v == d.options[i].value) {
50102 d.selectedIndex = i;
50110 * @property {Object} the last set data for the element
50115 * Sets the value of the field based on a object which is related to the record format for the store.
50116 * @param {Object} value the value to set as. or false on reset?
50118 setFromData : function(o){
50119 Roo.log('setfrom data?');
50125 reset : function(){
50129 findRecord : function(prop, value){
50134 if(this.store.getCount() > 0){
50135 this.store.each(function(r){
50136 if(r.data[prop] == value){
50146 getName: function()
50148 // returns hidden if it's set..
50149 if (!this.rendered) {return ''};
50150 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50158 onEmptyResults : function(){
50159 Roo.log('empty results');
50164 * Returns true if the dropdown list is expanded, else false.
50166 isExpanded : function(){
50171 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50172 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50173 * @param {String} value The data value of the item to select
50174 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50175 * selected item if it is not currently in view (defaults to true)
50176 * @return {Boolean} True if the value matched an item in the list, else false
50178 selectByValue : function(v, scrollIntoView){
50179 Roo.log('select By Value');
50182 if(v !== undefined && v !== null){
50183 var r = this.findRecord(this.valueField || this.displayField, v);
50185 this.select(this.store.indexOf(r), scrollIntoView);
50193 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50194 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50195 * @param {Number} index The zero-based index of the list item to select
50196 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50197 * selected item if it is not currently in view (defaults to true)
50199 select : function(index, scrollIntoView){
50200 Roo.log('select ');
50203 this.selectedIndex = index;
50204 this.view.select(index);
50205 if(scrollIntoView !== false){
50206 var el = this.view.getNode(index);
50208 this.innerList.scrollChildIntoView(el, false);
50216 validateBlur : function(){
50223 initQuery : function(){
50224 this.doQuery(this.getRawValue());
50228 doForce : function(){
50229 if(this.el.dom.value.length > 0){
50230 this.el.dom.value =
50231 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50237 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50238 * query allowing the query action to be canceled if needed.
50239 * @param {String} query The SQL query to execute
50240 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50241 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50242 * saved in the current store (defaults to false)
50244 doQuery : function(q, forceAll){
50246 Roo.log('doQuery?');
50247 if(q === undefined || q === null){
50252 forceAll: forceAll,
50256 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50260 forceAll = qe.forceAll;
50261 if(forceAll === true || (q.length >= this.minChars)){
50262 if(this.lastQuery != q || this.alwaysQuery){
50263 this.lastQuery = q;
50264 if(this.mode == 'local'){
50265 this.selectedIndex = -1;
50267 this.store.clearFilter();
50269 this.store.filter(this.displayField, q);
50273 this.store.baseParams[this.queryParam] = q;
50275 params: this.getParams(q)
50280 this.selectedIndex = -1;
50287 getParams : function(q){
50289 //p[this.queryParam] = q;
50292 p.limit = this.pageSize;
50298 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50300 collapse : function(){
50305 collapseIf : function(e){
50310 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50312 expand : function(){
50320 * @cfg {Boolean} grow
50324 * @cfg {Number} growMin
50328 * @cfg {Number} growMax
50336 setWidth : function()
50340 getResizeEl : function(){
50343 });//<script type="text/javasscript">
50347 * @class Roo.DDView
50348 * A DnD enabled version of Roo.View.
50349 * @param {Element/String} container The Element in which to create the View.
50350 * @param {String} tpl The template string used to create the markup for each element of the View
50351 * @param {Object} config The configuration properties. These include all the config options of
50352 * {@link Roo.View} plus some specific to this class.<br>
50354 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50355 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50357 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50358 .x-view-drag-insert-above {
50359 border-top:1px dotted #3366cc;
50361 .x-view-drag-insert-below {
50362 border-bottom:1px dotted #3366cc;
50368 Roo.DDView = function(container, tpl, config) {
50369 Roo.DDView.superclass.constructor.apply(this, arguments);
50370 this.getEl().setStyle("outline", "0px none");
50371 this.getEl().unselectable();
50372 if (this.dragGroup) {
50373 this.setDraggable(this.dragGroup.split(","));
50375 if (this.dropGroup) {
50376 this.setDroppable(this.dropGroup.split(","));
50378 if (this.deletable) {
50379 this.setDeletable();
50381 this.isDirtyFlag = false;
50387 Roo.extend(Roo.DDView, Roo.View, {
50388 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50389 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50390 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50391 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50395 reset: Roo.emptyFn,
50397 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50399 validate: function() {
50403 destroy: function() {
50404 this.purgeListeners();
50405 this.getEl.removeAllListeners();
50406 this.getEl().remove();
50407 if (this.dragZone) {
50408 if (this.dragZone.destroy) {
50409 this.dragZone.destroy();
50412 if (this.dropZone) {
50413 if (this.dropZone.destroy) {
50414 this.dropZone.destroy();
50419 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50420 getName: function() {
50424 /** Loads the View from a JSON string representing the Records to put into the Store. */
50425 setValue: function(v) {
50427 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50430 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50431 this.store.proxy = new Roo.data.MemoryProxy(data);
50435 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50436 getValue: function() {
50438 this.store.each(function(rec) {
50439 result += rec.id + ',';
50441 return result.substr(0, result.length - 1) + ')';
50444 getIds: function() {
50445 var i = 0, result = new Array(this.store.getCount());
50446 this.store.each(function(rec) {
50447 result[i++] = rec.id;
50452 isDirty: function() {
50453 return this.isDirtyFlag;
50457 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50458 * whole Element becomes the target, and this causes the drop gesture to append.
50460 getTargetFromEvent : function(e) {
50461 var target = e.getTarget();
50462 while ((target !== null) && (target.parentNode != this.el.dom)) {
50463 target = target.parentNode;
50466 target = this.el.dom.lastChild || this.el.dom;
50472 * Create the drag data which consists of an object which has the property "ddel" as
50473 * the drag proxy element.
50475 getDragData : function(e) {
50476 var target = this.findItemFromChild(e.getTarget());
50478 this.handleSelection(e);
50479 var selNodes = this.getSelectedNodes();
50482 copy: this.copy || (this.allowCopy && e.ctrlKey),
50486 var selectedIndices = this.getSelectedIndexes();
50487 for (var i = 0; i < selectedIndices.length; i++) {
50488 dragData.records.push(this.store.getAt(selectedIndices[i]));
50490 if (selNodes.length == 1) {
50491 dragData.ddel = target.cloneNode(true); // the div element
50493 var div = document.createElement('div'); // create the multi element drag "ghost"
50494 div.className = 'multi-proxy';
50495 for (var i = 0, len = selNodes.length; i < len; i++) {
50496 div.appendChild(selNodes[i].cloneNode(true));
50498 dragData.ddel = div;
50500 //console.log(dragData)
50501 //console.log(dragData.ddel.innerHTML)
50504 //console.log('nodragData')
50508 /** Specify to which ddGroup items in this DDView may be dragged. */
50509 setDraggable: function(ddGroup) {
50510 if (ddGroup instanceof Array) {
50511 Roo.each(ddGroup, this.setDraggable, this);
50514 if (this.dragZone) {
50515 this.dragZone.addToGroup(ddGroup);
50517 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50518 containerScroll: true,
50522 // Draggability implies selection. DragZone's mousedown selects the element.
50523 if (!this.multiSelect) { this.singleSelect = true; }
50525 // Wire the DragZone's handlers up to methods in *this*
50526 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50530 /** Specify from which ddGroup this DDView accepts drops. */
50531 setDroppable: function(ddGroup) {
50532 if (ddGroup instanceof Array) {
50533 Roo.each(ddGroup, this.setDroppable, this);
50536 if (this.dropZone) {
50537 this.dropZone.addToGroup(ddGroup);
50539 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50540 containerScroll: true,
50544 // Wire the DropZone's handlers up to methods in *this*
50545 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50546 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50547 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50548 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50549 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50553 /** Decide whether to drop above or below a View node. */
50554 getDropPoint : function(e, n, dd){
50555 if (n == this.el.dom) { return "above"; }
50556 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50557 var c = t + (b - t) / 2;
50558 var y = Roo.lib.Event.getPageY(e);
50566 onNodeEnter : function(n, dd, e, data){
50570 onNodeOver : function(n, dd, e, data){
50571 var pt = this.getDropPoint(e, n, dd);
50572 // set the insert point style on the target node
50573 var dragElClass = this.dropNotAllowed;
50576 if (pt == "above"){
50577 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50578 targetElClass = "x-view-drag-insert-above";
50580 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50581 targetElClass = "x-view-drag-insert-below";
50583 if (this.lastInsertClass != targetElClass){
50584 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50585 this.lastInsertClass = targetElClass;
50588 return dragElClass;
50591 onNodeOut : function(n, dd, e, data){
50592 this.removeDropIndicators(n);
50595 onNodeDrop : function(n, dd, e, data){
50596 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50599 var pt = this.getDropPoint(e, n, dd);
50600 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50601 if (pt == "below") { insertAt++; }
50602 for (var i = 0; i < data.records.length; i++) {
50603 var r = data.records[i];
50604 var dup = this.store.getById(r.id);
50605 if (dup && (dd != this.dragZone)) {
50606 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50609 this.store.insert(insertAt++, r.copy());
50611 data.source.isDirtyFlag = true;
50613 this.store.insert(insertAt++, r);
50615 this.isDirtyFlag = true;
50618 this.dragZone.cachedTarget = null;
50622 removeDropIndicators : function(n){
50624 Roo.fly(n).removeClass([
50625 "x-view-drag-insert-above",
50626 "x-view-drag-insert-below"]);
50627 this.lastInsertClass = "_noclass";
50632 * Utility method. Add a delete option to the DDView's context menu.
50633 * @param {String} imageUrl The URL of the "delete" icon image.
50635 setDeletable: function(imageUrl) {
50636 if (!this.singleSelect && !this.multiSelect) {
50637 this.singleSelect = true;
50639 var c = this.getContextMenu();
50640 this.contextMenu.on("itemclick", function(item) {
50643 this.remove(this.getSelectedIndexes());
50647 this.contextMenu.add({
50654 /** Return the context menu for this DDView. */
50655 getContextMenu: function() {
50656 if (!this.contextMenu) {
50657 // Create the View's context menu
50658 this.contextMenu = new Roo.menu.Menu({
50659 id: this.id + "-contextmenu"
50661 this.el.on("contextmenu", this.showContextMenu, this);
50663 return this.contextMenu;
50666 disableContextMenu: function() {
50667 if (this.contextMenu) {
50668 this.el.un("contextmenu", this.showContextMenu, this);
50672 showContextMenu: function(e, item) {
50673 item = this.findItemFromChild(e.getTarget());
50676 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50677 this.contextMenu.showAt(e.getXY());
50682 * Remove {@link Roo.data.Record}s at the specified indices.
50683 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50685 remove: function(selectedIndices) {
50686 selectedIndices = [].concat(selectedIndices);
50687 for (var i = 0; i < selectedIndices.length; i++) {
50688 var rec = this.store.getAt(selectedIndices[i]);
50689 this.store.remove(rec);
50694 * Double click fires the event, but also, if this is draggable, and there is only one other
50695 * related DropZone, it transfers the selected node.
50697 onDblClick : function(e){
50698 var item = this.findItemFromChild(e.getTarget());
50700 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50703 if (this.dragGroup) {
50704 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50705 while (targets.indexOf(this.dropZone) > -1) {
50706 targets.remove(this.dropZone);
50708 if (targets.length == 1) {
50709 this.dragZone.cachedTarget = null;
50710 var el = Roo.get(targets[0].getEl());
50711 var box = el.getBox(true);
50712 targets[0].onNodeDrop(el.dom, {
50714 xy: [box.x, box.y + box.height - 1]
50715 }, null, this.getDragData(e));
50721 handleSelection: function(e) {
50722 this.dragZone.cachedTarget = null;
50723 var item = this.findItemFromChild(e.getTarget());
50725 this.clearSelections(true);
50728 if (item && (this.multiSelect || this.singleSelect)){
50729 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50730 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50731 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50732 this.unselect(item);
50734 this.select(item, this.multiSelect && e.ctrlKey);
50735 this.lastSelection = item;
50740 onItemClick : function(item, index, e){
50741 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50747 unselect : function(nodeInfo, suppressEvent){
50748 var node = this.getNode(nodeInfo);
50749 if(node && this.isSelected(node)){
50750 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50751 Roo.fly(node).removeClass(this.selectedClass);
50752 this.selections.remove(node);
50753 if(!suppressEvent){
50754 this.fireEvent("selectionchange", this, this.selections);
50762 * Ext JS Library 1.1.1
50763 * Copyright(c) 2006-2007, Ext JS, LLC.
50765 * Originally Released Under LGPL - original licence link has changed is not relivant.
50768 * <script type="text/javascript">
50772 * @class Roo.LayoutManager
50773 * @extends Roo.util.Observable
50774 * Base class for layout managers.
50776 Roo.LayoutManager = function(container, config){
50777 Roo.LayoutManager.superclass.constructor.call(this);
50778 this.el = Roo.get(container);
50779 // ie scrollbar fix
50780 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50781 document.body.scroll = "no";
50782 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50783 this.el.position('relative');
50785 this.id = this.el.id;
50786 this.el.addClass("x-layout-container");
50787 /** false to disable window resize monitoring @type Boolean */
50788 this.monitorWindowResize = true;
50793 * Fires when a layout is performed.
50794 * @param {Roo.LayoutManager} this
50798 * @event regionresized
50799 * Fires when the user resizes a region.
50800 * @param {Roo.LayoutRegion} region The resized region
50801 * @param {Number} newSize The new size (width for east/west, height for north/south)
50803 "regionresized" : true,
50805 * @event regioncollapsed
50806 * Fires when a region is collapsed.
50807 * @param {Roo.LayoutRegion} region The collapsed region
50809 "regioncollapsed" : true,
50811 * @event regionexpanded
50812 * Fires when a region is expanded.
50813 * @param {Roo.LayoutRegion} region The expanded region
50815 "regionexpanded" : true
50817 this.updating = false;
50818 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50821 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50823 * Returns true if this layout is currently being updated
50824 * @return {Boolean}
50826 isUpdating : function(){
50827 return this.updating;
50831 * Suspend the LayoutManager from doing auto-layouts while
50832 * making multiple add or remove calls
50834 beginUpdate : function(){
50835 this.updating = true;
50839 * Restore auto-layouts and optionally disable the manager from performing a layout
50840 * @param {Boolean} noLayout true to disable a layout update
50842 endUpdate : function(noLayout){
50843 this.updating = false;
50849 layout: function(){
50853 onRegionResized : function(region, newSize){
50854 this.fireEvent("regionresized", region, newSize);
50858 onRegionCollapsed : function(region){
50859 this.fireEvent("regioncollapsed", region);
50862 onRegionExpanded : function(region){
50863 this.fireEvent("regionexpanded", region);
50867 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50868 * performs box-model adjustments.
50869 * @return {Object} The size as an object {width: (the width), height: (the height)}
50871 getViewSize : function(){
50873 if(this.el.dom != document.body){
50874 size = this.el.getSize();
50876 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50878 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50879 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50884 * Returns the Element this layout is bound to.
50885 * @return {Roo.Element}
50887 getEl : function(){
50892 * Returns the specified region.
50893 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50894 * @return {Roo.LayoutRegion}
50896 getRegion : function(target){
50897 return this.regions[target.toLowerCase()];
50900 onWindowResize : function(){
50901 if(this.monitorWindowResize){
50907 * Ext JS Library 1.1.1
50908 * Copyright(c) 2006-2007, Ext JS, LLC.
50910 * Originally Released Under LGPL - original licence link has changed is not relivant.
50913 * <script type="text/javascript">
50916 * @class Roo.BorderLayout
50917 * @extends Roo.LayoutManager
50918 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50919 * please see: <br><br>
50920 * <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>
50921 * <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>
50924 var layout = new Roo.BorderLayout(document.body, {
50958 preferredTabWidth: 150
50963 var CP = Roo.ContentPanel;
50965 layout.beginUpdate();
50966 layout.add("north", new CP("north", "North"));
50967 layout.add("south", new CP("south", {title: "South", closable: true}));
50968 layout.add("west", new CP("west", {title: "West"}));
50969 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50970 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50971 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50972 layout.getRegion("center").showPanel("center1");
50973 layout.endUpdate();
50976 <b>The container the layout is rendered into can be either the body element or any other element.
50977 If it is not the body element, the container needs to either be an absolute positioned element,
50978 or you will need to add "position:relative" to the css of the container. You will also need to specify
50979 the container size if it is not the body element.</b>
50982 * Create a new BorderLayout
50983 * @param {String/HTMLElement/Element} container The container this layout is bound to
50984 * @param {Object} config Configuration options
50986 Roo.BorderLayout = function(container, config){
50987 config = config || {};
50988 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50989 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50990 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50991 var target = this.factory.validRegions[i];
50992 if(config[target]){
50993 this.addRegion(target, config[target]);
50998 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51000 * Creates and adds a new region if it doesn't already exist.
51001 * @param {String} target The target region key (north, south, east, west or center).
51002 * @param {Object} config The regions config object
51003 * @return {BorderLayoutRegion} The new region
51005 addRegion : function(target, config){
51006 if(!this.regions[target]){
51007 var r = this.factory.create(target, this, config);
51008 this.bindRegion(target, r);
51010 return this.regions[target];
51014 bindRegion : function(name, r){
51015 this.regions[name] = r;
51016 r.on("visibilitychange", this.layout, this);
51017 r.on("paneladded", this.layout, this);
51018 r.on("panelremoved", this.layout, this);
51019 r.on("invalidated", this.layout, this);
51020 r.on("resized", this.onRegionResized, this);
51021 r.on("collapsed", this.onRegionCollapsed, this);
51022 r.on("expanded", this.onRegionExpanded, this);
51026 * Performs a layout update.
51028 layout : function(){
51029 if(this.updating) {
51032 var size = this.getViewSize();
51033 var w = size.width;
51034 var h = size.height;
51039 //var x = 0, y = 0;
51041 var rs = this.regions;
51042 var north = rs["north"];
51043 var south = rs["south"];
51044 var west = rs["west"];
51045 var east = rs["east"];
51046 var center = rs["center"];
51047 //if(this.hideOnLayout){ // not supported anymore
51048 //c.el.setStyle("display", "none");
51050 if(north && north.isVisible()){
51051 var b = north.getBox();
51052 var m = north.getMargins();
51053 b.width = w - (m.left+m.right);
51056 centerY = b.height + b.y + m.bottom;
51057 centerH -= centerY;
51058 north.updateBox(this.safeBox(b));
51060 if(south && south.isVisible()){
51061 var b = south.getBox();
51062 var m = south.getMargins();
51063 b.width = w - (m.left+m.right);
51065 var totalHeight = (b.height + m.top + m.bottom);
51066 b.y = h - totalHeight + m.top;
51067 centerH -= totalHeight;
51068 south.updateBox(this.safeBox(b));
51070 if(west && west.isVisible()){
51071 var b = west.getBox();
51072 var m = west.getMargins();
51073 b.height = centerH - (m.top+m.bottom);
51075 b.y = centerY + m.top;
51076 var totalWidth = (b.width + m.left + m.right);
51077 centerX += totalWidth;
51078 centerW -= totalWidth;
51079 west.updateBox(this.safeBox(b));
51081 if(east && east.isVisible()){
51082 var b = east.getBox();
51083 var m = east.getMargins();
51084 b.height = centerH - (m.top+m.bottom);
51085 var totalWidth = (b.width + m.left + m.right);
51086 b.x = w - totalWidth + m.left;
51087 b.y = centerY + m.top;
51088 centerW -= totalWidth;
51089 east.updateBox(this.safeBox(b));
51092 var m = center.getMargins();
51094 x: centerX + m.left,
51095 y: centerY + m.top,
51096 width: centerW - (m.left+m.right),
51097 height: centerH - (m.top+m.bottom)
51099 //if(this.hideOnLayout){
51100 //center.el.setStyle("display", "block");
51102 center.updateBox(this.safeBox(centerBox));
51105 this.fireEvent("layout", this);
51109 safeBox : function(box){
51110 box.width = Math.max(0, box.width);
51111 box.height = Math.max(0, box.height);
51116 * Adds a ContentPanel (or subclass) to this layout.
51117 * @param {String} target The target region key (north, south, east, west or center).
51118 * @param {Roo.ContentPanel} panel The panel to add
51119 * @return {Roo.ContentPanel} The added panel
51121 add : function(target, panel){
51123 target = target.toLowerCase();
51124 return this.regions[target].add(panel);
51128 * Remove a ContentPanel (or subclass) to this layout.
51129 * @param {String} target The target region key (north, south, east, west or center).
51130 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51131 * @return {Roo.ContentPanel} The removed panel
51133 remove : function(target, panel){
51134 target = target.toLowerCase();
51135 return this.regions[target].remove(panel);
51139 * Searches all regions for a panel with the specified id
51140 * @param {String} panelId
51141 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51143 findPanel : function(panelId){
51144 var rs = this.regions;
51145 for(var target in rs){
51146 if(typeof rs[target] != "function"){
51147 var p = rs[target].getPanel(panelId);
51157 * Searches all regions for a panel with the specified id and activates (shows) it.
51158 * @param {String/ContentPanel} panelId The panels id or the panel itself
51159 * @return {Roo.ContentPanel} The shown panel or null
51161 showPanel : function(panelId) {
51162 var rs = this.regions;
51163 for(var target in rs){
51164 var r = rs[target];
51165 if(typeof r != "function"){
51166 if(r.hasPanel(panelId)){
51167 return r.showPanel(panelId);
51175 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51176 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51178 restoreState : function(provider){
51180 provider = Roo.state.Manager;
51182 var sm = new Roo.LayoutStateManager();
51183 sm.init(this, provider);
51187 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51188 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51189 * a valid ContentPanel config object. Example:
51191 // Create the main layout
51192 var layout = new Roo.BorderLayout('main-ct', {
51203 // Create and add multiple ContentPanels at once via configs
51206 id: 'source-files',
51208 title:'Ext Source Files',
51221 * @param {Object} regions An object containing ContentPanel configs by region name
51223 batchAdd : function(regions){
51224 this.beginUpdate();
51225 for(var rname in regions){
51226 var lr = this.regions[rname];
51228 this.addTypedPanels(lr, regions[rname]);
51235 addTypedPanels : function(lr, ps){
51236 if(typeof ps == 'string'){
51237 lr.add(new Roo.ContentPanel(ps));
51239 else if(ps instanceof Array){
51240 for(var i =0, len = ps.length; i < len; i++){
51241 this.addTypedPanels(lr, ps[i]);
51244 else if(!ps.events){ // raw config?
51246 delete ps.el; // prevent conflict
51247 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51249 else { // panel object assumed!
51254 * Adds a xtype elements to the layout.
51258 xtype : 'ContentPanel',
51265 xtype : 'NestedLayoutPanel',
51271 items : [ ... list of content panels or nested layout panels.. ]
51275 * @param {Object} cfg Xtype definition of item to add.
51277 addxtype : function(cfg)
51279 // basically accepts a pannel...
51280 // can accept a layout region..!?!?
51281 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51283 if (!cfg.xtype.match(/Panel$/)) {
51288 if (typeof(cfg.region) == 'undefined') {
51289 Roo.log("Failed to add Panel, region was not set");
51293 var region = cfg.region;
51299 xitems = cfg.items;
51306 case 'ContentPanel': // ContentPanel (el, cfg)
51307 case 'ScrollPanel': // ContentPanel (el, cfg)
51309 if(cfg.autoCreate) {
51310 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51312 var el = this.el.createChild();
51313 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51316 this.add(region, ret);
51320 case 'TreePanel': // our new panel!
51321 cfg.el = this.el.createChild();
51322 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51323 this.add(region, ret);
51326 case 'NestedLayoutPanel':
51327 // create a new Layout (which is a Border Layout...
51328 var el = this.el.createChild();
51329 var clayout = cfg.layout;
51331 clayout.items = clayout.items || [];
51332 // replace this exitems with the clayout ones..
51333 xitems = clayout.items;
51336 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51337 cfg.background = false;
51339 var layout = new Roo.BorderLayout(el, clayout);
51341 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51342 //console.log('adding nested layout panel ' + cfg.toSource());
51343 this.add(region, ret);
51344 nb = {}; /// find first...
51349 // needs grid and region
51351 //var el = this.getRegion(region).el.createChild();
51352 var el = this.el.createChild();
51353 // create the grid first...
51355 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51357 if (region == 'center' && this.active ) {
51358 cfg.background = false;
51360 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51362 this.add(region, ret);
51363 if (cfg.background) {
51364 ret.on('activate', function(gp) {
51365 if (!gp.grid.rendered) {
51380 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51382 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51383 this.add(region, ret);
51386 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51390 // GridPanel (grid, cfg)
51393 this.beginUpdate();
51397 Roo.each(xitems, function(i) {
51398 region = nb && i.region ? i.region : false;
51400 var add = ret.addxtype(i);
51403 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51404 if (!i.background) {
51405 abn[region] = nb[region] ;
51412 // make the last non-background panel active..
51413 //if (nb) { Roo.log(abn); }
51416 for(var r in abn) {
51417 region = this.getRegion(r);
51419 // tried using nb[r], but it does not work..
51421 region.showPanel(abn[r]);
51432 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51433 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51434 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51435 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51438 var CP = Roo.ContentPanel;
51440 var layout = Roo.BorderLayout.create({
51444 panels: [new CP("north", "North")]
51453 panels: [new CP("west", {title: "West"})]
51462 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51471 panels: [new CP("south", {title: "South", closable: true})]
51478 preferredTabWidth: 150,
51480 new CP("center1", {title: "Close Me", closable: true}),
51481 new CP("center2", {title: "Center Panel", closable: false})
51486 layout.getRegion("center").showPanel("center1");
51491 Roo.BorderLayout.create = function(config, targetEl){
51492 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51493 layout.beginUpdate();
51494 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51495 for(var j = 0, jlen = regions.length; j < jlen; j++){
51496 var lr = regions[j];
51497 if(layout.regions[lr] && config[lr].panels){
51498 var r = layout.regions[lr];
51499 var ps = config[lr].panels;
51500 layout.addTypedPanels(r, ps);
51503 layout.endUpdate();
51508 Roo.BorderLayout.RegionFactory = {
51510 validRegions : ["north","south","east","west","center"],
51513 create : function(target, mgr, config){
51514 target = target.toLowerCase();
51515 if(config.lightweight || config.basic){
51516 return new Roo.BasicLayoutRegion(mgr, config, target);
51520 return new Roo.NorthLayoutRegion(mgr, config);
51522 return new Roo.SouthLayoutRegion(mgr, config);
51524 return new Roo.EastLayoutRegion(mgr, config);
51526 return new Roo.WestLayoutRegion(mgr, config);
51528 return new Roo.CenterLayoutRegion(mgr, config);
51530 throw 'Layout region "'+target+'" not supported.';
51534 * Ext JS Library 1.1.1
51535 * Copyright(c) 2006-2007, Ext JS, LLC.
51537 * Originally Released Under LGPL - original licence link has changed is not relivant.
51540 * <script type="text/javascript">
51544 * @class Roo.BasicLayoutRegion
51545 * @extends Roo.util.Observable
51546 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51547 * and does not have a titlebar, tabs or any other features. All it does is size and position
51548 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51550 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51552 this.position = pos;
51555 * @scope Roo.BasicLayoutRegion
51559 * @event beforeremove
51560 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51561 * @param {Roo.LayoutRegion} this
51562 * @param {Roo.ContentPanel} panel The panel
51563 * @param {Object} e The cancel event object
51565 "beforeremove" : true,
51567 * @event invalidated
51568 * Fires when the layout for this region is changed.
51569 * @param {Roo.LayoutRegion} this
51571 "invalidated" : true,
51573 * @event visibilitychange
51574 * Fires when this region is shown or hidden
51575 * @param {Roo.LayoutRegion} this
51576 * @param {Boolean} visibility true or false
51578 "visibilitychange" : true,
51580 * @event paneladded
51581 * Fires when a panel is added.
51582 * @param {Roo.LayoutRegion} this
51583 * @param {Roo.ContentPanel} panel The panel
51585 "paneladded" : true,
51587 * @event panelremoved
51588 * Fires when a panel is removed.
51589 * @param {Roo.LayoutRegion} this
51590 * @param {Roo.ContentPanel} panel The panel
51592 "panelremoved" : true,
51594 * @event beforecollapse
51595 * Fires when this region before collapse.
51596 * @param {Roo.LayoutRegion} this
51598 "beforecollapse" : true,
51601 * Fires when this region is collapsed.
51602 * @param {Roo.LayoutRegion} this
51604 "collapsed" : true,
51607 * Fires when this region is expanded.
51608 * @param {Roo.LayoutRegion} this
51613 * Fires when this region is slid into view.
51614 * @param {Roo.LayoutRegion} this
51616 "slideshow" : true,
51619 * Fires when this region slides out of view.
51620 * @param {Roo.LayoutRegion} this
51622 "slidehide" : true,
51624 * @event panelactivated
51625 * Fires when a panel is activated.
51626 * @param {Roo.LayoutRegion} this
51627 * @param {Roo.ContentPanel} panel The activated panel
51629 "panelactivated" : true,
51632 * Fires when the user resizes this region.
51633 * @param {Roo.LayoutRegion} this
51634 * @param {Number} newSize The new size (width for east/west, height for north/south)
51638 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51639 this.panels = new Roo.util.MixedCollection();
51640 this.panels.getKey = this.getPanelId.createDelegate(this);
51642 this.activePanel = null;
51643 // ensure listeners are added...
51645 if (config.listeners || config.events) {
51646 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51647 listeners : config.listeners || {},
51648 events : config.events || {}
51652 if(skipConfig !== true){
51653 this.applyConfig(config);
51657 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51658 getPanelId : function(p){
51662 applyConfig : function(config){
51663 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51664 this.config = config;
51669 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51670 * the width, for horizontal (north, south) the height.
51671 * @param {Number} newSize The new width or height
51673 resizeTo : function(newSize){
51674 var el = this.el ? this.el :
51675 (this.activePanel ? this.activePanel.getEl() : null);
51677 switch(this.position){
51680 el.setWidth(newSize);
51681 this.fireEvent("resized", this, newSize);
51685 el.setHeight(newSize);
51686 this.fireEvent("resized", this, newSize);
51692 getBox : function(){
51693 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51696 getMargins : function(){
51697 return this.margins;
51700 updateBox : function(box){
51702 var el = this.activePanel.getEl();
51703 el.dom.style.left = box.x + "px";
51704 el.dom.style.top = box.y + "px";
51705 this.activePanel.setSize(box.width, box.height);
51709 * Returns the container element for this region.
51710 * @return {Roo.Element}
51712 getEl : function(){
51713 return this.activePanel;
51717 * Returns true if this region is currently visible.
51718 * @return {Boolean}
51720 isVisible : function(){
51721 return this.activePanel ? true : false;
51724 setActivePanel : function(panel){
51725 panel = this.getPanel(panel);
51726 if(this.activePanel && this.activePanel != panel){
51727 this.activePanel.setActiveState(false);
51728 this.activePanel.getEl().setLeftTop(-10000,-10000);
51730 this.activePanel = panel;
51731 panel.setActiveState(true);
51733 panel.setSize(this.box.width, this.box.height);
51735 this.fireEvent("panelactivated", this, panel);
51736 this.fireEvent("invalidated");
51740 * Show the specified panel.
51741 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51742 * @return {Roo.ContentPanel} The shown panel or null
51744 showPanel : function(panel){
51745 if(panel = this.getPanel(panel)){
51746 this.setActivePanel(panel);
51752 * Get the active panel for this region.
51753 * @return {Roo.ContentPanel} The active panel or null
51755 getActivePanel : function(){
51756 return this.activePanel;
51760 * Add the passed ContentPanel(s)
51761 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51762 * @return {Roo.ContentPanel} The panel added (if only one was added)
51764 add : function(panel){
51765 if(arguments.length > 1){
51766 for(var i = 0, len = arguments.length; i < len; i++) {
51767 this.add(arguments[i]);
51771 if(this.hasPanel(panel)){
51772 this.showPanel(panel);
51775 var el = panel.getEl();
51776 if(el.dom.parentNode != this.mgr.el.dom){
51777 this.mgr.el.dom.appendChild(el.dom);
51779 if(panel.setRegion){
51780 panel.setRegion(this);
51782 this.panels.add(panel);
51783 el.setStyle("position", "absolute");
51784 if(!panel.background){
51785 this.setActivePanel(panel);
51786 if(this.config.initialSize && this.panels.getCount()==1){
51787 this.resizeTo(this.config.initialSize);
51790 this.fireEvent("paneladded", this, panel);
51795 * Returns true if the panel is in this region.
51796 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51797 * @return {Boolean}
51799 hasPanel : function(panel){
51800 if(typeof panel == "object"){ // must be panel obj
51801 panel = panel.getId();
51803 return this.getPanel(panel) ? true : false;
51807 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51808 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51809 * @param {Boolean} preservePanel Overrides the config preservePanel option
51810 * @return {Roo.ContentPanel} The panel that was removed
51812 remove : function(panel, preservePanel){
51813 panel = this.getPanel(panel);
51818 this.fireEvent("beforeremove", this, panel, e);
51819 if(e.cancel === true){
51822 var panelId = panel.getId();
51823 this.panels.removeKey(panelId);
51828 * Returns the panel specified or null if it's not in this region.
51829 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51830 * @return {Roo.ContentPanel}
51832 getPanel : function(id){
51833 if(typeof id == "object"){ // must be panel obj
51836 return this.panels.get(id);
51840 * Returns this regions position (north/south/east/west/center).
51843 getPosition: function(){
51844 return this.position;
51848 * Ext JS Library 1.1.1
51849 * Copyright(c) 2006-2007, Ext JS, LLC.
51851 * Originally Released Under LGPL - original licence link has changed is not relivant.
51854 * <script type="text/javascript">
51858 * @class Roo.LayoutRegion
51859 * @extends Roo.BasicLayoutRegion
51860 * This class represents a region in a layout manager.
51861 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51862 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51863 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51864 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51865 * @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})
51866 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51867 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51868 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51869 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51870 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51871 * @cfg {String} title The title for the region (overrides panel titles)
51872 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51873 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51874 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51875 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51876 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51877 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51878 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51879 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51880 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51881 * @cfg {Boolean} showPin True to show a pin button
51882 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51883 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51884 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51885 * @cfg {Number} width For East/West panels
51886 * @cfg {Number} height For North/South panels
51887 * @cfg {Boolean} split To show the splitter
51888 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51890 Roo.LayoutRegion = function(mgr, config, pos){
51891 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51892 var dh = Roo.DomHelper;
51893 /** This region's container element
51894 * @type Roo.Element */
51895 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51896 /** This region's title element
51897 * @type Roo.Element */
51899 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51900 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51901 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51903 this.titleEl.enableDisplayMode();
51904 /** This region's title text element
51905 * @type HTMLElement */
51906 this.titleTextEl = this.titleEl.dom.firstChild;
51907 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51908 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51909 this.closeBtn.enableDisplayMode();
51910 this.closeBtn.on("click", this.closeClicked, this);
51911 this.closeBtn.hide();
51913 this.createBody(config);
51914 this.visible = true;
51915 this.collapsed = false;
51917 if(config.hideWhenEmpty){
51919 this.on("paneladded", this.validateVisibility, this);
51920 this.on("panelremoved", this.validateVisibility, this);
51922 this.applyConfig(config);
51925 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51927 createBody : function(){
51928 /** This region's body element
51929 * @type Roo.Element */
51930 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51933 applyConfig : function(c){
51934 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51935 var dh = Roo.DomHelper;
51936 if(c.titlebar !== false){
51937 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51938 this.collapseBtn.on("click", this.collapse, this);
51939 this.collapseBtn.enableDisplayMode();
51941 if(c.showPin === true || this.showPin){
51942 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51943 this.stickBtn.enableDisplayMode();
51944 this.stickBtn.on("click", this.expand, this);
51945 this.stickBtn.hide();
51948 /** This region's collapsed element
51949 * @type Roo.Element */
51950 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51951 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51953 if(c.floatable !== false){
51954 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51955 this.collapsedEl.on("click", this.collapseClick, this);
51958 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51959 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51960 id: "message", unselectable: "on", style:{"float":"left"}});
51961 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51963 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51964 this.expandBtn.on("click", this.expand, this);
51966 if(this.collapseBtn){
51967 this.collapseBtn.setVisible(c.collapsible == true);
51969 this.cmargins = c.cmargins || this.cmargins ||
51970 (this.position == "west" || this.position == "east" ?
51971 {top: 0, left: 2, right:2, bottom: 0} :
51972 {top: 2, left: 0, right:0, bottom: 2});
51973 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51974 this.bottomTabs = c.tabPosition != "top";
51975 this.autoScroll = c.autoScroll || false;
51976 if(this.autoScroll){
51977 this.bodyEl.setStyle("overflow", "auto");
51979 this.bodyEl.setStyle("overflow", "hidden");
51981 //if(c.titlebar !== false){
51982 if((!c.titlebar && !c.title) || c.titlebar === false){
51983 this.titleEl.hide();
51985 this.titleEl.show();
51987 this.titleTextEl.innerHTML = c.title;
51991 this.duration = c.duration || .30;
51992 this.slideDuration = c.slideDuration || .45;
51995 this.collapse(true);
52002 * Returns true if this region is currently visible.
52003 * @return {Boolean}
52005 isVisible : function(){
52006 return this.visible;
52010 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52011 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52013 setCollapsedTitle : function(title){
52014 title = title || " ";
52015 if(this.collapsedTitleTextEl){
52016 this.collapsedTitleTextEl.innerHTML = title;
52020 getBox : function(){
52022 if(!this.collapsed){
52023 b = this.el.getBox(false, true);
52025 b = this.collapsedEl.getBox(false, true);
52030 getMargins : function(){
52031 return this.collapsed ? this.cmargins : this.margins;
52034 highlight : function(){
52035 this.el.addClass("x-layout-panel-dragover");
52038 unhighlight : function(){
52039 this.el.removeClass("x-layout-panel-dragover");
52042 updateBox : function(box){
52044 if(!this.collapsed){
52045 this.el.dom.style.left = box.x + "px";
52046 this.el.dom.style.top = box.y + "px";
52047 this.updateBody(box.width, box.height);
52049 this.collapsedEl.dom.style.left = box.x + "px";
52050 this.collapsedEl.dom.style.top = box.y + "px";
52051 this.collapsedEl.setSize(box.width, box.height);
52054 this.tabs.autoSizeTabs();
52058 updateBody : function(w, h){
52060 this.el.setWidth(w);
52061 w -= this.el.getBorderWidth("rl");
52062 if(this.config.adjustments){
52063 w += this.config.adjustments[0];
52067 this.el.setHeight(h);
52068 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52069 h -= this.el.getBorderWidth("tb");
52070 if(this.config.adjustments){
52071 h += this.config.adjustments[1];
52073 this.bodyEl.setHeight(h);
52075 h = this.tabs.syncHeight(h);
52078 if(this.panelSize){
52079 w = w !== null ? w : this.panelSize.width;
52080 h = h !== null ? h : this.panelSize.height;
52082 if(this.activePanel){
52083 var el = this.activePanel.getEl();
52084 w = w !== null ? w : el.getWidth();
52085 h = h !== null ? h : el.getHeight();
52086 this.panelSize = {width: w, height: h};
52087 this.activePanel.setSize(w, h);
52089 if(Roo.isIE && this.tabs){
52090 this.tabs.el.repaint();
52095 * Returns the container element for this region.
52096 * @return {Roo.Element}
52098 getEl : function(){
52103 * Hides this region.
52106 if(!this.collapsed){
52107 this.el.dom.style.left = "-2000px";
52110 this.collapsedEl.dom.style.left = "-2000px";
52111 this.collapsedEl.hide();
52113 this.visible = false;
52114 this.fireEvent("visibilitychange", this, false);
52118 * Shows this region if it was previously hidden.
52121 if(!this.collapsed){
52124 this.collapsedEl.show();
52126 this.visible = true;
52127 this.fireEvent("visibilitychange", this, true);
52130 closeClicked : function(){
52131 if(this.activePanel){
52132 this.remove(this.activePanel);
52136 collapseClick : function(e){
52138 e.stopPropagation();
52141 e.stopPropagation();
52147 * Collapses this region.
52148 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52150 collapse : function(skipAnim, skipCheck = false){
52151 if(this.collapsed) {
52155 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52157 this.collapsed = true;
52159 this.split.el.hide();
52161 if(this.config.animate && skipAnim !== true){
52162 this.fireEvent("invalidated", this);
52163 this.animateCollapse();
52165 this.el.setLocation(-20000,-20000);
52167 this.collapsedEl.show();
52168 this.fireEvent("collapsed", this);
52169 this.fireEvent("invalidated", this);
52175 animateCollapse : function(){
52180 * Expands this region if it was previously collapsed.
52181 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52182 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52184 expand : function(e, skipAnim){
52186 e.stopPropagation();
52188 if(!this.collapsed || this.el.hasActiveFx()) {
52192 this.afterSlideIn();
52195 this.collapsed = false;
52196 if(this.config.animate && skipAnim !== true){
52197 this.animateExpand();
52201 this.split.el.show();
52203 this.collapsedEl.setLocation(-2000,-2000);
52204 this.collapsedEl.hide();
52205 this.fireEvent("invalidated", this);
52206 this.fireEvent("expanded", this);
52210 animateExpand : function(){
52214 initTabs : function()
52216 this.bodyEl.setStyle("overflow", "hidden");
52217 var ts = new Roo.TabPanel(
52220 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52221 disableTooltips: this.config.disableTabTips,
52222 toolbar : this.config.toolbar
52225 if(this.config.hideTabs){
52226 ts.stripWrap.setDisplayed(false);
52229 ts.resizeTabs = this.config.resizeTabs === true;
52230 ts.minTabWidth = this.config.minTabWidth || 40;
52231 ts.maxTabWidth = this.config.maxTabWidth || 250;
52232 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52233 ts.monitorResize = false;
52234 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52235 ts.bodyEl.addClass('x-layout-tabs-body');
52236 this.panels.each(this.initPanelAsTab, this);
52239 initPanelAsTab : function(panel){
52240 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52241 this.config.closeOnTab && panel.isClosable());
52242 if(panel.tabTip !== undefined){
52243 ti.setTooltip(panel.tabTip);
52245 ti.on("activate", function(){
52246 this.setActivePanel(panel);
52248 if(this.config.closeOnTab){
52249 ti.on("beforeclose", function(t, e){
52251 this.remove(panel);
52257 updatePanelTitle : function(panel, title){
52258 if(this.activePanel == panel){
52259 this.updateTitle(title);
52262 var ti = this.tabs.getTab(panel.getEl().id);
52264 if(panel.tabTip !== undefined){
52265 ti.setTooltip(panel.tabTip);
52270 updateTitle : function(title){
52271 if(this.titleTextEl && !this.config.title){
52272 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52276 setActivePanel : function(panel){
52277 panel = this.getPanel(panel);
52278 if(this.activePanel && this.activePanel != panel){
52279 this.activePanel.setActiveState(false);
52281 this.activePanel = panel;
52282 panel.setActiveState(true);
52283 if(this.panelSize){
52284 panel.setSize(this.panelSize.width, this.panelSize.height);
52287 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52289 this.updateTitle(panel.getTitle());
52291 this.fireEvent("invalidated", this);
52293 this.fireEvent("panelactivated", this, panel);
52297 * Shows the specified panel.
52298 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52299 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52301 showPanel : function(panel)
52303 panel = this.getPanel(panel);
52306 var tab = this.tabs.getTab(panel.getEl().id);
52307 if(tab.isHidden()){
52308 this.tabs.unhideTab(tab.id);
52312 this.setActivePanel(panel);
52319 * Get the active panel for this region.
52320 * @return {Roo.ContentPanel} The active panel or null
52322 getActivePanel : function(){
52323 return this.activePanel;
52326 validateVisibility : function(){
52327 if(this.panels.getCount() < 1){
52328 this.updateTitle(" ");
52329 this.closeBtn.hide();
52332 if(!this.isVisible()){
52339 * Adds the passed ContentPanel(s) to this region.
52340 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52341 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52343 add : function(panel){
52344 if(arguments.length > 1){
52345 for(var i = 0, len = arguments.length; i < len; i++) {
52346 this.add(arguments[i]);
52350 if(this.hasPanel(panel)){
52351 this.showPanel(panel);
52354 panel.setRegion(this);
52355 this.panels.add(panel);
52356 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52357 this.bodyEl.dom.appendChild(panel.getEl().dom);
52358 if(panel.background !== true){
52359 this.setActivePanel(panel);
52361 this.fireEvent("paneladded", this, panel);
52367 this.initPanelAsTab(panel);
52369 if(panel.background !== true){
52370 this.tabs.activate(panel.getEl().id);
52372 this.fireEvent("paneladded", this, panel);
52377 * Hides the tab for the specified panel.
52378 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52380 hidePanel : function(panel){
52381 if(this.tabs && (panel = this.getPanel(panel))){
52382 this.tabs.hideTab(panel.getEl().id);
52387 * Unhides the tab for a previously hidden panel.
52388 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52390 unhidePanel : function(panel){
52391 if(this.tabs && (panel = this.getPanel(panel))){
52392 this.tabs.unhideTab(panel.getEl().id);
52396 clearPanels : function(){
52397 while(this.panels.getCount() > 0){
52398 this.remove(this.panels.first());
52403 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52404 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52405 * @param {Boolean} preservePanel Overrides the config preservePanel option
52406 * @return {Roo.ContentPanel} The panel that was removed
52408 remove : function(panel, preservePanel){
52409 panel = this.getPanel(panel);
52414 this.fireEvent("beforeremove", this, panel, e);
52415 if(e.cancel === true){
52418 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52419 var panelId = panel.getId();
52420 this.panels.removeKey(panelId);
52422 document.body.appendChild(panel.getEl().dom);
52425 this.tabs.removeTab(panel.getEl().id);
52426 }else if (!preservePanel){
52427 this.bodyEl.dom.removeChild(panel.getEl().dom);
52429 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52430 var p = this.panels.first();
52431 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52432 tempEl.appendChild(p.getEl().dom);
52433 this.bodyEl.update("");
52434 this.bodyEl.dom.appendChild(p.getEl().dom);
52436 this.updateTitle(p.getTitle());
52438 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52439 this.setActivePanel(p);
52441 panel.setRegion(null);
52442 if(this.activePanel == panel){
52443 this.activePanel = null;
52445 if(this.config.autoDestroy !== false && preservePanel !== true){
52446 try{panel.destroy();}catch(e){}
52448 this.fireEvent("panelremoved", this, panel);
52453 * Returns the TabPanel component used by this region
52454 * @return {Roo.TabPanel}
52456 getTabs : function(){
52460 createTool : function(parentEl, className){
52461 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52462 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52463 btn.addClassOnOver("x-layout-tools-button-over");
52468 * Ext JS Library 1.1.1
52469 * Copyright(c) 2006-2007, Ext JS, LLC.
52471 * Originally Released Under LGPL - original licence link has changed is not relivant.
52474 * <script type="text/javascript">
52480 * @class Roo.SplitLayoutRegion
52481 * @extends Roo.LayoutRegion
52482 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52484 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52485 this.cursor = cursor;
52486 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52489 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52490 splitTip : "Drag to resize.",
52491 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52492 useSplitTips : false,
52494 applyConfig : function(config){
52495 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52498 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52499 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52500 /** The SplitBar for this region
52501 * @type Roo.SplitBar */
52502 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52503 this.split.on("moved", this.onSplitMove, this);
52504 this.split.useShim = config.useShim === true;
52505 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52506 if(this.useSplitTips){
52507 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52509 if(config.collapsible){
52510 this.split.el.on("dblclick", this.collapse, this);
52513 if(typeof config.minSize != "undefined"){
52514 this.split.minSize = config.minSize;
52516 if(typeof config.maxSize != "undefined"){
52517 this.split.maxSize = config.maxSize;
52519 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52520 this.hideSplitter();
52525 getHMaxSize : function(){
52526 var cmax = this.config.maxSize || 10000;
52527 var center = this.mgr.getRegion("center");
52528 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52531 getVMaxSize : function(){
52532 var cmax = this.config.maxSize || 10000;
52533 var center = this.mgr.getRegion("center");
52534 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52537 onSplitMove : function(split, newSize){
52538 this.fireEvent("resized", this, newSize);
52542 * Returns the {@link Roo.SplitBar} for this region.
52543 * @return {Roo.SplitBar}
52545 getSplitBar : function(){
52550 this.hideSplitter();
52551 Roo.SplitLayoutRegion.superclass.hide.call(this);
52554 hideSplitter : function(){
52556 this.split.el.setLocation(-2000,-2000);
52557 this.split.el.hide();
52563 this.split.el.show();
52565 Roo.SplitLayoutRegion.superclass.show.call(this);
52568 beforeSlide: function(){
52569 if(Roo.isGecko){// firefox overflow auto bug workaround
52570 this.bodyEl.clip();
52572 this.tabs.bodyEl.clip();
52574 if(this.activePanel){
52575 this.activePanel.getEl().clip();
52577 if(this.activePanel.beforeSlide){
52578 this.activePanel.beforeSlide();
52584 afterSlide : function(){
52585 if(Roo.isGecko){// firefox overflow auto bug workaround
52586 this.bodyEl.unclip();
52588 this.tabs.bodyEl.unclip();
52590 if(this.activePanel){
52591 this.activePanel.getEl().unclip();
52592 if(this.activePanel.afterSlide){
52593 this.activePanel.afterSlide();
52599 initAutoHide : function(){
52600 if(this.autoHide !== false){
52601 if(!this.autoHideHd){
52602 var st = new Roo.util.DelayedTask(this.slideIn, this);
52603 this.autoHideHd = {
52604 "mouseout": function(e){
52605 if(!e.within(this.el, true)){
52609 "mouseover" : function(e){
52615 this.el.on(this.autoHideHd);
52619 clearAutoHide : function(){
52620 if(this.autoHide !== false){
52621 this.el.un("mouseout", this.autoHideHd.mouseout);
52622 this.el.un("mouseover", this.autoHideHd.mouseover);
52626 clearMonitor : function(){
52627 Roo.get(document).un("click", this.slideInIf, this);
52630 // these names are backwards but not changed for compat
52631 slideOut : function(){
52632 if(this.isSlid || this.el.hasActiveFx()){
52635 this.isSlid = true;
52636 if(this.collapseBtn){
52637 this.collapseBtn.hide();
52639 this.closeBtnState = this.closeBtn.getStyle('display');
52640 this.closeBtn.hide();
52642 this.stickBtn.show();
52645 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52646 this.beforeSlide();
52647 this.el.setStyle("z-index", 10001);
52648 this.el.slideIn(this.getSlideAnchor(), {
52649 callback: function(){
52651 this.initAutoHide();
52652 Roo.get(document).on("click", this.slideInIf, this);
52653 this.fireEvent("slideshow", this);
52660 afterSlideIn : function(){
52661 this.clearAutoHide();
52662 this.isSlid = false;
52663 this.clearMonitor();
52664 this.el.setStyle("z-index", "");
52665 if(this.collapseBtn){
52666 this.collapseBtn.show();
52668 this.closeBtn.setStyle('display', this.closeBtnState);
52670 this.stickBtn.hide();
52672 this.fireEvent("slidehide", this);
52675 slideIn : function(cb){
52676 if(!this.isSlid || this.el.hasActiveFx()){
52680 this.isSlid = false;
52681 this.beforeSlide();
52682 this.el.slideOut(this.getSlideAnchor(), {
52683 callback: function(){
52684 this.el.setLeftTop(-10000, -10000);
52686 this.afterSlideIn();
52694 slideInIf : function(e){
52695 if(!e.within(this.el)){
52700 animateCollapse : function(){
52701 this.beforeSlide();
52702 this.el.setStyle("z-index", 20000);
52703 var anchor = this.getSlideAnchor();
52704 this.el.slideOut(anchor, {
52705 callback : function(){
52706 this.el.setStyle("z-index", "");
52707 this.collapsedEl.slideIn(anchor, {duration:.3});
52709 this.el.setLocation(-10000,-10000);
52711 this.fireEvent("collapsed", this);
52718 animateExpand : function(){
52719 this.beforeSlide();
52720 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52721 this.el.setStyle("z-index", 20000);
52722 this.collapsedEl.hide({
52725 this.el.slideIn(this.getSlideAnchor(), {
52726 callback : function(){
52727 this.el.setStyle("z-index", "");
52730 this.split.el.show();
52732 this.fireEvent("invalidated", this);
52733 this.fireEvent("expanded", this);
52761 getAnchor : function(){
52762 return this.anchors[this.position];
52765 getCollapseAnchor : function(){
52766 return this.canchors[this.position];
52769 getSlideAnchor : function(){
52770 return this.sanchors[this.position];
52773 getAlignAdj : function(){
52774 var cm = this.cmargins;
52775 switch(this.position){
52791 getExpandAdj : function(){
52792 var c = this.collapsedEl, cm = this.cmargins;
52793 switch(this.position){
52795 return [-(cm.right+c.getWidth()+cm.left), 0];
52798 return [cm.right+c.getWidth()+cm.left, 0];
52801 return [0, -(cm.top+cm.bottom+c.getHeight())];
52804 return [0, cm.top+cm.bottom+c.getHeight()];
52810 * Ext JS Library 1.1.1
52811 * Copyright(c) 2006-2007, Ext JS, LLC.
52813 * Originally Released Under LGPL - original licence link has changed is not relivant.
52816 * <script type="text/javascript">
52819 * These classes are private internal classes
52821 Roo.CenterLayoutRegion = function(mgr, config){
52822 Roo.LayoutRegion.call(this, mgr, config, "center");
52823 this.visible = true;
52824 this.minWidth = config.minWidth || 20;
52825 this.minHeight = config.minHeight || 20;
52828 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52830 // center panel can't be hidden
52834 // center panel can't be hidden
52837 getMinWidth: function(){
52838 return this.minWidth;
52841 getMinHeight: function(){
52842 return this.minHeight;
52847 Roo.NorthLayoutRegion = function(mgr, config){
52848 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52850 this.split.placement = Roo.SplitBar.TOP;
52851 this.split.orientation = Roo.SplitBar.VERTICAL;
52852 this.split.el.addClass("x-layout-split-v");
52854 var size = config.initialSize || config.height;
52855 if(typeof size != "undefined"){
52856 this.el.setHeight(size);
52859 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52860 orientation: Roo.SplitBar.VERTICAL,
52861 getBox : function(){
52862 if(this.collapsed){
52863 return this.collapsedEl.getBox();
52865 var box = this.el.getBox();
52867 box.height += this.split.el.getHeight();
52872 updateBox : function(box){
52873 if(this.split && !this.collapsed){
52874 box.height -= this.split.el.getHeight();
52875 this.split.el.setLeft(box.x);
52876 this.split.el.setTop(box.y+box.height);
52877 this.split.el.setWidth(box.width);
52879 if(this.collapsed){
52880 this.updateBody(box.width, null);
52882 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52886 Roo.SouthLayoutRegion = function(mgr, config){
52887 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52889 this.split.placement = Roo.SplitBar.BOTTOM;
52890 this.split.orientation = Roo.SplitBar.VERTICAL;
52891 this.split.el.addClass("x-layout-split-v");
52893 var size = config.initialSize || config.height;
52894 if(typeof size != "undefined"){
52895 this.el.setHeight(size);
52898 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52899 orientation: Roo.SplitBar.VERTICAL,
52900 getBox : function(){
52901 if(this.collapsed){
52902 return this.collapsedEl.getBox();
52904 var box = this.el.getBox();
52906 var sh = this.split.el.getHeight();
52913 updateBox : function(box){
52914 if(this.split && !this.collapsed){
52915 var sh = this.split.el.getHeight();
52918 this.split.el.setLeft(box.x);
52919 this.split.el.setTop(box.y-sh);
52920 this.split.el.setWidth(box.width);
52922 if(this.collapsed){
52923 this.updateBody(box.width, null);
52925 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52929 Roo.EastLayoutRegion = function(mgr, config){
52930 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52932 this.split.placement = Roo.SplitBar.RIGHT;
52933 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52934 this.split.el.addClass("x-layout-split-h");
52936 var size = config.initialSize || config.width;
52937 if(typeof size != "undefined"){
52938 this.el.setWidth(size);
52941 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52942 orientation: Roo.SplitBar.HORIZONTAL,
52943 getBox : function(){
52944 if(this.collapsed){
52945 return this.collapsedEl.getBox();
52947 var box = this.el.getBox();
52949 var sw = this.split.el.getWidth();
52956 updateBox : function(box){
52957 if(this.split && !this.collapsed){
52958 var sw = this.split.el.getWidth();
52960 this.split.el.setLeft(box.x);
52961 this.split.el.setTop(box.y);
52962 this.split.el.setHeight(box.height);
52965 if(this.collapsed){
52966 this.updateBody(null, box.height);
52968 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52972 Roo.WestLayoutRegion = function(mgr, config){
52973 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52975 this.split.placement = Roo.SplitBar.LEFT;
52976 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52977 this.split.el.addClass("x-layout-split-h");
52979 var size = config.initialSize || config.width;
52980 if(typeof size != "undefined"){
52981 this.el.setWidth(size);
52984 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52985 orientation: Roo.SplitBar.HORIZONTAL,
52986 getBox : function(){
52987 if(this.collapsed){
52988 return this.collapsedEl.getBox();
52990 var box = this.el.getBox();
52992 box.width += this.split.el.getWidth();
52997 updateBox : function(box){
52998 if(this.split && !this.collapsed){
52999 var sw = this.split.el.getWidth();
53001 this.split.el.setLeft(box.x+box.width);
53002 this.split.el.setTop(box.y);
53003 this.split.el.setHeight(box.height);
53005 if(this.collapsed){
53006 this.updateBody(null, box.height);
53008 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53013 * Ext JS Library 1.1.1
53014 * Copyright(c) 2006-2007, Ext JS, LLC.
53016 * Originally Released Under LGPL - original licence link has changed is not relivant.
53019 * <script type="text/javascript">
53024 * Private internal class for reading and applying state
53026 Roo.LayoutStateManager = function(layout){
53027 // default empty state
53036 Roo.LayoutStateManager.prototype = {
53037 init : function(layout, provider){
53038 this.provider = provider;
53039 var state = provider.get(layout.id+"-layout-state");
53041 var wasUpdating = layout.isUpdating();
53043 layout.beginUpdate();
53045 for(var key in state){
53046 if(typeof state[key] != "function"){
53047 var rstate = state[key];
53048 var r = layout.getRegion(key);
53051 r.resizeTo(rstate.size);
53053 if(rstate.collapsed == true){
53056 r.expand(null, true);
53062 layout.endUpdate();
53064 this.state = state;
53066 this.layout = layout;
53067 layout.on("regionresized", this.onRegionResized, this);
53068 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53069 layout.on("regionexpanded", this.onRegionExpanded, this);
53072 storeState : function(){
53073 this.provider.set(this.layout.id+"-layout-state", this.state);
53076 onRegionResized : function(region, newSize){
53077 this.state[region.getPosition()].size = newSize;
53081 onRegionCollapsed : function(region){
53082 this.state[region.getPosition()].collapsed = true;
53086 onRegionExpanded : function(region){
53087 this.state[region.getPosition()].collapsed = false;
53092 * Ext JS Library 1.1.1
53093 * Copyright(c) 2006-2007, Ext JS, LLC.
53095 * Originally Released Under LGPL - original licence link has changed is not relivant.
53098 * <script type="text/javascript">
53101 * @class Roo.ContentPanel
53102 * @extends Roo.util.Observable
53103 * A basic ContentPanel element.
53104 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53105 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53106 * @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
53107 * @cfg {Boolean} closable True if the panel can be closed/removed
53108 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53109 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53110 * @cfg {Toolbar} toolbar A toolbar for this panel
53111 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53112 * @cfg {String} title The title for this panel
53113 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53114 * @cfg {String} url Calls {@link #setUrl} with this value
53115 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53116 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53117 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53118 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53121 * Create a new ContentPanel.
53122 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53123 * @param {String/Object} config A string to set only the title or a config object
53124 * @param {String} content (optional) Set the HTML content for this panel
53125 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53127 Roo.ContentPanel = function(el, config, content){
53131 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53135 if (config && config.parentLayout) {
53136 el = config.parentLayout.el.createChild();
53139 if(el.autoCreate){ // xtype is available if this is called from factory
53143 this.el = Roo.get(el);
53144 if(!this.el && config && config.autoCreate){
53145 if(typeof config.autoCreate == "object"){
53146 if(!config.autoCreate.id){
53147 config.autoCreate.id = config.id||el;
53149 this.el = Roo.DomHelper.append(document.body,
53150 config.autoCreate, true);
53152 this.el = Roo.DomHelper.append(document.body,
53153 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53156 this.closable = false;
53157 this.loaded = false;
53158 this.active = false;
53159 if(typeof config == "string"){
53160 this.title = config;
53162 Roo.apply(this, config);
53165 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53166 this.wrapEl = this.el.wrap();
53167 this.toolbar.container = this.el.insertSibling(false, 'before');
53168 this.toolbar = new Roo.Toolbar(this.toolbar);
53171 // xtype created footer. - not sure if will work as we normally have to render first..
53172 if (this.footer && !this.footer.el && this.footer.xtype) {
53173 if (!this.wrapEl) {
53174 this.wrapEl = this.el.wrap();
53177 this.footer.container = this.wrapEl.createChild();
53179 this.footer = Roo.factory(this.footer, Roo);
53184 this.resizeEl = Roo.get(this.resizeEl, true);
53186 this.resizeEl = this.el;
53188 // handle view.xtype
53196 * Fires when this panel is activated.
53197 * @param {Roo.ContentPanel} this
53201 * @event deactivate
53202 * Fires when this panel is activated.
53203 * @param {Roo.ContentPanel} this
53205 "deactivate" : true,
53209 * Fires when this panel is resized if fitToFrame is true.
53210 * @param {Roo.ContentPanel} this
53211 * @param {Number} width The width after any component adjustments
53212 * @param {Number} height The height after any component adjustments
53218 * Fires when this tab is created
53219 * @param {Roo.ContentPanel} this
53230 if(this.autoScroll){
53231 this.resizeEl.setStyle("overflow", "auto");
53233 // fix randome scrolling
53234 this.el.on('scroll', function() {
53235 Roo.log('fix random scolling');
53236 this.scrollTo('top',0);
53239 content = content || this.content;
53241 this.setContent(content);
53243 if(config && config.url){
53244 this.setUrl(this.url, this.params, this.loadOnce);
53249 Roo.ContentPanel.superclass.constructor.call(this);
53251 if (this.view && typeof(this.view.xtype) != 'undefined') {
53252 this.view.el = this.el.appendChild(document.createElement("div"));
53253 this.view = Roo.factory(this.view);
53254 this.view.render && this.view.render(false, '');
53258 this.fireEvent('render', this);
53261 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53263 setRegion : function(region){
53264 this.region = region;
53266 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53268 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53273 * Returns the toolbar for this Panel if one was configured.
53274 * @return {Roo.Toolbar}
53276 getToolbar : function(){
53277 return this.toolbar;
53280 setActiveState : function(active){
53281 this.active = active;
53283 this.fireEvent("deactivate", this);
53285 this.fireEvent("activate", this);
53289 * Updates this panel's element
53290 * @param {String} content The new content
53291 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53293 setContent : function(content, loadScripts){
53294 this.el.update(content, loadScripts);
53297 ignoreResize : function(w, h){
53298 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53301 this.lastSize = {width: w, height: h};
53306 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53307 * @return {Roo.UpdateManager} The UpdateManager
53309 getUpdateManager : function(){
53310 return this.el.getUpdateManager();
53313 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53314 * @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:
53317 url: "your-url.php",
53318 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53319 callback: yourFunction,
53320 scope: yourObject, //(optional scope)
53323 text: "Loading...",
53328 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53329 * 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.
53330 * @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}
53331 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53332 * @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.
53333 * @return {Roo.ContentPanel} this
53336 var um = this.el.getUpdateManager();
53337 um.update.apply(um, arguments);
53343 * 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.
53344 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53345 * @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)
53346 * @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)
53347 * @return {Roo.UpdateManager} The UpdateManager
53349 setUrl : function(url, params, loadOnce){
53350 if(this.refreshDelegate){
53351 this.removeListener("activate", this.refreshDelegate);
53353 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53354 this.on("activate", this.refreshDelegate);
53355 return this.el.getUpdateManager();
53358 _handleRefresh : function(url, params, loadOnce){
53359 if(!loadOnce || !this.loaded){
53360 var updater = this.el.getUpdateManager();
53361 updater.update(url, params, this._setLoaded.createDelegate(this));
53365 _setLoaded : function(){
53366 this.loaded = true;
53370 * Returns this panel's id
53373 getId : function(){
53378 * Returns this panel's element - used by regiosn to add.
53379 * @return {Roo.Element}
53381 getEl : function(){
53382 return this.wrapEl || this.el;
53385 adjustForComponents : function(width, height)
53387 //Roo.log('adjustForComponents ');
53388 if(this.resizeEl != this.el){
53389 width -= this.el.getFrameWidth('lr');
53390 height -= this.el.getFrameWidth('tb');
53393 var te = this.toolbar.getEl();
53394 height -= te.getHeight();
53395 te.setWidth(width);
53398 var te = this.footer.getEl();
53399 Roo.log("footer:" + te.getHeight());
53401 height -= te.getHeight();
53402 te.setWidth(width);
53406 if(this.adjustments){
53407 width += this.adjustments[0];
53408 height += this.adjustments[1];
53410 return {"width": width, "height": height};
53413 setSize : function(width, height){
53414 if(this.fitToFrame && !this.ignoreResize(width, height)){
53415 if(this.fitContainer && this.resizeEl != this.el){
53416 this.el.setSize(width, height);
53418 var size = this.adjustForComponents(width, height);
53419 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53420 this.fireEvent('resize', this, size.width, size.height);
53425 * Returns this panel's title
53428 getTitle : function(){
53433 * Set this panel's title
53434 * @param {String} title
53436 setTitle : function(title){
53437 this.title = title;
53439 this.region.updatePanelTitle(this, title);
53444 * Returns true is this panel was configured to be closable
53445 * @return {Boolean}
53447 isClosable : function(){
53448 return this.closable;
53451 beforeSlide : function(){
53453 this.resizeEl.clip();
53456 afterSlide : function(){
53458 this.resizeEl.unclip();
53462 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53463 * Will fail silently if the {@link #setUrl} method has not been called.
53464 * This does not activate the panel, just updates its content.
53466 refresh : function(){
53467 if(this.refreshDelegate){
53468 this.loaded = false;
53469 this.refreshDelegate();
53474 * Destroys this panel
53476 destroy : function(){
53477 this.el.removeAllListeners();
53478 var tempEl = document.createElement("span");
53479 tempEl.appendChild(this.el.dom);
53480 tempEl.innerHTML = "";
53486 * form - if the content panel contains a form - this is a reference to it.
53487 * @type {Roo.form.Form}
53491 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53492 * This contains a reference to it.
53498 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53508 * @param {Object} cfg Xtype definition of item to add.
53511 addxtype : function(cfg) {
53513 if (cfg.xtype.match(/^Form$/)) {
53516 //if (this.footer) {
53517 // el = this.footer.container.insertSibling(false, 'before');
53519 el = this.el.createChild();
53522 this.form = new Roo.form.Form(cfg);
53525 if ( this.form.allItems.length) {
53526 this.form.render(el.dom);
53530 // should only have one of theses..
53531 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53532 // views.. should not be just added - used named prop 'view''
53534 cfg.el = this.el.appendChild(document.createElement("div"));
53537 var ret = new Roo.factory(cfg);
53539 ret.render && ret.render(false, ''); // render blank..
53548 * @class Roo.GridPanel
53549 * @extends Roo.ContentPanel
53551 * Create a new GridPanel.
53552 * @param {Roo.grid.Grid} grid The grid for this panel
53553 * @param {String/Object} config A string to set only the panel's title, or a config object
53555 Roo.GridPanel = function(grid, config){
53558 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53559 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53561 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53563 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53566 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53568 // xtype created footer. - not sure if will work as we normally have to render first..
53569 if (this.footer && !this.footer.el && this.footer.xtype) {
53571 this.footer.container = this.grid.getView().getFooterPanel(true);
53572 this.footer.dataSource = this.grid.dataSource;
53573 this.footer = Roo.factory(this.footer, Roo);
53577 grid.monitorWindowResize = false; // turn off autosizing
53578 grid.autoHeight = false;
53579 grid.autoWidth = false;
53581 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53584 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53585 getId : function(){
53586 return this.grid.id;
53590 * Returns the grid for this panel
53591 * @return {Roo.grid.Grid}
53593 getGrid : function(){
53597 setSize : function(width, height){
53598 if(!this.ignoreResize(width, height)){
53599 var grid = this.grid;
53600 var size = this.adjustForComponents(width, height);
53601 grid.getGridEl().setSize(size.width, size.height);
53606 beforeSlide : function(){
53607 this.grid.getView().scroller.clip();
53610 afterSlide : function(){
53611 this.grid.getView().scroller.unclip();
53614 destroy : function(){
53615 this.grid.destroy();
53617 Roo.GridPanel.superclass.destroy.call(this);
53623 * @class Roo.NestedLayoutPanel
53624 * @extends Roo.ContentPanel
53626 * Create a new NestedLayoutPanel.
53629 * @param {Roo.BorderLayout} layout The layout for this panel
53630 * @param {String/Object} config A string to set only the title or a config object
53632 Roo.NestedLayoutPanel = function(layout, config)
53634 // construct with only one argument..
53635 /* FIXME - implement nicer consturctors
53636 if (layout.layout) {
53638 layout = config.layout;
53639 delete config.layout;
53641 if (layout.xtype && !layout.getEl) {
53642 // then layout needs constructing..
53643 layout = Roo.factory(layout, Roo);
53648 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53650 layout.monitorWindowResize = false; // turn off autosizing
53651 this.layout = layout;
53652 this.layout.getEl().addClass("x-layout-nested-layout");
53659 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53661 setSize : function(width, height){
53662 if(!this.ignoreResize(width, height)){
53663 var size = this.adjustForComponents(width, height);
53664 var el = this.layout.getEl();
53665 el.setSize(size.width, size.height);
53666 var touch = el.dom.offsetWidth;
53667 this.layout.layout();
53668 // ie requires a double layout on the first pass
53669 if(Roo.isIE && !this.initialized){
53670 this.initialized = true;
53671 this.layout.layout();
53676 // activate all subpanels if not currently active..
53678 setActiveState : function(active){
53679 this.active = active;
53681 this.fireEvent("deactivate", this);
53685 this.fireEvent("activate", this);
53686 // not sure if this should happen before or after..
53687 if (!this.layout) {
53688 return; // should not happen..
53691 for (var r in this.layout.regions) {
53692 reg = this.layout.getRegion(r);
53693 if (reg.getActivePanel()) {
53694 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53695 reg.setActivePanel(reg.getActivePanel());
53698 if (!reg.panels.length) {
53701 reg.showPanel(reg.getPanel(0));
53710 * Returns the nested BorderLayout for this panel
53711 * @return {Roo.BorderLayout}
53713 getLayout : function(){
53714 return this.layout;
53718 * Adds a xtype elements to the layout of the nested panel
53722 xtype : 'ContentPanel',
53729 xtype : 'NestedLayoutPanel',
53735 items : [ ... list of content panels or nested layout panels.. ]
53739 * @param {Object} cfg Xtype definition of item to add.
53741 addxtype : function(cfg) {
53742 return this.layout.addxtype(cfg);
53747 Roo.ScrollPanel = function(el, config, content){
53748 config = config || {};
53749 config.fitToFrame = true;
53750 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53752 this.el.dom.style.overflow = "hidden";
53753 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53754 this.el.removeClass("x-layout-inactive-content");
53755 this.el.on("mousewheel", this.onWheel, this);
53757 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53758 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53759 up.unselectable(); down.unselectable();
53760 up.on("click", this.scrollUp, this);
53761 down.on("click", this.scrollDown, this);
53762 up.addClassOnOver("x-scroller-btn-over");
53763 down.addClassOnOver("x-scroller-btn-over");
53764 up.addClassOnClick("x-scroller-btn-click");
53765 down.addClassOnClick("x-scroller-btn-click");
53766 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53768 this.resizeEl = this.el;
53769 this.el = wrap; this.up = up; this.down = down;
53772 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53774 wheelIncrement : 5,
53775 scrollUp : function(){
53776 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53779 scrollDown : function(){
53780 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53783 afterScroll : function(){
53784 var el = this.resizeEl;
53785 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53786 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53787 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53790 setSize : function(){
53791 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53792 this.afterScroll();
53795 onWheel : function(e){
53796 var d = e.getWheelDelta();
53797 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53798 this.afterScroll();
53802 setContent : function(content, loadScripts){
53803 this.resizeEl.update(content, loadScripts);
53817 * @class Roo.TreePanel
53818 * @extends Roo.ContentPanel
53820 * Create a new TreePanel. - defaults to fit/scoll contents.
53821 * @param {String/Object} config A string to set only the panel's title, or a config object
53822 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53824 Roo.TreePanel = function(config){
53825 var el = config.el;
53826 var tree = config.tree;
53827 delete config.tree;
53828 delete config.el; // hopefull!
53830 // wrapper for IE7 strict & safari scroll issue
53832 var treeEl = el.createChild();
53833 config.resizeEl = treeEl;
53837 Roo.TreePanel.superclass.constructor.call(this, el, config);
53840 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53841 //console.log(tree);
53842 this.on('activate', function()
53844 if (this.tree.rendered) {
53847 //console.log('render tree');
53848 this.tree.render();
53850 // this should not be needed.. - it's actually the 'el' that resizes?
53851 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53853 //this.on('resize', function (cp, w, h) {
53854 // this.tree.innerCt.setWidth(w);
53855 // this.tree.innerCt.setHeight(h);
53856 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53863 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53880 * Ext JS Library 1.1.1
53881 * Copyright(c) 2006-2007, Ext JS, LLC.
53883 * Originally Released Under LGPL - original licence link has changed is not relivant.
53886 * <script type="text/javascript">
53891 * @class Roo.ReaderLayout
53892 * @extends Roo.BorderLayout
53893 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53894 * center region containing two nested regions (a top one for a list view and one for item preview below),
53895 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53896 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53897 * expedites the setup of the overall layout and regions for this common application style.
53900 var reader = new Roo.ReaderLayout();
53901 var CP = Roo.ContentPanel; // shortcut for adding
53903 reader.beginUpdate();
53904 reader.add("north", new CP("north", "North"));
53905 reader.add("west", new CP("west", {title: "West"}));
53906 reader.add("east", new CP("east", {title: "East"}));
53908 reader.regions.listView.add(new CP("listView", "List"));
53909 reader.regions.preview.add(new CP("preview", "Preview"));
53910 reader.endUpdate();
53913 * Create a new ReaderLayout
53914 * @param {Object} config Configuration options
53915 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53916 * document.body if omitted)
53918 Roo.ReaderLayout = function(config, renderTo){
53919 var c = config || {size:{}};
53920 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53921 north: c.north !== false ? Roo.apply({
53925 }, c.north) : false,
53926 west: c.west !== false ? Roo.apply({
53934 margins:{left:5,right:0,bottom:5,top:5},
53935 cmargins:{left:5,right:5,bottom:5,top:5}
53936 }, c.west) : false,
53937 east: c.east !== false ? Roo.apply({
53945 margins:{left:0,right:5,bottom:5,top:5},
53946 cmargins:{left:5,right:5,bottom:5,top:5}
53947 }, c.east) : false,
53948 center: Roo.apply({
53949 tabPosition: 'top',
53953 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53957 this.el.addClass('x-reader');
53959 this.beginUpdate();
53961 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53962 south: c.preview !== false ? Roo.apply({
53969 cmargins:{top:5,left:0, right:0, bottom:0}
53970 }, c.preview) : false,
53971 center: Roo.apply({
53977 this.add('center', new Roo.NestedLayoutPanel(inner,
53978 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53982 this.regions.preview = inner.getRegion('south');
53983 this.regions.listView = inner.getRegion('center');
53986 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53988 * Ext JS Library 1.1.1
53989 * Copyright(c) 2006-2007, Ext JS, LLC.
53991 * Originally Released Under LGPL - original licence link has changed is not relivant.
53994 * <script type="text/javascript">
53998 * @class Roo.grid.Grid
53999 * @extends Roo.util.Observable
54000 * This class represents the primary interface of a component based grid control.
54001 * <br><br>Usage:<pre><code>
54002 var grid = new Roo.grid.Grid("my-container-id", {
54005 selModel: mySelectionModel,
54006 autoSizeColumns: true,
54007 monitorWindowResize: false,
54008 trackMouseOver: true
54013 * <b>Common Problems:</b><br/>
54014 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54015 * element will correct this<br/>
54016 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54017 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54018 * are unpredictable.<br/>
54019 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54020 * grid to calculate dimensions/offsets.<br/>
54022 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54023 * The container MUST have some type of size defined for the grid to fill. The container will be
54024 * automatically set to position relative if it isn't already.
54025 * @param {Object} config A config object that sets properties on this grid.
54027 Roo.grid.Grid = function(container, config){
54028 // initialize the container
54029 this.container = Roo.get(container);
54030 this.container.update("");
54031 this.container.setStyle("overflow", "hidden");
54032 this.container.addClass('x-grid-container');
54034 this.id = this.container.id;
54036 Roo.apply(this, config);
54037 // check and correct shorthanded configs
54039 this.dataSource = this.ds;
54043 this.colModel = this.cm;
54047 this.selModel = this.sm;
54051 if (this.selModel) {
54052 this.selModel = Roo.factory(this.selModel, Roo.grid);
54053 this.sm = this.selModel;
54054 this.sm.xmodule = this.xmodule || false;
54056 if (typeof(this.colModel.config) == 'undefined') {
54057 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54058 this.cm = this.colModel;
54059 this.cm.xmodule = this.xmodule || false;
54061 if (this.dataSource) {
54062 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54063 this.ds = this.dataSource;
54064 this.ds.xmodule = this.xmodule || false;
54071 this.container.setWidth(this.width);
54075 this.container.setHeight(this.height);
54082 * The raw click event for the entire grid.
54083 * @param {Roo.EventObject} e
54088 * The raw dblclick event for the entire grid.
54089 * @param {Roo.EventObject} e
54093 * @event contextmenu
54094 * The raw contextmenu event for the entire grid.
54095 * @param {Roo.EventObject} e
54097 "contextmenu" : true,
54100 * The raw mousedown event for the entire grid.
54101 * @param {Roo.EventObject} e
54103 "mousedown" : true,
54106 * The raw mouseup event for the entire grid.
54107 * @param {Roo.EventObject} e
54112 * The raw mouseover event for the entire grid.
54113 * @param {Roo.EventObject} e
54115 "mouseover" : true,
54118 * The raw mouseout event for the entire grid.
54119 * @param {Roo.EventObject} e
54124 * The raw keypress event for the entire grid.
54125 * @param {Roo.EventObject} e
54130 * The raw keydown event for the entire grid.
54131 * @param {Roo.EventObject} e
54139 * Fires when a cell is clicked
54140 * @param {Grid} this
54141 * @param {Number} rowIndex
54142 * @param {Number} columnIndex
54143 * @param {Roo.EventObject} e
54145 "cellclick" : true,
54147 * @event celldblclick
54148 * Fires when a cell is double clicked
54149 * @param {Grid} this
54150 * @param {Number} rowIndex
54151 * @param {Number} columnIndex
54152 * @param {Roo.EventObject} e
54154 "celldblclick" : true,
54157 * Fires when a row is clicked
54158 * @param {Grid} this
54159 * @param {Number} rowIndex
54160 * @param {Roo.EventObject} e
54164 * @event rowdblclick
54165 * Fires when a row is double clicked
54166 * @param {Grid} this
54167 * @param {Number} rowIndex
54168 * @param {Roo.EventObject} e
54170 "rowdblclick" : true,
54172 * @event headerclick
54173 * Fires when a header is clicked
54174 * @param {Grid} this
54175 * @param {Number} columnIndex
54176 * @param {Roo.EventObject} e
54178 "headerclick" : true,
54180 * @event headerdblclick
54181 * Fires when a header cell is double clicked
54182 * @param {Grid} this
54183 * @param {Number} columnIndex
54184 * @param {Roo.EventObject} e
54186 "headerdblclick" : true,
54188 * @event rowcontextmenu
54189 * Fires when a row is right clicked
54190 * @param {Grid} this
54191 * @param {Number} rowIndex
54192 * @param {Roo.EventObject} e
54194 "rowcontextmenu" : true,
54196 * @event cellcontextmenu
54197 * Fires when a cell is right clicked
54198 * @param {Grid} this
54199 * @param {Number} rowIndex
54200 * @param {Number} cellIndex
54201 * @param {Roo.EventObject} e
54203 "cellcontextmenu" : true,
54205 * @event headercontextmenu
54206 * Fires when a header is right clicked
54207 * @param {Grid} this
54208 * @param {Number} columnIndex
54209 * @param {Roo.EventObject} e
54211 "headercontextmenu" : true,
54213 * @event bodyscroll
54214 * Fires when the body element is scrolled
54215 * @param {Number} scrollLeft
54216 * @param {Number} scrollTop
54218 "bodyscroll" : true,
54220 * @event columnresize
54221 * Fires when the user resizes a column
54222 * @param {Number} columnIndex
54223 * @param {Number} newSize
54225 "columnresize" : true,
54227 * @event columnmove
54228 * Fires when the user moves a column
54229 * @param {Number} oldIndex
54230 * @param {Number} newIndex
54232 "columnmove" : true,
54235 * Fires when row(s) start being dragged
54236 * @param {Grid} this
54237 * @param {Roo.GridDD} dd The drag drop object
54238 * @param {event} e The raw browser event
54240 "startdrag" : true,
54243 * Fires when a drag operation is complete
54244 * @param {Grid} this
54245 * @param {Roo.GridDD} dd The drag drop object
54246 * @param {event} e The raw browser event
54251 * Fires when dragged row(s) are dropped on a valid DD target
54252 * @param {Grid} this
54253 * @param {Roo.GridDD} dd The drag drop object
54254 * @param {String} targetId The target drag drop object
54255 * @param {event} e The raw browser event
54260 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54261 * @param {Grid} this
54262 * @param {Roo.GridDD} dd The drag drop object
54263 * @param {String} targetId The target drag drop object
54264 * @param {event} e The raw browser event
54269 * Fires when the dragged row(s) first cross another DD target while being dragged
54270 * @param {Grid} this
54271 * @param {Roo.GridDD} dd The drag drop object
54272 * @param {String} targetId The target drag drop object
54273 * @param {event} e The raw browser event
54275 "dragenter" : true,
54278 * Fires when the dragged row(s) leave another DD target while being dragged
54279 * @param {Grid} this
54280 * @param {Roo.GridDD} dd The drag drop object
54281 * @param {String} targetId The target drag drop object
54282 * @param {event} e The raw browser event
54287 * Fires when a row is rendered, so you can change add a style to it.
54288 * @param {GridView} gridview The grid view
54289 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54295 * Fires when the grid is rendered
54296 * @param {Grid} grid
54301 Roo.grid.Grid.superclass.constructor.call(this);
54303 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54306 * @cfg {String} ddGroup - drag drop group.
54310 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54312 minColumnWidth : 25,
54315 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54316 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54317 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54319 autoSizeColumns : false,
54322 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54324 autoSizeHeaders : true,
54327 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54329 monitorWindowResize : true,
54332 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54333 * rows measured to get a columns size. Default is 0 (all rows).
54335 maxRowsToMeasure : 0,
54338 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54340 trackMouseOver : true,
54343 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54347 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54349 enableDragDrop : false,
54352 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54354 enableColumnMove : true,
54357 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54359 enableColumnHide : true,
54362 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54364 enableRowHeightSync : false,
54367 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54372 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54374 autoHeight : false,
54377 * @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.
54379 autoExpandColumn : false,
54382 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54385 autoExpandMin : 50,
54388 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54390 autoExpandMax : 1000,
54393 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54398 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54402 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54412 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54413 * of a fixed width. Default is false.
54416 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54419 * Called once after all setup has been completed and the grid is ready to be rendered.
54420 * @return {Roo.grid.Grid} this
54422 render : function()
54424 var c = this.container;
54425 // try to detect autoHeight/width mode
54426 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54427 this.autoHeight = true;
54429 var view = this.getView();
54432 c.on("click", this.onClick, this);
54433 c.on("dblclick", this.onDblClick, this);
54434 c.on("contextmenu", this.onContextMenu, this);
54435 c.on("keydown", this.onKeyDown, this);
54437 c.on("touchstart", this.onTouchStart, this);
54440 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54442 this.getSelectionModel().init(this);
54447 this.loadMask = new Roo.LoadMask(this.container,
54448 Roo.apply({store:this.dataSource}, this.loadMask));
54452 if (this.toolbar && this.toolbar.xtype) {
54453 this.toolbar.container = this.getView().getHeaderPanel(true);
54454 this.toolbar = new Roo.Toolbar(this.toolbar);
54456 if (this.footer && this.footer.xtype) {
54457 this.footer.dataSource = this.getDataSource();
54458 this.footer.container = this.getView().getFooterPanel(true);
54459 this.footer = Roo.factory(this.footer, Roo);
54461 if (this.dropTarget && this.dropTarget.xtype) {
54462 delete this.dropTarget.xtype;
54463 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54467 this.rendered = true;
54468 this.fireEvent('render', this);
54473 * Reconfigures the grid to use a different Store and Column Model.
54474 * The View will be bound to the new objects and refreshed.
54475 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54476 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54478 reconfigure : function(dataSource, colModel){
54480 this.loadMask.destroy();
54481 this.loadMask = new Roo.LoadMask(this.container,
54482 Roo.apply({store:dataSource}, this.loadMask));
54484 this.view.bind(dataSource, colModel);
54485 this.dataSource = dataSource;
54486 this.colModel = colModel;
54487 this.view.refresh(true);
54491 onKeyDown : function(e){
54492 this.fireEvent("keydown", e);
54496 * Destroy this grid.
54497 * @param {Boolean} removeEl True to remove the element
54499 destroy : function(removeEl, keepListeners){
54501 this.loadMask.destroy();
54503 var c = this.container;
54504 c.removeAllListeners();
54505 this.view.destroy();
54506 this.colModel.purgeListeners();
54507 if(!keepListeners){
54508 this.purgeListeners();
54511 if(removeEl === true){
54517 processEvent : function(name, e){
54518 // does this fire select???
54519 //Roo.log('grid:processEvent ' + name);
54521 if (name != 'touchstart' ) {
54522 this.fireEvent(name, e);
54525 var t = e.getTarget();
54527 var header = v.findHeaderIndex(t);
54528 if(header !== false){
54529 var ename = name == 'touchstart' ? 'click' : name;
54531 this.fireEvent("header" + ename, this, header, e);
54533 var row = v.findRowIndex(t);
54534 var cell = v.findCellIndex(t);
54535 if (name == 'touchstart') {
54536 // first touch is always a click.
54537 // hopefull this happens after selection is updated.?
54540 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54541 var cs = this.selModel.getSelectedCell();
54542 if (row == cs[0] && cell == cs[1]){
54546 if (typeof(this.selModel.getSelections) != 'undefined') {
54547 var cs = this.selModel.getSelections();
54548 var ds = this.dataSource;
54549 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54560 this.fireEvent("row" + name, this, row, e);
54561 if(cell !== false){
54562 this.fireEvent("cell" + name, this, row, cell, e);
54569 onClick : function(e){
54570 this.processEvent("click", e);
54573 onTouchStart : function(e){
54574 this.processEvent("touchstart", e);
54578 onContextMenu : function(e, t){
54579 this.processEvent("contextmenu", e);
54583 onDblClick : function(e){
54584 this.processEvent("dblclick", e);
54588 walkCells : function(row, col, step, fn, scope){
54589 var cm = this.colModel, clen = cm.getColumnCount();
54590 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54602 if(fn.call(scope || this, row, col, cm) === true){
54620 if(fn.call(scope || this, row, col, cm) === true){
54632 getSelections : function(){
54633 return this.selModel.getSelections();
54637 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54638 * but if manual update is required this method will initiate it.
54640 autoSize : function(){
54642 this.view.layout();
54643 if(this.view.adjustForScroll){
54644 this.view.adjustForScroll();
54650 * Returns the grid's underlying element.
54651 * @return {Element} The element
54653 getGridEl : function(){
54654 return this.container;
54657 // private for compatibility, overridden by editor grid
54658 stopEditing : function(){},
54661 * Returns the grid's SelectionModel.
54662 * @return {SelectionModel}
54664 getSelectionModel : function(){
54665 if(!this.selModel){
54666 this.selModel = new Roo.grid.RowSelectionModel();
54668 return this.selModel;
54672 * Returns the grid's DataSource.
54673 * @return {DataSource}
54675 getDataSource : function(){
54676 return this.dataSource;
54680 * Returns the grid's ColumnModel.
54681 * @return {ColumnModel}
54683 getColumnModel : function(){
54684 return this.colModel;
54688 * Returns the grid's GridView object.
54689 * @return {GridView}
54691 getView : function(){
54693 this.view = new Roo.grid.GridView(this.viewConfig);
54698 * Called to get grid's drag proxy text, by default returns this.ddText.
54701 getDragDropText : function(){
54702 var count = this.selModel.getCount();
54703 return String.format(this.ddText, count, count == 1 ? '' : 's');
54707 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54708 * %0 is replaced with the number of selected rows.
54711 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54713 * Ext JS Library 1.1.1
54714 * Copyright(c) 2006-2007, Ext JS, LLC.
54716 * Originally Released Under LGPL - original licence link has changed is not relivant.
54719 * <script type="text/javascript">
54722 Roo.grid.AbstractGridView = function(){
54726 "beforerowremoved" : true,
54727 "beforerowsinserted" : true,
54728 "beforerefresh" : true,
54729 "rowremoved" : true,
54730 "rowsinserted" : true,
54731 "rowupdated" : true,
54734 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54737 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54738 rowClass : "x-grid-row",
54739 cellClass : "x-grid-cell",
54740 tdClass : "x-grid-td",
54741 hdClass : "x-grid-hd",
54742 splitClass : "x-grid-hd-split",
54744 init: function(grid){
54746 var cid = this.grid.getGridEl().id;
54747 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54748 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54749 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54750 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54753 getColumnRenderers : function(){
54754 var renderers = [];
54755 var cm = this.grid.colModel;
54756 var colCount = cm.getColumnCount();
54757 for(var i = 0; i < colCount; i++){
54758 renderers[i] = cm.getRenderer(i);
54763 getColumnIds : function(){
54765 var cm = this.grid.colModel;
54766 var colCount = cm.getColumnCount();
54767 for(var i = 0; i < colCount; i++){
54768 ids[i] = cm.getColumnId(i);
54773 getDataIndexes : function(){
54774 if(!this.indexMap){
54775 this.indexMap = this.buildIndexMap();
54777 return this.indexMap.colToData;
54780 getColumnIndexByDataIndex : function(dataIndex){
54781 if(!this.indexMap){
54782 this.indexMap = this.buildIndexMap();
54784 return this.indexMap.dataToCol[dataIndex];
54788 * Set a css style for a column dynamically.
54789 * @param {Number} colIndex The index of the column
54790 * @param {String} name The css property name
54791 * @param {String} value The css value
54793 setCSSStyle : function(colIndex, name, value){
54794 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54795 Roo.util.CSS.updateRule(selector, name, value);
54798 generateRules : function(cm){
54799 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54800 Roo.util.CSS.removeStyleSheet(rulesId);
54801 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54802 var cid = cm.getColumnId(i);
54803 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54804 this.tdSelector, cid, " {\n}\n",
54805 this.hdSelector, cid, " {\n}\n",
54806 this.splitSelector, cid, " {\n}\n");
54808 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54812 * Ext JS Library 1.1.1
54813 * Copyright(c) 2006-2007, Ext JS, LLC.
54815 * Originally Released Under LGPL - original licence link has changed is not relivant.
54818 * <script type="text/javascript">
54822 // This is a support class used internally by the Grid components
54823 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54825 this.view = grid.getView();
54826 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54827 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54829 this.setHandleElId(Roo.id(hd));
54830 this.setOuterHandleElId(Roo.id(hd2));
54832 this.scroll = false;
54834 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54836 getDragData : function(e){
54837 var t = Roo.lib.Event.getTarget(e);
54838 var h = this.view.findHeaderCell(t);
54840 return {ddel: h.firstChild, header:h};
54845 onInitDrag : function(e){
54846 this.view.headersDisabled = true;
54847 var clone = this.dragData.ddel.cloneNode(true);
54848 clone.id = Roo.id();
54849 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54850 this.proxy.update(clone);
54854 afterValidDrop : function(){
54856 setTimeout(function(){
54857 v.headersDisabled = false;
54861 afterInvalidDrop : function(){
54863 setTimeout(function(){
54864 v.headersDisabled = false;
54870 * Ext JS Library 1.1.1
54871 * Copyright(c) 2006-2007, Ext JS, LLC.
54873 * Originally Released Under LGPL - original licence link has changed is not relivant.
54876 * <script type="text/javascript">
54879 // This is a support class used internally by the Grid components
54880 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54882 this.view = grid.getView();
54883 // split the proxies so they don't interfere with mouse events
54884 this.proxyTop = Roo.DomHelper.append(document.body, {
54885 cls:"col-move-top", html:" "
54887 this.proxyBottom = Roo.DomHelper.append(document.body, {
54888 cls:"col-move-bottom", html:" "
54890 this.proxyTop.hide = this.proxyBottom.hide = function(){
54891 this.setLeftTop(-100,-100);
54892 this.setStyle("visibility", "hidden");
54894 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54895 // temporarily disabled
54896 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54897 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54899 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54900 proxyOffsets : [-4, -9],
54901 fly: Roo.Element.fly,
54903 getTargetFromEvent : function(e){
54904 var t = Roo.lib.Event.getTarget(e);
54905 var cindex = this.view.findCellIndex(t);
54906 if(cindex !== false){
54907 return this.view.getHeaderCell(cindex);
54912 nextVisible : function(h){
54913 var v = this.view, cm = this.grid.colModel;
54916 if(!cm.isHidden(v.getCellIndex(h))){
54924 prevVisible : function(h){
54925 var v = this.view, cm = this.grid.colModel;
54928 if(!cm.isHidden(v.getCellIndex(h))){
54936 positionIndicator : function(h, n, e){
54937 var x = Roo.lib.Event.getPageX(e);
54938 var r = Roo.lib.Dom.getRegion(n.firstChild);
54939 var px, pt, py = r.top + this.proxyOffsets[1];
54940 if((r.right - x) <= (r.right-r.left)/2){
54941 px = r.right+this.view.borderWidth;
54947 var oldIndex = this.view.getCellIndex(h);
54948 var newIndex = this.view.getCellIndex(n);
54950 if(this.grid.colModel.isFixed(newIndex)){
54954 var locked = this.grid.colModel.isLocked(newIndex);
54959 if(oldIndex < newIndex){
54962 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54965 px += this.proxyOffsets[0];
54966 this.proxyTop.setLeftTop(px, py);
54967 this.proxyTop.show();
54968 if(!this.bottomOffset){
54969 this.bottomOffset = this.view.mainHd.getHeight();
54971 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54972 this.proxyBottom.show();
54976 onNodeEnter : function(n, dd, e, data){
54977 if(data.header != n){
54978 this.positionIndicator(data.header, n, e);
54982 onNodeOver : function(n, dd, e, data){
54983 var result = false;
54984 if(data.header != n){
54985 result = this.positionIndicator(data.header, n, e);
54988 this.proxyTop.hide();
54989 this.proxyBottom.hide();
54991 return result ? this.dropAllowed : this.dropNotAllowed;
54994 onNodeOut : function(n, dd, e, data){
54995 this.proxyTop.hide();
54996 this.proxyBottom.hide();
54999 onNodeDrop : function(n, dd, e, data){
55000 var h = data.header;
55002 var cm = this.grid.colModel;
55003 var x = Roo.lib.Event.getPageX(e);
55004 var r = Roo.lib.Dom.getRegion(n.firstChild);
55005 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55006 var oldIndex = this.view.getCellIndex(h);
55007 var newIndex = this.view.getCellIndex(n);
55008 var locked = cm.isLocked(newIndex);
55012 if(oldIndex < newIndex){
55015 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55018 cm.setLocked(oldIndex, locked, true);
55019 cm.moveColumn(oldIndex, newIndex);
55020 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55028 * Ext JS Library 1.1.1
55029 * Copyright(c) 2006-2007, Ext JS, LLC.
55031 * Originally Released Under LGPL - original licence link has changed is not relivant.
55034 * <script type="text/javascript">
55038 * @class Roo.grid.GridView
55039 * @extends Roo.util.Observable
55042 * @param {Object} config
55044 Roo.grid.GridView = function(config){
55045 Roo.grid.GridView.superclass.constructor.call(this);
55048 Roo.apply(this, config);
55051 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55053 unselectable : 'unselectable="on"',
55054 unselectableCls : 'x-unselectable',
55057 rowClass : "x-grid-row",
55059 cellClass : "x-grid-col",
55061 tdClass : "x-grid-td",
55063 hdClass : "x-grid-hd",
55065 splitClass : "x-grid-split",
55067 sortClasses : ["sort-asc", "sort-desc"],
55069 enableMoveAnim : false,
55073 dh : Roo.DomHelper,
55075 fly : Roo.Element.fly,
55077 css : Roo.util.CSS,
55083 scrollIncrement : 22,
55085 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55087 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55089 bind : function(ds, cm){
55091 this.ds.un("load", this.onLoad, this);
55092 this.ds.un("datachanged", this.onDataChange, this);
55093 this.ds.un("add", this.onAdd, this);
55094 this.ds.un("remove", this.onRemove, this);
55095 this.ds.un("update", this.onUpdate, this);
55096 this.ds.un("clear", this.onClear, this);
55099 ds.on("load", this.onLoad, this);
55100 ds.on("datachanged", this.onDataChange, this);
55101 ds.on("add", this.onAdd, this);
55102 ds.on("remove", this.onRemove, this);
55103 ds.on("update", this.onUpdate, this);
55104 ds.on("clear", this.onClear, this);
55109 this.cm.un("widthchange", this.onColWidthChange, this);
55110 this.cm.un("headerchange", this.onHeaderChange, this);
55111 this.cm.un("hiddenchange", this.onHiddenChange, this);
55112 this.cm.un("columnmoved", this.onColumnMove, this);
55113 this.cm.un("columnlockchange", this.onColumnLock, this);
55116 this.generateRules(cm);
55117 cm.on("widthchange", this.onColWidthChange, this);
55118 cm.on("headerchange", this.onHeaderChange, this);
55119 cm.on("hiddenchange", this.onHiddenChange, this);
55120 cm.on("columnmoved", this.onColumnMove, this);
55121 cm.on("columnlockchange", this.onColumnLock, this);
55126 init: function(grid){
55127 Roo.grid.GridView.superclass.init.call(this, grid);
55129 this.bind(grid.dataSource, grid.colModel);
55131 grid.on("headerclick", this.handleHeaderClick, this);
55133 if(grid.trackMouseOver){
55134 grid.on("mouseover", this.onRowOver, this);
55135 grid.on("mouseout", this.onRowOut, this);
55137 grid.cancelTextSelection = function(){};
55138 this.gridId = grid.id;
55140 var tpls = this.templates || {};
55143 tpls.master = new Roo.Template(
55144 '<div class="x-grid" hidefocus="true">',
55145 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55146 '<div class="x-grid-topbar"></div>',
55147 '<div class="x-grid-scroller"><div></div></div>',
55148 '<div class="x-grid-locked">',
55149 '<div class="x-grid-header">{lockedHeader}</div>',
55150 '<div class="x-grid-body">{lockedBody}</div>',
55152 '<div class="x-grid-viewport">',
55153 '<div class="x-grid-header">{header}</div>',
55154 '<div class="x-grid-body">{body}</div>',
55156 '<div class="x-grid-bottombar"></div>',
55158 '<div class="x-grid-resize-proxy"> </div>',
55161 tpls.master.disableformats = true;
55165 tpls.header = new Roo.Template(
55166 '<table border="0" cellspacing="0" cellpadding="0">',
55167 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55170 tpls.header.disableformats = true;
55172 tpls.header.compile();
55175 tpls.hcell = new Roo.Template(
55176 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55177 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55180 tpls.hcell.disableFormats = true;
55182 tpls.hcell.compile();
55185 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55186 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55187 tpls.hsplit.disableFormats = true;
55189 tpls.hsplit.compile();
55192 tpls.body = new Roo.Template(
55193 '<table border="0" cellspacing="0" cellpadding="0">',
55194 "<tbody>{rows}</tbody>",
55197 tpls.body.disableFormats = true;
55199 tpls.body.compile();
55202 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55203 tpls.row.disableFormats = true;
55205 tpls.row.compile();
55208 tpls.cell = new Roo.Template(
55209 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55210 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55211 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55214 tpls.cell.disableFormats = true;
55216 tpls.cell.compile();
55218 this.templates = tpls;
55221 // remap these for backwards compat
55222 onColWidthChange : function(){
55223 this.updateColumns.apply(this, arguments);
55225 onHeaderChange : function(){
55226 this.updateHeaders.apply(this, arguments);
55228 onHiddenChange : function(){
55229 this.handleHiddenChange.apply(this, arguments);
55231 onColumnMove : function(){
55232 this.handleColumnMove.apply(this, arguments);
55234 onColumnLock : function(){
55235 this.handleLockChange.apply(this, arguments);
55238 onDataChange : function(){
55240 this.updateHeaderSortState();
55243 onClear : function(){
55247 onUpdate : function(ds, record){
55248 this.refreshRow(record);
55251 refreshRow : function(record){
55252 var ds = this.ds, index;
55253 if(typeof record == 'number'){
55255 record = ds.getAt(index);
55257 index = ds.indexOf(record);
55259 this.insertRows(ds, index, index, true);
55260 this.onRemove(ds, record, index+1, true);
55261 this.syncRowHeights(index, index);
55263 this.fireEvent("rowupdated", this, index, record);
55266 onAdd : function(ds, records, index){
55267 this.insertRows(ds, index, index + (records.length-1));
55270 onRemove : function(ds, record, index, isUpdate){
55271 if(isUpdate !== true){
55272 this.fireEvent("beforerowremoved", this, index, record);
55274 var bt = this.getBodyTable(), lt = this.getLockedTable();
55275 if(bt.rows[index]){
55276 bt.firstChild.removeChild(bt.rows[index]);
55278 if(lt.rows[index]){
55279 lt.firstChild.removeChild(lt.rows[index]);
55281 if(isUpdate !== true){
55282 this.stripeRows(index);
55283 this.syncRowHeights(index, index);
55285 this.fireEvent("rowremoved", this, index, record);
55289 onLoad : function(){
55290 this.scrollToTop();
55294 * Scrolls the grid to the top
55296 scrollToTop : function(){
55298 this.scroller.dom.scrollTop = 0;
55304 * Gets a panel in the header of the grid that can be used for toolbars etc.
55305 * After modifying the contents of this panel a call to grid.autoSize() may be
55306 * required to register any changes in size.
55307 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55308 * @return Roo.Element
55310 getHeaderPanel : function(doShow){
55312 this.headerPanel.show();
55314 return this.headerPanel;
55318 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55319 * After modifying the contents of this panel a call to grid.autoSize() may be
55320 * required to register any changes in size.
55321 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55322 * @return Roo.Element
55324 getFooterPanel : function(doShow){
55326 this.footerPanel.show();
55328 return this.footerPanel;
55331 initElements : function(){
55332 var E = Roo.Element;
55333 var el = this.grid.getGridEl().dom.firstChild;
55334 var cs = el.childNodes;
55336 this.el = new E(el);
55338 this.focusEl = new E(el.firstChild);
55339 this.focusEl.swallowEvent("click", true);
55341 this.headerPanel = new E(cs[1]);
55342 this.headerPanel.enableDisplayMode("block");
55344 this.scroller = new E(cs[2]);
55345 this.scrollSizer = new E(this.scroller.dom.firstChild);
55347 this.lockedWrap = new E(cs[3]);
55348 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55349 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55351 this.mainWrap = new E(cs[4]);
55352 this.mainHd = new E(this.mainWrap.dom.firstChild);
55353 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55355 this.footerPanel = new E(cs[5]);
55356 this.footerPanel.enableDisplayMode("block");
55358 this.resizeProxy = new E(cs[6]);
55360 this.headerSelector = String.format(
55361 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55362 this.lockedHd.id, this.mainHd.id
55365 this.splitterSelector = String.format(
55366 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55367 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55370 idToCssName : function(s)
55372 return s.replace(/[^a-z0-9]+/ig, '-');
55375 getHeaderCell : function(index){
55376 return Roo.DomQuery.select(this.headerSelector)[index];
55379 getHeaderCellMeasure : function(index){
55380 return this.getHeaderCell(index).firstChild;
55383 getHeaderCellText : function(index){
55384 return this.getHeaderCell(index).firstChild.firstChild;
55387 getLockedTable : function(){
55388 return this.lockedBody.dom.firstChild;
55391 getBodyTable : function(){
55392 return this.mainBody.dom.firstChild;
55395 getLockedRow : function(index){
55396 return this.getLockedTable().rows[index];
55399 getRow : function(index){
55400 return this.getBodyTable().rows[index];
55403 getRowComposite : function(index){
55405 this.rowEl = new Roo.CompositeElementLite();
55407 var els = [], lrow, mrow;
55408 if(lrow = this.getLockedRow(index)){
55411 if(mrow = this.getRow(index)){
55414 this.rowEl.elements = els;
55418 * Gets the 'td' of the cell
55420 * @param {Integer} rowIndex row to select
55421 * @param {Integer} colIndex column to select
55425 getCell : function(rowIndex, colIndex){
55426 var locked = this.cm.getLockedCount();
55428 if(colIndex < locked){
55429 source = this.lockedBody.dom.firstChild;
55431 source = this.mainBody.dom.firstChild;
55432 colIndex -= locked;
55434 return source.rows[rowIndex].childNodes[colIndex];
55437 getCellText : function(rowIndex, colIndex){
55438 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55441 getCellBox : function(cell){
55442 var b = this.fly(cell).getBox();
55443 if(Roo.isOpera){ // opera fails to report the Y
55444 b.y = cell.offsetTop + this.mainBody.getY();
55449 getCellIndex : function(cell){
55450 var id = String(cell.className).match(this.cellRE);
55452 return parseInt(id[1], 10);
55457 findHeaderIndex : function(n){
55458 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55459 return r ? this.getCellIndex(r) : false;
55462 findHeaderCell : function(n){
55463 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55464 return r ? r : false;
55467 findRowIndex : function(n){
55471 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55472 return r ? r.rowIndex : false;
55475 findCellIndex : function(node){
55476 var stop = this.el.dom;
55477 while(node && node != stop){
55478 if(this.findRE.test(node.className)){
55479 return this.getCellIndex(node);
55481 node = node.parentNode;
55486 getColumnId : function(index){
55487 return this.cm.getColumnId(index);
55490 getSplitters : function()
55492 if(this.splitterSelector){
55493 return Roo.DomQuery.select(this.splitterSelector);
55499 getSplitter : function(index){
55500 return this.getSplitters()[index];
55503 onRowOver : function(e, t){
55505 if((row = this.findRowIndex(t)) !== false){
55506 this.getRowComposite(row).addClass("x-grid-row-over");
55510 onRowOut : function(e, t){
55512 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55513 this.getRowComposite(row).removeClass("x-grid-row-over");
55517 renderHeaders : function(){
55519 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55520 var cb = [], lb = [], sb = [], lsb = [], p = {};
55521 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55522 p.cellId = "x-grid-hd-0-" + i;
55523 p.splitId = "x-grid-csplit-0-" + i;
55524 p.id = cm.getColumnId(i);
55525 p.value = cm.getColumnHeader(i) || "";
55526 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55527 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55528 if(!cm.isLocked(i)){
55529 cb[cb.length] = ct.apply(p);
55530 sb[sb.length] = st.apply(p);
55532 lb[lb.length] = ct.apply(p);
55533 lsb[lsb.length] = st.apply(p);
55536 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55537 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55540 updateHeaders : function(){
55541 var html = this.renderHeaders();
55542 this.lockedHd.update(html[0]);
55543 this.mainHd.update(html[1]);
55547 * Focuses the specified row.
55548 * @param {Number} row The row index
55550 focusRow : function(row)
55552 //Roo.log('GridView.focusRow');
55553 var x = this.scroller.dom.scrollLeft;
55554 this.focusCell(row, 0, false);
55555 this.scroller.dom.scrollLeft = x;
55559 * Focuses the specified cell.
55560 * @param {Number} row The row index
55561 * @param {Number} col The column index
55562 * @param {Boolean} hscroll false to disable horizontal scrolling
55564 focusCell : function(row, col, hscroll)
55566 //Roo.log('GridView.focusCell');
55567 var el = this.ensureVisible(row, col, hscroll);
55568 this.focusEl.alignTo(el, "tl-tl");
55570 this.focusEl.focus();
55572 this.focusEl.focus.defer(1, this.focusEl);
55577 * Scrolls the specified cell into view
55578 * @param {Number} row The row index
55579 * @param {Number} col The column index
55580 * @param {Boolean} hscroll false to disable horizontal scrolling
55582 ensureVisible : function(row, col, hscroll)
55584 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55585 //return null; //disable for testing.
55586 if(typeof row != "number"){
55587 row = row.rowIndex;
55589 if(row < 0 && row >= this.ds.getCount()){
55592 col = (col !== undefined ? col : 0);
55593 var cm = this.grid.colModel;
55594 while(cm.isHidden(col)){
55598 var el = this.getCell(row, col);
55602 var c = this.scroller.dom;
55604 var ctop = parseInt(el.offsetTop, 10);
55605 var cleft = parseInt(el.offsetLeft, 10);
55606 var cbot = ctop + el.offsetHeight;
55607 var cright = cleft + el.offsetWidth;
55609 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55610 var stop = parseInt(c.scrollTop, 10);
55611 var sleft = parseInt(c.scrollLeft, 10);
55612 var sbot = stop + ch;
55613 var sright = sleft + c.clientWidth;
55615 Roo.log('GridView.ensureVisible:' +
55617 ' c.clientHeight:' + c.clientHeight +
55618 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55626 c.scrollTop = ctop;
55627 //Roo.log("set scrolltop to ctop DISABLE?");
55628 }else if(cbot > sbot){
55629 //Roo.log("set scrolltop to cbot-ch");
55630 c.scrollTop = cbot-ch;
55633 if(hscroll !== false){
55635 c.scrollLeft = cleft;
55636 }else if(cright > sright){
55637 c.scrollLeft = cright-c.clientWidth;
55644 updateColumns : function(){
55645 this.grid.stopEditing();
55646 var cm = this.grid.colModel, colIds = this.getColumnIds();
55647 //var totalWidth = cm.getTotalWidth();
55649 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55650 //if(cm.isHidden(i)) continue;
55651 var w = cm.getColumnWidth(i);
55652 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55653 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55655 this.updateSplitters();
55658 generateRules : function(cm){
55659 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55660 Roo.util.CSS.removeStyleSheet(rulesId);
55661 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55662 var cid = cm.getColumnId(i);
55664 if(cm.config[i].align){
55665 align = 'text-align:'+cm.config[i].align+';';
55668 if(cm.isHidden(i)){
55669 hidden = 'display:none;';
55671 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55673 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55674 this.hdSelector, cid, " {\n", align, width, "}\n",
55675 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55676 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55678 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55681 updateSplitters : function(){
55682 var cm = this.cm, s = this.getSplitters();
55683 if(s){ // splitters not created yet
55684 var pos = 0, locked = true;
55685 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55686 if(cm.isHidden(i)) {
55689 var w = cm.getColumnWidth(i); // make sure it's a number
55690 if(!cm.isLocked(i) && locked){
55695 s[i].style.left = (pos-this.splitOffset) + "px";
55700 handleHiddenChange : function(colModel, colIndex, hidden){
55702 this.hideColumn(colIndex);
55704 this.unhideColumn(colIndex);
55708 hideColumn : function(colIndex){
55709 var cid = this.getColumnId(colIndex);
55710 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55711 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55713 this.updateHeaders();
55715 this.updateSplitters();
55719 unhideColumn : function(colIndex){
55720 var cid = this.getColumnId(colIndex);
55721 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55722 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55725 this.updateHeaders();
55727 this.updateSplitters();
55731 insertRows : function(dm, firstRow, lastRow, isUpdate){
55732 if(firstRow == 0 && lastRow == dm.getCount()-1){
55736 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55738 var s = this.getScrollState();
55739 var markup = this.renderRows(firstRow, lastRow);
55740 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55741 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55742 this.restoreScroll(s);
55744 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55745 this.syncRowHeights(firstRow, lastRow);
55746 this.stripeRows(firstRow);
55752 bufferRows : function(markup, target, index){
55753 var before = null, trows = target.rows, tbody = target.tBodies[0];
55754 if(index < trows.length){
55755 before = trows[index];
55757 var b = document.createElement("div");
55758 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55759 var rows = b.firstChild.rows;
55760 for(var i = 0, len = rows.length; i < len; i++){
55762 tbody.insertBefore(rows[0], before);
55764 tbody.appendChild(rows[0]);
55771 deleteRows : function(dm, firstRow, lastRow){
55772 if(dm.getRowCount()<1){
55773 this.fireEvent("beforerefresh", this);
55774 this.mainBody.update("");
55775 this.lockedBody.update("");
55776 this.fireEvent("refresh", this);
55778 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55779 var bt = this.getBodyTable();
55780 var tbody = bt.firstChild;
55781 var rows = bt.rows;
55782 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55783 tbody.removeChild(rows[firstRow]);
55785 this.stripeRows(firstRow);
55786 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55790 updateRows : function(dataSource, firstRow, lastRow){
55791 var s = this.getScrollState();
55793 this.restoreScroll(s);
55796 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55800 this.updateHeaderSortState();
55803 getScrollState : function(){
55805 var sb = this.scroller.dom;
55806 return {left: sb.scrollLeft, top: sb.scrollTop};
55809 stripeRows : function(startRow){
55810 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55813 startRow = startRow || 0;
55814 var rows = this.getBodyTable().rows;
55815 var lrows = this.getLockedTable().rows;
55816 var cls = ' x-grid-row-alt ';
55817 for(var i = startRow, len = rows.length; i < len; i++){
55818 var row = rows[i], lrow = lrows[i];
55819 var isAlt = ((i+1) % 2 == 0);
55820 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55821 if(isAlt == hasAlt){
55825 row.className += " x-grid-row-alt";
55827 row.className = row.className.replace("x-grid-row-alt", "");
55830 lrow.className = row.className;
55835 restoreScroll : function(state){
55836 //Roo.log('GridView.restoreScroll');
55837 var sb = this.scroller.dom;
55838 sb.scrollLeft = state.left;
55839 sb.scrollTop = state.top;
55843 syncScroll : function(){
55844 //Roo.log('GridView.syncScroll');
55845 var sb = this.scroller.dom;
55846 var sh = this.mainHd.dom;
55847 var bs = this.mainBody.dom;
55848 var lv = this.lockedBody.dom;
55849 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55850 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55853 handleScroll : function(e){
55855 var sb = this.scroller.dom;
55856 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55860 handleWheel : function(e){
55861 var d = e.getWheelDelta();
55862 this.scroller.dom.scrollTop -= d*22;
55863 // set this here to prevent jumpy scrolling on large tables
55864 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55868 renderRows : function(startRow, endRow){
55869 // pull in all the crap needed to render rows
55870 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55871 var colCount = cm.getColumnCount();
55873 if(ds.getCount() < 1){
55877 // build a map for all the columns
55879 for(var i = 0; i < colCount; i++){
55880 var name = cm.getDataIndex(i);
55882 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55883 renderer : cm.getRenderer(i),
55884 id : cm.getColumnId(i),
55885 locked : cm.isLocked(i),
55886 has_editor : cm.isCellEditable(i)
55890 startRow = startRow || 0;
55891 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55893 // records to render
55894 var rs = ds.getRange(startRow, endRow);
55896 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55899 // As much as I hate to duplicate code, this was branched because FireFox really hates
55900 // [].join("") on strings. The performance difference was substantial enough to
55901 // branch this function
55902 doRender : Roo.isGecko ?
55903 function(cs, rs, ds, startRow, colCount, stripe){
55904 var ts = this.templates, ct = ts.cell, rt = ts.row;
55906 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55908 var hasListener = this.grid.hasListener('rowclass');
55910 for(var j = 0, len = rs.length; j < len; j++){
55911 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55912 for(var i = 0; i < colCount; i++){
55914 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55916 p.css = p.attr = "";
55917 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55918 if(p.value == undefined || p.value === "") {
55919 p.value = " ";
55922 p.css += ' x-grid-editable-cell';
55924 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55925 p.css += ' x-grid-dirty-cell';
55927 var markup = ct.apply(p);
55935 if(stripe && ((rowIndex+1) % 2 == 0)){
55936 alt.push("x-grid-row-alt")
55939 alt.push( " x-grid-dirty-row");
55942 if(this.getRowClass){
55943 alt.push(this.getRowClass(r, rowIndex));
55949 rowIndex : rowIndex,
55952 this.grid.fireEvent('rowclass', this, rowcfg);
55953 alt.push(rowcfg.rowClass);
55955 rp.alt = alt.join(" ");
55956 lbuf+= rt.apply(rp);
55958 buf+= rt.apply(rp);
55960 return [lbuf, buf];
55962 function(cs, rs, ds, startRow, colCount, stripe){
55963 var ts = this.templates, ct = ts.cell, rt = ts.row;
55965 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55966 var hasListener = this.grid.hasListener('rowclass');
55969 for(var j = 0, len = rs.length; j < len; j++){
55970 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55971 for(var i = 0; i < colCount; i++){
55973 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55975 p.css = p.attr = "";
55976 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55977 if(p.value == undefined || p.value === "") {
55978 p.value = " ";
55982 p.css += ' x-grid-editable-cell';
55984 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55985 p.css += ' x-grid-dirty-cell'
55988 var markup = ct.apply(p);
55990 cb[cb.length] = markup;
55992 lcb[lcb.length] = markup;
55996 if(stripe && ((rowIndex+1) % 2 == 0)){
55997 alt.push( "x-grid-row-alt");
56000 alt.push(" x-grid-dirty-row");
56003 if(this.getRowClass){
56004 alt.push( this.getRowClass(r, rowIndex));
56010 rowIndex : rowIndex,
56013 this.grid.fireEvent('rowclass', this, rowcfg);
56014 alt.push(rowcfg.rowClass);
56017 rp.alt = alt.join(" ");
56018 rp.cells = lcb.join("");
56019 lbuf[lbuf.length] = rt.apply(rp);
56020 rp.cells = cb.join("");
56021 buf[buf.length] = rt.apply(rp);
56023 return [lbuf.join(""), buf.join("")];
56026 renderBody : function(){
56027 var markup = this.renderRows();
56028 var bt = this.templates.body;
56029 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56033 * Refreshes the grid
56034 * @param {Boolean} headersToo
56036 refresh : function(headersToo){
56037 this.fireEvent("beforerefresh", this);
56038 this.grid.stopEditing();
56039 var result = this.renderBody();
56040 this.lockedBody.update(result[0]);
56041 this.mainBody.update(result[1]);
56042 if(headersToo === true){
56043 this.updateHeaders();
56044 this.updateColumns();
56045 this.updateSplitters();
56046 this.updateHeaderSortState();
56048 this.syncRowHeights();
56050 this.fireEvent("refresh", this);
56053 handleColumnMove : function(cm, oldIndex, newIndex){
56054 this.indexMap = null;
56055 var s = this.getScrollState();
56056 this.refresh(true);
56057 this.restoreScroll(s);
56058 this.afterMove(newIndex);
56061 afterMove : function(colIndex){
56062 if(this.enableMoveAnim && Roo.enableFx){
56063 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56065 // if multisort - fix sortOrder, and reload..
56066 if (this.grid.dataSource.multiSort) {
56067 // the we can call sort again..
56068 var dm = this.grid.dataSource;
56069 var cm = this.grid.colModel;
56071 for(var i = 0; i < cm.config.length; i++ ) {
56073 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56074 continue; // dont' bother, it's not in sort list or being set.
56077 so.push(cm.config[i].dataIndex);
56080 dm.load(dm.lastOptions);
56087 updateCell : function(dm, rowIndex, dataIndex){
56088 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56089 if(typeof colIndex == "undefined"){ // not present in grid
56092 var cm = this.grid.colModel;
56093 var cell = this.getCell(rowIndex, colIndex);
56094 var cellText = this.getCellText(rowIndex, colIndex);
56097 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56098 id : cm.getColumnId(colIndex),
56099 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56101 var renderer = cm.getRenderer(colIndex);
56102 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56103 if(typeof val == "undefined" || val === "") {
56106 cellText.innerHTML = val;
56107 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56108 this.syncRowHeights(rowIndex, rowIndex);
56111 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56113 if(this.grid.autoSizeHeaders){
56114 var h = this.getHeaderCellMeasure(colIndex);
56115 maxWidth = Math.max(maxWidth, h.scrollWidth);
56118 if(this.cm.isLocked(colIndex)){
56119 tb = this.getLockedTable();
56122 tb = this.getBodyTable();
56123 index = colIndex - this.cm.getLockedCount();
56126 var rows = tb.rows;
56127 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56128 for(var i = 0; i < stopIndex; i++){
56129 var cell = rows[i].childNodes[index].firstChild;
56130 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56133 return maxWidth + /*margin for error in IE*/ 5;
56136 * Autofit a column to its content.
56137 * @param {Number} colIndex
56138 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56140 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56141 if(this.cm.isHidden(colIndex)){
56142 return; // can't calc a hidden column
56145 var cid = this.cm.getColumnId(colIndex);
56146 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56147 if(this.grid.autoSizeHeaders){
56148 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56151 var newWidth = this.calcColumnWidth(colIndex);
56152 this.cm.setColumnWidth(colIndex,
56153 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56154 if(!suppressEvent){
56155 this.grid.fireEvent("columnresize", colIndex, newWidth);
56160 * Autofits all columns to their content and then expands to fit any extra space in the grid
56162 autoSizeColumns : function(){
56163 var cm = this.grid.colModel;
56164 var colCount = cm.getColumnCount();
56165 for(var i = 0; i < colCount; i++){
56166 this.autoSizeColumn(i, true, true);
56168 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56171 this.updateColumns();
56177 * Autofits all columns to the grid's width proportionate with their current size
56178 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56180 fitColumns : function(reserveScrollSpace){
56181 var cm = this.grid.colModel;
56182 var colCount = cm.getColumnCount();
56186 for (i = 0; i < colCount; i++){
56187 if(!cm.isHidden(i) && !cm.isFixed(i)){
56188 w = cm.getColumnWidth(i);
56194 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56195 if(reserveScrollSpace){
56198 var frac = (avail - cm.getTotalWidth())/width;
56199 while (cols.length){
56202 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56204 this.updateColumns();
56208 onRowSelect : function(rowIndex){
56209 var row = this.getRowComposite(rowIndex);
56210 row.addClass("x-grid-row-selected");
56213 onRowDeselect : function(rowIndex){
56214 var row = this.getRowComposite(rowIndex);
56215 row.removeClass("x-grid-row-selected");
56218 onCellSelect : function(row, col){
56219 var cell = this.getCell(row, col);
56221 Roo.fly(cell).addClass("x-grid-cell-selected");
56225 onCellDeselect : function(row, col){
56226 var cell = this.getCell(row, col);
56228 Roo.fly(cell).removeClass("x-grid-cell-selected");
56232 updateHeaderSortState : function(){
56234 // sort state can be single { field: xxx, direction : yyy}
56235 // or { xxx=>ASC , yyy : DESC ..... }
56238 if (!this.ds.multiSort) {
56239 var state = this.ds.getSortState();
56243 mstate[state.field] = state.direction;
56244 // FIXME... - this is not used here.. but might be elsewhere..
56245 this.sortState = state;
56248 mstate = this.ds.sortToggle;
56250 //remove existing sort classes..
56252 var sc = this.sortClasses;
56253 var hds = this.el.select(this.headerSelector).removeClass(sc);
56255 for(var f in mstate) {
56257 var sortColumn = this.cm.findColumnIndex(f);
56259 if(sortColumn != -1){
56260 var sortDir = mstate[f];
56261 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56270 handleHeaderClick : function(g, index,e){
56272 Roo.log("header click");
56275 // touch events on header are handled by context
56276 this.handleHdCtx(g,index,e);
56281 if(this.headersDisabled){
56284 var dm = g.dataSource, cm = g.colModel;
56285 if(!cm.isSortable(index)){
56290 if (dm.multiSort) {
56291 // update the sortOrder
56293 for(var i = 0; i < cm.config.length; i++ ) {
56295 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56296 continue; // dont' bother, it's not in sort list or being set.
56299 so.push(cm.config[i].dataIndex);
56305 dm.sort(cm.getDataIndex(index));
56309 destroy : function(){
56311 this.colMenu.removeAll();
56312 Roo.menu.MenuMgr.unregister(this.colMenu);
56313 this.colMenu.getEl().remove();
56314 delete this.colMenu;
56317 this.hmenu.removeAll();
56318 Roo.menu.MenuMgr.unregister(this.hmenu);
56319 this.hmenu.getEl().remove();
56322 if(this.grid.enableColumnMove){
56323 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56325 for(var dd in dds){
56326 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56327 var elid = dds[dd].dragElId;
56329 Roo.get(elid).remove();
56330 } else if(dds[dd].config.isTarget){
56331 dds[dd].proxyTop.remove();
56332 dds[dd].proxyBottom.remove();
56335 if(Roo.dd.DDM.locationCache[dd]){
56336 delete Roo.dd.DDM.locationCache[dd];
56339 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56342 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56343 this.bind(null, null);
56344 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56347 handleLockChange : function(){
56348 this.refresh(true);
56351 onDenyColumnLock : function(){
56355 onDenyColumnHide : function(){
56359 handleHdMenuClick : function(item){
56360 var index = this.hdCtxIndex;
56361 var cm = this.cm, ds = this.ds;
56364 ds.sort(cm.getDataIndex(index), "ASC");
56367 ds.sort(cm.getDataIndex(index), "DESC");
56370 var lc = cm.getLockedCount();
56371 if(cm.getColumnCount(true) <= lc+1){
56372 this.onDenyColumnLock();
56376 cm.setLocked(index, true, true);
56377 cm.moveColumn(index, lc);
56378 this.grid.fireEvent("columnmove", index, lc);
56380 cm.setLocked(index, true);
56384 var lc = cm.getLockedCount();
56385 if((lc-1) != index){
56386 cm.setLocked(index, false, true);
56387 cm.moveColumn(index, lc-1);
56388 this.grid.fireEvent("columnmove", index, lc-1);
56390 cm.setLocked(index, false);
56393 case 'wider': // used to expand cols on touch..
56395 var cw = cm.getColumnWidth(index);
56396 cw += (item.id == 'wider' ? 1 : -1) * 50;
56397 cw = Math.max(0, cw);
56398 cw = Math.min(cw,4000);
56399 cm.setColumnWidth(index, cw);
56403 index = cm.getIndexById(item.id.substr(4));
56405 if(item.checked && cm.getColumnCount(true) <= 1){
56406 this.onDenyColumnHide();
56409 cm.setHidden(index, item.checked);
56415 beforeColMenuShow : function(){
56416 var cm = this.cm, colCount = cm.getColumnCount();
56417 this.colMenu.removeAll();
56418 for(var i = 0; i < colCount; i++){
56419 this.colMenu.add(new Roo.menu.CheckItem({
56420 id: "col-"+cm.getColumnId(i),
56421 text: cm.getColumnHeader(i),
56422 checked: !cm.isHidden(i),
56428 handleHdCtx : function(g, index, e){
56430 var hd = this.getHeaderCell(index);
56431 this.hdCtxIndex = index;
56432 var ms = this.hmenu.items, cm = this.cm;
56433 ms.get("asc").setDisabled(!cm.isSortable(index));
56434 ms.get("desc").setDisabled(!cm.isSortable(index));
56435 if(this.grid.enableColLock !== false){
56436 ms.get("lock").setDisabled(cm.isLocked(index));
56437 ms.get("unlock").setDisabled(!cm.isLocked(index));
56439 this.hmenu.show(hd, "tl-bl");
56442 handleHdOver : function(e){
56443 var hd = this.findHeaderCell(e.getTarget());
56444 if(hd && !this.headersDisabled){
56445 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56446 this.fly(hd).addClass("x-grid-hd-over");
56451 handleHdOut : function(e){
56452 var hd = this.findHeaderCell(e.getTarget());
56454 this.fly(hd).removeClass("x-grid-hd-over");
56458 handleSplitDblClick : function(e, t){
56459 var i = this.getCellIndex(t);
56460 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56461 this.autoSizeColumn(i, true);
56466 render : function(){
56469 var colCount = cm.getColumnCount();
56471 if(this.grid.monitorWindowResize === true){
56472 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56474 var header = this.renderHeaders();
56475 var body = this.templates.body.apply({rows:""});
56476 var html = this.templates.master.apply({
56479 lockedHeader: header[0],
56483 //this.updateColumns();
56485 this.grid.getGridEl().dom.innerHTML = html;
56487 this.initElements();
56489 // a kludge to fix the random scolling effect in webkit
56490 this.el.on("scroll", function() {
56491 this.el.dom.scrollTop=0; // hopefully not recursive..
56494 this.scroller.on("scroll", this.handleScroll, this);
56495 this.lockedBody.on("mousewheel", this.handleWheel, this);
56496 this.mainBody.on("mousewheel", this.handleWheel, this);
56498 this.mainHd.on("mouseover", this.handleHdOver, this);
56499 this.mainHd.on("mouseout", this.handleHdOut, this);
56500 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56501 {delegate: "."+this.splitClass});
56503 this.lockedHd.on("mouseover", this.handleHdOver, this);
56504 this.lockedHd.on("mouseout", this.handleHdOut, this);
56505 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56506 {delegate: "."+this.splitClass});
56508 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56509 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56512 this.updateSplitters();
56514 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56515 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56516 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56519 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56520 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56522 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56523 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56525 if(this.grid.enableColLock !== false){
56526 this.hmenu.add('-',
56527 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56528 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56532 this.hmenu.add('-',
56533 {id:"wider", text: this.columnsWiderText},
56534 {id:"narrow", text: this.columnsNarrowText }
56540 if(this.grid.enableColumnHide !== false){
56542 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56543 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56544 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56546 this.hmenu.add('-',
56547 {id:"columns", text: this.columnsText, menu: this.colMenu}
56550 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56552 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56555 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56556 this.dd = new Roo.grid.GridDragZone(this.grid, {
56557 ddGroup : this.grid.ddGroup || 'GridDD'
56563 for(var i = 0; i < colCount; i++){
56564 if(cm.isHidden(i)){
56565 this.hideColumn(i);
56567 if(cm.config[i].align){
56568 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56569 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56573 this.updateHeaderSortState();
56575 this.beforeInitialResize();
56578 // two part rendering gives faster view to the user
56579 this.renderPhase2.defer(1, this);
56582 renderPhase2 : function(){
56583 // render the rows now
56585 if(this.grid.autoSizeColumns){
56586 this.autoSizeColumns();
56590 beforeInitialResize : function(){
56594 onColumnSplitterMoved : function(i, w){
56595 this.userResized = true;
56596 var cm = this.grid.colModel;
56597 cm.setColumnWidth(i, w, true);
56598 var cid = cm.getColumnId(i);
56599 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56600 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56601 this.updateSplitters();
56603 this.grid.fireEvent("columnresize", i, w);
56606 syncRowHeights : function(startIndex, endIndex){
56607 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56608 startIndex = startIndex || 0;
56609 var mrows = this.getBodyTable().rows;
56610 var lrows = this.getLockedTable().rows;
56611 var len = mrows.length-1;
56612 endIndex = Math.min(endIndex || len, len);
56613 for(var i = startIndex; i <= endIndex; i++){
56614 var m = mrows[i], l = lrows[i];
56615 var h = Math.max(m.offsetHeight, l.offsetHeight);
56616 m.style.height = l.style.height = h + "px";
56621 layout : function(initialRender, is2ndPass){
56623 var auto = g.autoHeight;
56624 var scrollOffset = 16;
56625 var c = g.getGridEl(), cm = this.cm,
56626 expandCol = g.autoExpandColumn,
56628 //c.beginMeasure();
56630 if(!c.dom.offsetWidth){ // display:none?
56632 this.lockedWrap.show();
56633 this.mainWrap.show();
56638 var hasLock = this.cm.isLocked(0);
56640 var tbh = this.headerPanel.getHeight();
56641 var bbh = this.footerPanel.getHeight();
56644 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56645 var newHeight = ch + c.getBorderWidth("tb");
56647 newHeight = Math.min(g.maxHeight, newHeight);
56649 c.setHeight(newHeight);
56653 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56656 var s = this.scroller;
56658 var csize = c.getSize(true);
56660 this.el.setSize(csize.width, csize.height);
56662 this.headerPanel.setWidth(csize.width);
56663 this.footerPanel.setWidth(csize.width);
56665 var hdHeight = this.mainHd.getHeight();
56666 var vw = csize.width;
56667 var vh = csize.height - (tbh + bbh);
56671 var bt = this.getBodyTable();
56673 if(cm.getLockedCount() == cm.config.length){
56674 bt = this.getLockedTable();
56677 var ltWidth = hasLock ?
56678 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56680 var scrollHeight = bt.offsetHeight;
56681 var scrollWidth = ltWidth + bt.offsetWidth;
56682 var vscroll = false, hscroll = false;
56684 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56686 var lw = this.lockedWrap, mw = this.mainWrap;
56687 var lb = this.lockedBody, mb = this.mainBody;
56689 setTimeout(function(){
56690 var t = s.dom.offsetTop;
56691 var w = s.dom.clientWidth,
56692 h = s.dom.clientHeight;
56695 lw.setSize(ltWidth, h);
56697 mw.setLeftTop(ltWidth, t);
56698 mw.setSize(w-ltWidth, h);
56700 lb.setHeight(h-hdHeight);
56701 mb.setHeight(h-hdHeight);
56703 if(is2ndPass !== true && !gv.userResized && expandCol){
56704 // high speed resize without full column calculation
56706 var ci = cm.getIndexById(expandCol);
56708 ci = cm.findColumnIndex(expandCol);
56710 ci = Math.max(0, ci); // make sure it's got at least the first col.
56711 var expandId = cm.getColumnId(ci);
56712 var tw = cm.getTotalWidth(false);
56713 var currentWidth = cm.getColumnWidth(ci);
56714 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56715 if(currentWidth != cw){
56716 cm.setColumnWidth(ci, cw, true);
56717 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56718 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56719 gv.updateSplitters();
56720 gv.layout(false, true);
56732 onWindowResize : function(){
56733 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56739 appendFooter : function(parentEl){
56743 sortAscText : "Sort Ascending",
56744 sortDescText : "Sort Descending",
56745 lockText : "Lock Column",
56746 unlockText : "Unlock Column",
56747 columnsText : "Columns",
56749 columnsWiderText : "Wider",
56750 columnsNarrowText : "Thinner"
56754 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56755 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56756 this.proxy.el.addClass('x-grid3-col-dd');
56759 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56760 handleMouseDown : function(e){
56764 callHandleMouseDown : function(e){
56765 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56770 * Ext JS Library 1.1.1
56771 * Copyright(c) 2006-2007, Ext JS, LLC.
56773 * Originally Released Under LGPL - original licence link has changed is not relivant.
56776 * <script type="text/javascript">
56780 // This is a support class used internally by the Grid components
56781 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56783 this.view = grid.getView();
56784 this.proxy = this.view.resizeProxy;
56785 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56786 "gridSplitters" + this.grid.getGridEl().id, {
56787 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56789 this.setHandleElId(Roo.id(hd));
56790 this.setOuterHandleElId(Roo.id(hd2));
56791 this.scroll = false;
56793 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56794 fly: Roo.Element.fly,
56796 b4StartDrag : function(x, y){
56797 this.view.headersDisabled = true;
56798 this.proxy.setHeight(this.view.mainWrap.getHeight());
56799 var w = this.cm.getColumnWidth(this.cellIndex);
56800 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56801 this.resetConstraints();
56802 this.setXConstraint(minw, 1000);
56803 this.setYConstraint(0, 0);
56804 this.minX = x - minw;
56805 this.maxX = x + 1000;
56807 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56811 handleMouseDown : function(e){
56812 ev = Roo.EventObject.setEvent(e);
56813 var t = this.fly(ev.getTarget());
56814 if(t.hasClass("x-grid-split")){
56815 this.cellIndex = this.view.getCellIndex(t.dom);
56816 this.split = t.dom;
56817 this.cm = this.grid.colModel;
56818 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56819 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56824 endDrag : function(e){
56825 this.view.headersDisabled = false;
56826 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56827 var diff = endX - this.startPos;
56828 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56831 autoOffset : function(){
56832 this.setDelta(0,0);
56836 * Ext JS Library 1.1.1
56837 * Copyright(c) 2006-2007, Ext JS, LLC.
56839 * Originally Released Under LGPL - original licence link has changed is not relivant.
56842 * <script type="text/javascript">
56846 // This is a support class used internally by the Grid components
56847 Roo.grid.GridDragZone = function(grid, config){
56848 this.view = grid.getView();
56849 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56850 if(this.view.lockedBody){
56851 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56852 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56854 this.scroll = false;
56856 this.ddel = document.createElement('div');
56857 this.ddel.className = 'x-grid-dd-wrap';
56860 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56861 ddGroup : "GridDD",
56863 getDragData : function(e){
56864 var t = Roo.lib.Event.getTarget(e);
56865 var rowIndex = this.view.findRowIndex(t);
56866 var sm = this.grid.selModel;
56868 //Roo.log(rowIndex);
56870 if (sm.getSelectedCell) {
56871 // cell selection..
56872 if (!sm.getSelectedCell()) {
56875 if (rowIndex != sm.getSelectedCell()[0]) {
56881 if(rowIndex !== false){
56886 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56888 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56891 if (e.hasModifier()){
56892 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56895 Roo.log("getDragData");
56900 rowIndex: rowIndex,
56901 selections:sm.getSelections ? sm.getSelections() : (
56902 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56909 onInitDrag : function(e){
56910 var data = this.dragData;
56911 this.ddel.innerHTML = this.grid.getDragDropText();
56912 this.proxy.update(this.ddel);
56913 // fire start drag?
56916 afterRepair : function(){
56917 this.dragging = false;
56920 getRepairXY : function(e, data){
56924 onEndDrag : function(data, e){
56928 onValidDrop : function(dd, e, id){
56933 beforeInvalidDrop : function(e, id){
56938 * Ext JS Library 1.1.1
56939 * Copyright(c) 2006-2007, Ext JS, LLC.
56941 * Originally Released Under LGPL - original licence link has changed is not relivant.
56944 * <script type="text/javascript">
56949 * @class Roo.grid.ColumnModel
56950 * @extends Roo.util.Observable
56951 * This is the default implementation of a ColumnModel used by the Grid. It defines
56952 * the columns in the grid.
56955 var colModel = new Roo.grid.ColumnModel([
56956 {header: "Ticker", width: 60, sortable: true, locked: true},
56957 {header: "Company Name", width: 150, sortable: true},
56958 {header: "Market Cap.", width: 100, sortable: true},
56959 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56960 {header: "Employees", width: 100, sortable: true, resizable: false}
56965 * The config options listed for this class are options which may appear in each
56966 * individual column definition.
56967 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56969 * @param {Object} config An Array of column config objects. See this class's
56970 * config objects for details.
56972 Roo.grid.ColumnModel = function(config){
56974 * The config passed into the constructor
56976 this.config = config;
56979 // if no id, create one
56980 // if the column does not have a dataIndex mapping,
56981 // map it to the order it is in the config
56982 for(var i = 0, len = config.length; i < len; i++){
56984 if(typeof c.dataIndex == "undefined"){
56987 if(typeof c.renderer == "string"){
56988 c.renderer = Roo.util.Format[c.renderer];
56990 if(typeof c.id == "undefined"){
56993 if(c.editor && c.editor.xtype){
56994 c.editor = Roo.factory(c.editor, Roo.grid);
56996 if(c.editor && c.editor.isFormField){
56997 c.editor = new Roo.grid.GridEditor(c.editor);
56999 this.lookup[c.id] = c;
57003 * The width of columns which have no width specified (defaults to 100)
57006 this.defaultWidth = 100;
57009 * Default sortable of columns which have no sortable specified (defaults to false)
57012 this.defaultSortable = false;
57016 * @event widthchange
57017 * Fires when the width of a column changes.
57018 * @param {ColumnModel} this
57019 * @param {Number} columnIndex The column index
57020 * @param {Number} newWidth The new width
57022 "widthchange": true,
57024 * @event headerchange
57025 * Fires when the text of a header changes.
57026 * @param {ColumnModel} this
57027 * @param {Number} columnIndex The column index
57028 * @param {Number} newText The new header text
57030 "headerchange": true,
57032 * @event hiddenchange
57033 * Fires when a column is hidden or "unhidden".
57034 * @param {ColumnModel} this
57035 * @param {Number} columnIndex The column index
57036 * @param {Boolean} hidden true if hidden, false otherwise
57038 "hiddenchange": true,
57040 * @event columnmoved
57041 * Fires when a column is moved.
57042 * @param {ColumnModel} this
57043 * @param {Number} oldIndex
57044 * @param {Number} newIndex
57046 "columnmoved" : true,
57048 * @event columlockchange
57049 * Fires when a column's locked state is changed
57050 * @param {ColumnModel} this
57051 * @param {Number} colIndex
57052 * @param {Boolean} locked true if locked
57054 "columnlockchange" : true
57056 Roo.grid.ColumnModel.superclass.constructor.call(this);
57058 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57060 * @cfg {String} header The header text to display in the Grid view.
57063 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57064 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57065 * specified, the column's index is used as an index into the Record's data Array.
57068 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57069 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57072 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57073 * Defaults to the value of the {@link #defaultSortable} property.
57074 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57077 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57080 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57083 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57086 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57089 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57090 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57091 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57092 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57095 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57098 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57101 * @cfg {String} cursor (Optional)
57104 * @cfg {String} tooltip (Optional)
57107 * @cfg {Number} xs (Optional)
57110 * @cfg {Number} sm (Optional)
57113 * @cfg {Number} md (Optional)
57116 * @cfg {Number} lg (Optional)
57119 * Returns the id of the column at the specified index.
57120 * @param {Number} index The column index
57121 * @return {String} the id
57123 getColumnId : function(index){
57124 return this.config[index].id;
57128 * Returns the column for a specified id.
57129 * @param {String} id The column id
57130 * @return {Object} the column
57132 getColumnById : function(id){
57133 return this.lookup[id];
57138 * Returns the column for a specified dataIndex.
57139 * @param {String} dataIndex The column dataIndex
57140 * @return {Object|Boolean} the column or false if not found
57142 getColumnByDataIndex: function(dataIndex){
57143 var index = this.findColumnIndex(dataIndex);
57144 return index > -1 ? this.config[index] : false;
57148 * Returns the index for a specified column id.
57149 * @param {String} id The column id
57150 * @return {Number} the index, or -1 if not found
57152 getIndexById : function(id){
57153 for(var i = 0, len = this.config.length; i < len; i++){
57154 if(this.config[i].id == id){
57162 * Returns the index for a specified column dataIndex.
57163 * @param {String} dataIndex The column dataIndex
57164 * @return {Number} the index, or -1 if not found
57167 findColumnIndex : function(dataIndex){
57168 for(var i = 0, len = this.config.length; i < len; i++){
57169 if(this.config[i].dataIndex == dataIndex){
57177 moveColumn : function(oldIndex, newIndex){
57178 var c = this.config[oldIndex];
57179 this.config.splice(oldIndex, 1);
57180 this.config.splice(newIndex, 0, c);
57181 this.dataMap = null;
57182 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57185 isLocked : function(colIndex){
57186 return this.config[colIndex].locked === true;
57189 setLocked : function(colIndex, value, suppressEvent){
57190 if(this.isLocked(colIndex) == value){
57193 this.config[colIndex].locked = value;
57194 if(!suppressEvent){
57195 this.fireEvent("columnlockchange", this, colIndex, value);
57199 getTotalLockedWidth : function(){
57200 var totalWidth = 0;
57201 for(var i = 0; i < this.config.length; i++){
57202 if(this.isLocked(i) && !this.isHidden(i)){
57203 this.totalWidth += this.getColumnWidth(i);
57209 getLockedCount : function(){
57210 for(var i = 0, len = this.config.length; i < len; i++){
57211 if(!this.isLocked(i)){
57216 return this.config.length;
57220 * Returns the number of columns.
57223 getColumnCount : function(visibleOnly){
57224 if(visibleOnly === true){
57226 for(var i = 0, len = this.config.length; i < len; i++){
57227 if(!this.isHidden(i)){
57233 return this.config.length;
57237 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57238 * @param {Function} fn
57239 * @param {Object} scope (optional)
57240 * @return {Array} result
57242 getColumnsBy : function(fn, scope){
57244 for(var i = 0, len = this.config.length; i < len; i++){
57245 var c = this.config[i];
57246 if(fn.call(scope||this, c, i) === true){
57254 * Returns true if the specified column is sortable.
57255 * @param {Number} col The column index
57256 * @return {Boolean}
57258 isSortable : function(col){
57259 if(typeof this.config[col].sortable == "undefined"){
57260 return this.defaultSortable;
57262 return this.config[col].sortable;
57266 * Returns the rendering (formatting) function defined for the column.
57267 * @param {Number} col The column index.
57268 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57270 getRenderer : function(col){
57271 if(!this.config[col].renderer){
57272 return Roo.grid.ColumnModel.defaultRenderer;
57274 return this.config[col].renderer;
57278 * Sets the rendering (formatting) function for a column.
57279 * @param {Number} col The column index
57280 * @param {Function} fn The function to use to process the cell's raw data
57281 * to return HTML markup for the grid view. The render function is called with
57282 * the following parameters:<ul>
57283 * <li>Data value.</li>
57284 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57285 * <li>css A CSS style string to apply to the table cell.</li>
57286 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57287 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57288 * <li>Row index</li>
57289 * <li>Column index</li>
57290 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57292 setRenderer : function(col, fn){
57293 this.config[col].renderer = fn;
57297 * Returns the width for the specified column.
57298 * @param {Number} col The column index
57301 getColumnWidth : function(col){
57302 return this.config[col].width * 1 || this.defaultWidth;
57306 * Sets the width for a column.
57307 * @param {Number} col The column index
57308 * @param {Number} width The new width
57310 setColumnWidth : function(col, width, suppressEvent){
57311 this.config[col].width = width;
57312 this.totalWidth = null;
57313 if(!suppressEvent){
57314 this.fireEvent("widthchange", this, col, width);
57319 * Returns the total width of all columns.
57320 * @param {Boolean} includeHidden True to include hidden column widths
57323 getTotalWidth : function(includeHidden){
57324 if(!this.totalWidth){
57325 this.totalWidth = 0;
57326 for(var i = 0, len = this.config.length; i < len; i++){
57327 if(includeHidden || !this.isHidden(i)){
57328 this.totalWidth += this.getColumnWidth(i);
57332 return this.totalWidth;
57336 * Returns the header for the specified column.
57337 * @param {Number} col The column index
57340 getColumnHeader : function(col){
57341 return this.config[col].header;
57345 * Sets the header for a column.
57346 * @param {Number} col The column index
57347 * @param {String} header The new header
57349 setColumnHeader : function(col, header){
57350 this.config[col].header = header;
57351 this.fireEvent("headerchange", this, col, header);
57355 * Returns the tooltip for the specified column.
57356 * @param {Number} col The column index
57359 getColumnTooltip : function(col){
57360 return this.config[col].tooltip;
57363 * Sets the tooltip for a column.
57364 * @param {Number} col The column index
57365 * @param {String} tooltip The new tooltip
57367 setColumnTooltip : function(col, tooltip){
57368 this.config[col].tooltip = tooltip;
57372 * Returns the dataIndex for the specified column.
57373 * @param {Number} col The column index
57376 getDataIndex : function(col){
57377 return this.config[col].dataIndex;
57381 * Sets the dataIndex for a column.
57382 * @param {Number} col The column index
57383 * @param {Number} dataIndex The new dataIndex
57385 setDataIndex : function(col, dataIndex){
57386 this.config[col].dataIndex = dataIndex;
57392 * Returns true if the cell is editable.
57393 * @param {Number} colIndex The column index
57394 * @param {Number} rowIndex The row index - this is nto actually used..?
57395 * @return {Boolean}
57397 isCellEditable : function(colIndex, rowIndex){
57398 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57402 * Returns the editor defined for the cell/column.
57403 * return false or null to disable editing.
57404 * @param {Number} colIndex The column index
57405 * @param {Number} rowIndex The row index
57408 getCellEditor : function(colIndex, rowIndex){
57409 return this.config[colIndex].editor;
57413 * Sets if a column is editable.
57414 * @param {Number} col The column index
57415 * @param {Boolean} editable True if the column is editable
57417 setEditable : function(col, editable){
57418 this.config[col].editable = editable;
57423 * Returns true if the column is hidden.
57424 * @param {Number} colIndex The column index
57425 * @return {Boolean}
57427 isHidden : function(colIndex){
57428 return this.config[colIndex].hidden;
57433 * Returns true if the column width cannot be changed
57435 isFixed : function(colIndex){
57436 return this.config[colIndex].fixed;
57440 * Returns true if the column can be resized
57441 * @return {Boolean}
57443 isResizable : function(colIndex){
57444 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57447 * Sets if a column is hidden.
57448 * @param {Number} colIndex The column index
57449 * @param {Boolean} hidden True if the column is hidden
57451 setHidden : function(colIndex, hidden){
57452 this.config[colIndex].hidden = hidden;
57453 this.totalWidth = null;
57454 this.fireEvent("hiddenchange", this, colIndex, hidden);
57458 * Sets the editor for a column.
57459 * @param {Number} col The column index
57460 * @param {Object} editor The editor object
57462 setEditor : function(col, editor){
57463 this.config[col].editor = editor;
57467 Roo.grid.ColumnModel.defaultRenderer = function(value)
57469 if(typeof value == "object") {
57472 if(typeof value == "string" && value.length < 1){
57476 return String.format("{0}", value);
57479 // Alias for backwards compatibility
57480 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57483 * Ext JS Library 1.1.1
57484 * Copyright(c) 2006-2007, Ext JS, LLC.
57486 * Originally Released Under LGPL - original licence link has changed is not relivant.
57489 * <script type="text/javascript">
57493 * @class Roo.grid.AbstractSelectionModel
57494 * @extends Roo.util.Observable
57495 * Abstract base class for grid SelectionModels. It provides the interface that should be
57496 * implemented by descendant classes. This class should not be directly instantiated.
57499 Roo.grid.AbstractSelectionModel = function(){
57500 this.locked = false;
57501 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57504 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57505 /** @ignore Called by the grid automatically. Do not call directly. */
57506 init : function(grid){
57512 * Locks the selections.
57515 this.locked = true;
57519 * Unlocks the selections.
57521 unlock : function(){
57522 this.locked = false;
57526 * Returns true if the selections are locked.
57527 * @return {Boolean}
57529 isLocked : function(){
57530 return this.locked;
57534 * Ext JS Library 1.1.1
57535 * Copyright(c) 2006-2007, Ext JS, LLC.
57537 * Originally Released Under LGPL - original licence link has changed is not relivant.
57540 * <script type="text/javascript">
57543 * @extends Roo.grid.AbstractSelectionModel
57544 * @class Roo.grid.RowSelectionModel
57545 * The default SelectionModel used by {@link Roo.grid.Grid}.
57546 * It supports multiple selections and keyboard selection/navigation.
57548 * @param {Object} config
57550 Roo.grid.RowSelectionModel = function(config){
57551 Roo.apply(this, config);
57552 this.selections = new Roo.util.MixedCollection(false, function(o){
57557 this.lastActive = false;
57561 * @event selectionchange
57562 * Fires when the selection changes
57563 * @param {SelectionModel} this
57565 "selectionchange" : true,
57567 * @event afterselectionchange
57568 * Fires after the selection changes (eg. by key press or clicking)
57569 * @param {SelectionModel} this
57571 "afterselectionchange" : true,
57573 * @event beforerowselect
57574 * Fires when a row is selected being selected, return false to cancel.
57575 * @param {SelectionModel} this
57576 * @param {Number} rowIndex The selected index
57577 * @param {Boolean} keepExisting False if other selections will be cleared
57579 "beforerowselect" : true,
57582 * Fires when a row is selected.
57583 * @param {SelectionModel} this
57584 * @param {Number} rowIndex The selected index
57585 * @param {Roo.data.Record} r The record
57587 "rowselect" : true,
57589 * @event rowdeselect
57590 * Fires when a row is deselected.
57591 * @param {SelectionModel} this
57592 * @param {Number} rowIndex The selected index
57594 "rowdeselect" : true
57596 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57597 this.locked = false;
57600 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57602 * @cfg {Boolean} singleSelect
57603 * True to allow selection of only one row at a time (defaults to false)
57605 singleSelect : false,
57608 initEvents : function(){
57610 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57611 this.grid.on("mousedown", this.handleMouseDown, this);
57612 }else{ // allow click to work like normal
57613 this.grid.on("rowclick", this.handleDragableRowClick, this);
57616 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57617 "up" : function(e){
57619 this.selectPrevious(e.shiftKey);
57620 }else if(this.last !== false && this.lastActive !== false){
57621 var last = this.last;
57622 this.selectRange(this.last, this.lastActive-1);
57623 this.grid.getView().focusRow(this.lastActive);
57624 if(last !== false){
57628 this.selectFirstRow();
57630 this.fireEvent("afterselectionchange", this);
57632 "down" : function(e){
57634 this.selectNext(e.shiftKey);
57635 }else if(this.last !== false && this.lastActive !== false){
57636 var last = this.last;
57637 this.selectRange(this.last, this.lastActive+1);
57638 this.grid.getView().focusRow(this.lastActive);
57639 if(last !== false){
57643 this.selectFirstRow();
57645 this.fireEvent("afterselectionchange", this);
57650 var view = this.grid.view;
57651 view.on("refresh", this.onRefresh, this);
57652 view.on("rowupdated", this.onRowUpdated, this);
57653 view.on("rowremoved", this.onRemove, this);
57657 onRefresh : function(){
57658 var ds = this.grid.dataSource, i, v = this.grid.view;
57659 var s = this.selections;
57660 s.each(function(r){
57661 if((i = ds.indexOfId(r.id)) != -1){
57663 s.add(ds.getAt(i)); // updating the selection relate data
57671 onRemove : function(v, index, r){
57672 this.selections.remove(r);
57676 onRowUpdated : function(v, index, r){
57677 if(this.isSelected(r)){
57678 v.onRowSelect(index);
57684 * @param {Array} records The records to select
57685 * @param {Boolean} keepExisting (optional) True to keep existing selections
57687 selectRecords : function(records, keepExisting){
57689 this.clearSelections();
57691 var ds = this.grid.dataSource;
57692 for(var i = 0, len = records.length; i < len; i++){
57693 this.selectRow(ds.indexOf(records[i]), true);
57698 * Gets the number of selected rows.
57701 getCount : function(){
57702 return this.selections.length;
57706 * Selects the first row in the grid.
57708 selectFirstRow : function(){
57713 * Select the last row.
57714 * @param {Boolean} keepExisting (optional) True to keep existing selections
57716 selectLastRow : function(keepExisting){
57717 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57721 * Selects the row immediately following the last selected row.
57722 * @param {Boolean} keepExisting (optional) True to keep existing selections
57724 selectNext : function(keepExisting){
57725 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57726 this.selectRow(this.last+1, keepExisting);
57727 this.grid.getView().focusRow(this.last);
57732 * Selects the row that precedes the last selected row.
57733 * @param {Boolean} keepExisting (optional) True to keep existing selections
57735 selectPrevious : function(keepExisting){
57737 this.selectRow(this.last-1, keepExisting);
57738 this.grid.getView().focusRow(this.last);
57743 * Returns the selected records
57744 * @return {Array} Array of selected records
57746 getSelections : function(){
57747 return [].concat(this.selections.items);
57751 * Returns the first selected record.
57754 getSelected : function(){
57755 return this.selections.itemAt(0);
57760 * Clears all selections.
57762 clearSelections : function(fast){
57767 var ds = this.grid.dataSource;
57768 var s = this.selections;
57769 s.each(function(r){
57770 this.deselectRow(ds.indexOfId(r.id));
57774 this.selections.clear();
57781 * Selects all rows.
57783 selectAll : function(){
57787 this.selections.clear();
57788 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57789 this.selectRow(i, true);
57794 * Returns True if there is a selection.
57795 * @return {Boolean}
57797 hasSelection : function(){
57798 return this.selections.length > 0;
57802 * Returns True if the specified row is selected.
57803 * @param {Number/Record} record The record or index of the record to check
57804 * @return {Boolean}
57806 isSelected : function(index){
57807 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57808 return (r && this.selections.key(r.id) ? true : false);
57812 * Returns True if the specified record id is selected.
57813 * @param {String} id The id of record to check
57814 * @return {Boolean}
57816 isIdSelected : function(id){
57817 return (this.selections.key(id) ? true : false);
57821 handleMouseDown : function(e, t){
57822 var view = this.grid.getView(), rowIndex;
57823 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57826 if(e.shiftKey && this.last !== false){
57827 var last = this.last;
57828 this.selectRange(last, rowIndex, e.ctrlKey);
57829 this.last = last; // reset the last
57830 view.focusRow(rowIndex);
57832 var isSelected = this.isSelected(rowIndex);
57833 if(e.button !== 0 && isSelected){
57834 view.focusRow(rowIndex);
57835 }else if(e.ctrlKey && isSelected){
57836 this.deselectRow(rowIndex);
57837 }else if(!isSelected){
57838 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57839 view.focusRow(rowIndex);
57842 this.fireEvent("afterselectionchange", this);
57845 handleDragableRowClick : function(grid, rowIndex, e)
57847 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57848 this.selectRow(rowIndex, false);
57849 grid.view.focusRow(rowIndex);
57850 this.fireEvent("afterselectionchange", this);
57855 * Selects multiple rows.
57856 * @param {Array} rows Array of the indexes of the row to select
57857 * @param {Boolean} keepExisting (optional) True to keep existing selections
57859 selectRows : function(rows, keepExisting){
57861 this.clearSelections();
57863 for(var i = 0, len = rows.length; i < len; i++){
57864 this.selectRow(rows[i], true);
57869 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57870 * @param {Number} startRow The index of the first row in the range
57871 * @param {Number} endRow The index of the last row in the range
57872 * @param {Boolean} keepExisting (optional) True to retain existing selections
57874 selectRange : function(startRow, endRow, keepExisting){
57879 this.clearSelections();
57881 if(startRow <= endRow){
57882 for(var i = startRow; i <= endRow; i++){
57883 this.selectRow(i, true);
57886 for(var i = startRow; i >= endRow; i--){
57887 this.selectRow(i, true);
57893 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57894 * @param {Number} startRow The index of the first row in the range
57895 * @param {Number} endRow The index of the last row in the range
57897 deselectRange : function(startRow, endRow, preventViewNotify){
57901 for(var i = startRow; i <= endRow; i++){
57902 this.deselectRow(i, preventViewNotify);
57908 * @param {Number} row The index of the row to select
57909 * @param {Boolean} keepExisting (optional) True to keep existing selections
57911 selectRow : function(index, keepExisting, preventViewNotify){
57912 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57915 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57916 if(!keepExisting || this.singleSelect){
57917 this.clearSelections();
57919 var r = this.grid.dataSource.getAt(index);
57920 this.selections.add(r);
57921 this.last = this.lastActive = index;
57922 if(!preventViewNotify){
57923 this.grid.getView().onRowSelect(index);
57925 this.fireEvent("rowselect", this, index, r);
57926 this.fireEvent("selectionchange", this);
57932 * @param {Number} row The index of the row to deselect
57934 deselectRow : function(index, preventViewNotify){
57938 if(this.last == index){
57941 if(this.lastActive == index){
57942 this.lastActive = false;
57944 var r = this.grid.dataSource.getAt(index);
57945 this.selections.remove(r);
57946 if(!preventViewNotify){
57947 this.grid.getView().onRowDeselect(index);
57949 this.fireEvent("rowdeselect", this, index);
57950 this.fireEvent("selectionchange", this);
57954 restoreLast : function(){
57956 this.last = this._last;
57961 acceptsNav : function(row, col, cm){
57962 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57966 onEditorKey : function(field, e){
57967 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57972 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57974 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57976 }else if(k == e.ENTER && !e.ctrlKey){
57980 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57982 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57984 }else if(k == e.ESC){
57988 g.startEditing(newCell[0], newCell[1]);
57993 * Ext JS Library 1.1.1
57994 * Copyright(c) 2006-2007, Ext JS, LLC.
57996 * Originally Released Under LGPL - original licence link has changed is not relivant.
57999 * <script type="text/javascript">
58002 * @class Roo.grid.CellSelectionModel
58003 * @extends Roo.grid.AbstractSelectionModel
58004 * This class provides the basic implementation for cell selection in a grid.
58006 * @param {Object} config The object containing the configuration of this model.
58007 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58009 Roo.grid.CellSelectionModel = function(config){
58010 Roo.apply(this, config);
58012 this.selection = null;
58016 * @event beforerowselect
58017 * Fires before a cell is selected.
58018 * @param {SelectionModel} this
58019 * @param {Number} rowIndex The selected row index
58020 * @param {Number} colIndex The selected cell index
58022 "beforecellselect" : true,
58024 * @event cellselect
58025 * Fires when a cell is selected.
58026 * @param {SelectionModel} this
58027 * @param {Number} rowIndex The selected row index
58028 * @param {Number} colIndex The selected cell index
58030 "cellselect" : true,
58032 * @event selectionchange
58033 * Fires when the active selection changes.
58034 * @param {SelectionModel} this
58035 * @param {Object} selection null for no selection or an object (o) with two properties
58037 <li>o.record: the record object for the row the selection is in</li>
58038 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58041 "selectionchange" : true,
58044 * Fires when the tab (or enter) was pressed on the last editable cell
58045 * You can use this to trigger add new row.
58046 * @param {SelectionModel} this
58050 * @event beforeeditnext
58051 * Fires before the next editable sell is made active
58052 * You can use this to skip to another cell or fire the tabend
58053 * if you set cell to false
58054 * @param {Object} eventdata object : { cell : [ row, col ] }
58056 "beforeeditnext" : true
58058 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58061 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58063 enter_is_tab: false,
58066 initEvents : function(){
58067 this.grid.on("mousedown", this.handleMouseDown, this);
58068 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58069 var view = this.grid.view;
58070 view.on("refresh", this.onViewChange, this);
58071 view.on("rowupdated", this.onRowUpdated, this);
58072 view.on("beforerowremoved", this.clearSelections, this);
58073 view.on("beforerowsinserted", this.clearSelections, this);
58074 if(this.grid.isEditor){
58075 this.grid.on("beforeedit", this.beforeEdit, this);
58080 beforeEdit : function(e){
58081 this.select(e.row, e.column, false, true, e.record);
58085 onRowUpdated : function(v, index, r){
58086 if(this.selection && this.selection.record == r){
58087 v.onCellSelect(index, this.selection.cell[1]);
58092 onViewChange : function(){
58093 this.clearSelections(true);
58097 * Returns the currently selected cell,.
58098 * @return {Array} The selected cell (row, column) or null if none selected.
58100 getSelectedCell : function(){
58101 return this.selection ? this.selection.cell : null;
58105 * Clears all selections.
58106 * @param {Boolean} true to prevent the gridview from being notified about the change.
58108 clearSelections : function(preventNotify){
58109 var s = this.selection;
58111 if(preventNotify !== true){
58112 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58114 this.selection = null;
58115 this.fireEvent("selectionchange", this, null);
58120 * Returns true if there is a selection.
58121 * @return {Boolean}
58123 hasSelection : function(){
58124 return this.selection ? true : false;
58128 handleMouseDown : function(e, t){
58129 var v = this.grid.getView();
58130 if(this.isLocked()){
58133 var row = v.findRowIndex(t);
58134 var cell = v.findCellIndex(t);
58135 if(row !== false && cell !== false){
58136 this.select(row, cell);
58142 * @param {Number} rowIndex
58143 * @param {Number} collIndex
58145 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58146 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58147 this.clearSelections();
58148 r = r || this.grid.dataSource.getAt(rowIndex);
58151 cell : [rowIndex, colIndex]
58153 if(!preventViewNotify){
58154 var v = this.grid.getView();
58155 v.onCellSelect(rowIndex, colIndex);
58156 if(preventFocus !== true){
58157 v.focusCell(rowIndex, colIndex);
58160 this.fireEvent("cellselect", this, rowIndex, colIndex);
58161 this.fireEvent("selectionchange", this, this.selection);
58166 isSelectable : function(rowIndex, colIndex, cm){
58167 return !cm.isHidden(colIndex);
58171 handleKeyDown : function(e){
58172 //Roo.log('Cell Sel Model handleKeyDown');
58173 if(!e.isNavKeyPress()){
58176 var g = this.grid, s = this.selection;
58179 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58181 this.select(cell[0], cell[1]);
58186 var walk = function(row, col, step){
58187 return g.walkCells(row, col, step, sm.isSelectable, sm);
58189 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58196 // handled by onEditorKey
58197 if (g.isEditor && g.editing) {
58201 newCell = walk(r, c-1, -1);
58203 newCell = walk(r, c+1, 1);
58208 newCell = walk(r+1, c, 1);
58212 newCell = walk(r-1, c, -1);
58216 newCell = walk(r, c+1, 1);
58220 newCell = walk(r, c-1, -1);
58225 if(g.isEditor && !g.editing){
58226 g.startEditing(r, c);
58235 this.select(newCell[0], newCell[1]);
58241 acceptsNav : function(row, col, cm){
58242 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58246 * @param {Number} field (not used) - as it's normally used as a listener
58247 * @param {Number} e - event - fake it by using
58249 * var e = Roo.EventObjectImpl.prototype;
58250 * e.keyCode = e.TAB
58254 onEditorKey : function(field, e){
58256 var k = e.getKey(),
58259 ed = g.activeEditor,
58261 ///Roo.log('onEditorKey' + k);
58264 if (this.enter_is_tab && k == e.ENTER) {
58270 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58272 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58278 } else if(k == e.ENTER && !e.ctrlKey){
58281 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58283 } else if(k == e.ESC){
58288 var ecall = { cell : newCell, forward : forward };
58289 this.fireEvent('beforeeditnext', ecall );
58290 newCell = ecall.cell;
58291 forward = ecall.forward;
58295 //Roo.log('next cell after edit');
58296 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58297 } else if (forward) {
58298 // tabbed past last
58299 this.fireEvent.defer(100, this, ['tabend',this]);
58304 * Ext JS Library 1.1.1
58305 * Copyright(c) 2006-2007, Ext JS, LLC.
58307 * Originally Released Under LGPL - original licence link has changed is not relivant.
58310 * <script type="text/javascript">
58314 * @class Roo.grid.EditorGrid
58315 * @extends Roo.grid.Grid
58316 * Class for creating and editable grid.
58317 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58318 * The container MUST have some type of size defined for the grid to fill. The container will be
58319 * automatically set to position relative if it isn't already.
58320 * @param {Object} dataSource The data model to bind to
58321 * @param {Object} colModel The column model with info about this grid's columns
58323 Roo.grid.EditorGrid = function(container, config){
58324 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58325 this.getGridEl().addClass("xedit-grid");
58327 if(!this.selModel){
58328 this.selModel = new Roo.grid.CellSelectionModel();
58331 this.activeEditor = null;
58335 * @event beforeedit
58336 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58337 * <ul style="padding:5px;padding-left:16px;">
58338 * <li>grid - This grid</li>
58339 * <li>record - The record being edited</li>
58340 * <li>field - The field name being edited</li>
58341 * <li>value - The value for the field being edited.</li>
58342 * <li>row - The grid row index</li>
58343 * <li>column - The grid column index</li>
58344 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58346 * @param {Object} e An edit event (see above for description)
58348 "beforeedit" : true,
58351 * Fires after a cell is edited. <br />
58352 * <ul style="padding:5px;padding-left:16px;">
58353 * <li>grid - This grid</li>
58354 * <li>record - The record being edited</li>
58355 * <li>field - The field name being edited</li>
58356 * <li>value - The value being set</li>
58357 * <li>originalValue - The original value for the field, before the edit.</li>
58358 * <li>row - The grid row index</li>
58359 * <li>column - The grid column index</li>
58361 * @param {Object} e An edit event (see above for description)
58363 "afteredit" : true,
58365 * @event validateedit
58366 * Fires after a cell is edited, but before the value is set in the record.
58367 * You can use this to modify the value being set in the field, Return false
58368 * to cancel the change. The edit event object has the following properties <br />
58369 * <ul style="padding:5px;padding-left:16px;">
58370 * <li>editor - This editor</li>
58371 * <li>grid - This grid</li>
58372 * <li>record - The record being edited</li>
58373 * <li>field - The field name being edited</li>
58374 * <li>value - The value being set</li>
58375 * <li>originalValue - The original value for the field, before the edit.</li>
58376 * <li>row - The grid row index</li>
58377 * <li>column - The grid column index</li>
58378 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58380 * @param {Object} e An edit event (see above for description)
58382 "validateedit" : true
58384 this.on("bodyscroll", this.stopEditing, this);
58385 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58388 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58390 * @cfg {Number} clicksToEdit
58391 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58398 trackMouseOver: false, // causes very odd FF errors
58400 onCellDblClick : function(g, row, col){
58401 this.startEditing(row, col);
58404 onEditComplete : function(ed, value, startValue){
58405 this.editing = false;
58406 this.activeEditor = null;
58407 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58409 var field = this.colModel.getDataIndex(ed.col);
58414 originalValue: startValue,
58421 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58424 if(String(value) !== String(startValue)){
58426 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58427 r.set(field, e.value);
58428 // if we are dealing with a combo box..
58429 // then we also set the 'name' colum to be the displayField
58430 if (ed.field.displayField && ed.field.name) {
58431 r.set(ed.field.name, ed.field.el.dom.value);
58434 delete e.cancel; //?? why!!!
58435 this.fireEvent("afteredit", e);
58438 this.fireEvent("afteredit", e); // always fire it!
58440 this.view.focusCell(ed.row, ed.col);
58444 * Starts editing the specified for the specified row/column
58445 * @param {Number} rowIndex
58446 * @param {Number} colIndex
58448 startEditing : function(row, col){
58449 this.stopEditing();
58450 if(this.colModel.isCellEditable(col, row)){
58451 this.view.ensureVisible(row, col, true);
58453 var r = this.dataSource.getAt(row);
58454 var field = this.colModel.getDataIndex(col);
58455 var cell = Roo.get(this.view.getCell(row,col));
58460 value: r.data[field],
58465 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58466 this.editing = true;
58467 var ed = this.colModel.getCellEditor(col, row);
58473 ed.render(ed.parentEl || document.body);
58479 (function(){ // complex but required for focus issues in safari, ie and opera
58483 ed.on("complete", this.onEditComplete, this, {single: true});
58484 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58485 this.activeEditor = ed;
58486 var v = r.data[field];
58487 ed.startEdit(this.view.getCell(row, col), v);
58488 // combo's with 'displayField and name set
58489 if (ed.field.displayField && ed.field.name) {
58490 ed.field.el.dom.value = r.data[ed.field.name];
58494 }).defer(50, this);
58500 * Stops any active editing
58502 stopEditing : function(){
58503 if(this.activeEditor){
58504 this.activeEditor.completeEdit();
58506 this.activeEditor = null;
58510 * Called to get grid's drag proxy text, by default returns this.ddText.
58513 getDragDropText : function(){
58514 var count = this.selModel.getSelectedCell() ? 1 : 0;
58515 return String.format(this.ddText, count, count == 1 ? '' : 's');
58520 * Ext JS Library 1.1.1
58521 * Copyright(c) 2006-2007, Ext JS, LLC.
58523 * Originally Released Under LGPL - original licence link has changed is not relivant.
58526 * <script type="text/javascript">
58529 // private - not really -- you end up using it !
58530 // This is a support class used internally by the Grid components
58533 * @class Roo.grid.GridEditor
58534 * @extends Roo.Editor
58535 * Class for creating and editable grid elements.
58536 * @param {Object} config any settings (must include field)
58538 Roo.grid.GridEditor = function(field, config){
58539 if (!config && field.field) {
58541 field = Roo.factory(config.field, Roo.form);
58543 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58544 field.monitorTab = false;
58547 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58550 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58553 alignment: "tl-tl",
58556 cls: "x-small-editor x-grid-editor",
58561 * Ext JS Library 1.1.1
58562 * Copyright(c) 2006-2007, Ext JS, LLC.
58564 * Originally Released Under LGPL - original licence link has changed is not relivant.
58567 * <script type="text/javascript">
58572 Roo.grid.PropertyRecord = Roo.data.Record.create([
58573 {name:'name',type:'string'}, 'value'
58577 Roo.grid.PropertyStore = function(grid, source){
58579 this.store = new Roo.data.Store({
58580 recordType : Roo.grid.PropertyRecord
58582 this.store.on('update', this.onUpdate, this);
58584 this.setSource(source);
58586 Roo.grid.PropertyStore.superclass.constructor.call(this);
58591 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58592 setSource : function(o){
58594 this.store.removeAll();
58597 if(this.isEditableValue(o[k])){
58598 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58601 this.store.loadRecords({records: data}, {}, true);
58604 onUpdate : function(ds, record, type){
58605 if(type == Roo.data.Record.EDIT){
58606 var v = record.data['value'];
58607 var oldValue = record.modified['value'];
58608 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58609 this.source[record.id] = v;
58611 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58618 getProperty : function(row){
58619 return this.store.getAt(row);
58622 isEditableValue: function(val){
58623 if(val && val instanceof Date){
58625 }else if(typeof val == 'object' || typeof val == 'function'){
58631 setValue : function(prop, value){
58632 this.source[prop] = value;
58633 this.store.getById(prop).set('value', value);
58636 getSource : function(){
58637 return this.source;
58641 Roo.grid.PropertyColumnModel = function(grid, store){
58644 g.PropertyColumnModel.superclass.constructor.call(this, [
58645 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58646 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58648 this.store = store;
58649 this.bselect = Roo.DomHelper.append(document.body, {
58650 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58651 {tag: 'option', value: 'true', html: 'true'},
58652 {tag: 'option', value: 'false', html: 'false'}
58655 Roo.id(this.bselect);
58658 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58659 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58660 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58661 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58662 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58664 this.renderCellDelegate = this.renderCell.createDelegate(this);
58665 this.renderPropDelegate = this.renderProp.createDelegate(this);
58668 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58672 valueText : 'Value',
58674 dateFormat : 'm/j/Y',
58677 renderDate : function(dateVal){
58678 return dateVal.dateFormat(this.dateFormat);
58681 renderBool : function(bVal){
58682 return bVal ? 'true' : 'false';
58685 isCellEditable : function(colIndex, rowIndex){
58686 return colIndex == 1;
58689 getRenderer : function(col){
58691 this.renderCellDelegate : this.renderPropDelegate;
58694 renderProp : function(v){
58695 return this.getPropertyName(v);
58698 renderCell : function(val){
58700 if(val instanceof Date){
58701 rv = this.renderDate(val);
58702 }else if(typeof val == 'boolean'){
58703 rv = this.renderBool(val);
58705 return Roo.util.Format.htmlEncode(rv);
58708 getPropertyName : function(name){
58709 var pn = this.grid.propertyNames;
58710 return pn && pn[name] ? pn[name] : name;
58713 getCellEditor : function(colIndex, rowIndex){
58714 var p = this.store.getProperty(rowIndex);
58715 var n = p.data['name'], val = p.data['value'];
58717 if(typeof(this.grid.customEditors[n]) == 'string'){
58718 return this.editors[this.grid.customEditors[n]];
58720 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58721 return this.grid.customEditors[n];
58723 if(val instanceof Date){
58724 return this.editors['date'];
58725 }else if(typeof val == 'number'){
58726 return this.editors['number'];
58727 }else if(typeof val == 'boolean'){
58728 return this.editors['boolean'];
58730 return this.editors['string'];
58736 * @class Roo.grid.PropertyGrid
58737 * @extends Roo.grid.EditorGrid
58738 * This class represents the interface of a component based property grid control.
58739 * <br><br>Usage:<pre><code>
58740 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58748 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58749 * The container MUST have some type of size defined for the grid to fill. The container will be
58750 * automatically set to position relative if it isn't already.
58751 * @param {Object} config A config object that sets properties on this grid.
58753 Roo.grid.PropertyGrid = function(container, config){
58754 config = config || {};
58755 var store = new Roo.grid.PropertyStore(this);
58756 this.store = store;
58757 var cm = new Roo.grid.PropertyColumnModel(this, store);
58758 store.store.sort('name', 'ASC');
58759 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58762 enableColLock:false,
58763 enableColumnMove:false,
58765 trackMouseOver: false,
58768 this.getGridEl().addClass('x-props-grid');
58769 this.lastEditRow = null;
58770 this.on('columnresize', this.onColumnResize, this);
58773 * @event beforepropertychange
58774 * Fires before a property changes (return false to stop?)
58775 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58776 * @param {String} id Record Id
58777 * @param {String} newval New Value
58778 * @param {String} oldval Old Value
58780 "beforepropertychange": true,
58782 * @event propertychange
58783 * Fires after a property changes
58784 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58785 * @param {String} id Record Id
58786 * @param {String} newval New Value
58787 * @param {String} oldval Old Value
58789 "propertychange": true
58791 this.customEditors = this.customEditors || {};
58793 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58796 * @cfg {Object} customEditors map of colnames=> custom editors.
58797 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58798 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58799 * false disables editing of the field.
58803 * @cfg {Object} propertyNames map of property Names to their displayed value
58806 render : function(){
58807 Roo.grid.PropertyGrid.superclass.render.call(this);
58808 this.autoSize.defer(100, this);
58811 autoSize : function(){
58812 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58814 this.view.fitColumns();
58818 onColumnResize : function(){
58819 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58823 * Sets the data for the Grid
58824 * accepts a Key => Value object of all the elements avaiable.
58825 * @param {Object} data to appear in grid.
58827 setSource : function(source){
58828 this.store.setSource(source);
58832 * Gets all the data from the grid.
58833 * @return {Object} data data stored in grid
58835 getSource : function(){
58836 return this.store.getSource();
58845 * @class Roo.grid.Calendar
58846 * @extends Roo.util.Grid
58847 * This class extends the Grid to provide a calendar widget
58848 * <br><br>Usage:<pre><code>
58849 var grid = new Roo.grid.Calendar("my-container-id", {
58852 selModel: mySelectionModel,
58853 autoSizeColumns: true,
58854 monitorWindowResize: false,
58855 trackMouseOver: true
58856 eventstore : real data store..
58862 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58863 * The container MUST have some type of size defined for the grid to fill. The container will be
58864 * automatically set to position relative if it isn't already.
58865 * @param {Object} config A config object that sets properties on this grid.
58867 Roo.grid.Calendar = function(container, config){
58868 // initialize the container
58869 this.container = Roo.get(container);
58870 this.container.update("");
58871 this.container.setStyle("overflow", "hidden");
58872 this.container.addClass('x-grid-container');
58874 this.id = this.container.id;
58876 Roo.apply(this, config);
58877 // check and correct shorthanded configs
58881 for (var r = 0;r < 6;r++) {
58884 for (var c =0;c < 7;c++) {
58888 if (this.eventStore) {
58889 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58890 this.eventStore.on('load',this.onLoad, this);
58891 this.eventStore.on('beforeload',this.clearEvents, this);
58895 this.dataSource = new Roo.data.Store({
58896 proxy: new Roo.data.MemoryProxy(rows),
58897 reader: new Roo.data.ArrayReader({}, [
58898 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58901 this.dataSource.load();
58902 this.ds = this.dataSource;
58903 this.ds.xmodule = this.xmodule || false;
58906 var cellRender = function(v,x,r)
58908 return String.format(
58909 '<div class="fc-day fc-widget-content"><div>' +
58910 '<div class="fc-event-container"></div>' +
58911 '<div class="fc-day-number">{0}</div>'+
58913 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58914 '</div></div>', v);
58919 this.colModel = new Roo.grid.ColumnModel( [
58921 xtype: 'ColumnModel',
58923 dataIndex : 'weekday0',
58925 renderer : cellRender
58928 xtype: 'ColumnModel',
58930 dataIndex : 'weekday1',
58932 renderer : cellRender
58935 xtype: 'ColumnModel',
58937 dataIndex : 'weekday2',
58938 header : 'Tuesday',
58939 renderer : cellRender
58942 xtype: 'ColumnModel',
58944 dataIndex : 'weekday3',
58945 header : 'Wednesday',
58946 renderer : cellRender
58949 xtype: 'ColumnModel',
58951 dataIndex : 'weekday4',
58952 header : 'Thursday',
58953 renderer : cellRender
58956 xtype: 'ColumnModel',
58958 dataIndex : 'weekday5',
58960 renderer : cellRender
58963 xtype: 'ColumnModel',
58965 dataIndex : 'weekday6',
58966 header : 'Saturday',
58967 renderer : cellRender
58970 this.cm = this.colModel;
58971 this.cm.xmodule = this.xmodule || false;
58975 //this.selModel = new Roo.grid.CellSelectionModel();
58976 //this.sm = this.selModel;
58977 //this.selModel.init(this);
58981 this.container.setWidth(this.width);
58985 this.container.setHeight(this.height);
58992 * The raw click event for the entire grid.
58993 * @param {Roo.EventObject} e
58998 * The raw dblclick event for the entire grid.
58999 * @param {Roo.EventObject} e
59003 * @event contextmenu
59004 * The raw contextmenu event for the entire grid.
59005 * @param {Roo.EventObject} e
59007 "contextmenu" : true,
59010 * The raw mousedown event for the entire grid.
59011 * @param {Roo.EventObject} e
59013 "mousedown" : true,
59016 * The raw mouseup event for the entire grid.
59017 * @param {Roo.EventObject} e
59022 * The raw mouseover event for the entire grid.
59023 * @param {Roo.EventObject} e
59025 "mouseover" : true,
59028 * The raw mouseout event for the entire grid.
59029 * @param {Roo.EventObject} e
59034 * The raw keypress event for the entire grid.
59035 * @param {Roo.EventObject} e
59040 * The raw keydown event for the entire grid.
59041 * @param {Roo.EventObject} e
59049 * Fires when a cell is clicked
59050 * @param {Grid} this
59051 * @param {Number} rowIndex
59052 * @param {Number} columnIndex
59053 * @param {Roo.EventObject} e
59055 "cellclick" : true,
59057 * @event celldblclick
59058 * Fires when a cell is double clicked
59059 * @param {Grid} this
59060 * @param {Number} rowIndex
59061 * @param {Number} columnIndex
59062 * @param {Roo.EventObject} e
59064 "celldblclick" : true,
59067 * Fires when a row is clicked
59068 * @param {Grid} this
59069 * @param {Number} rowIndex
59070 * @param {Roo.EventObject} e
59074 * @event rowdblclick
59075 * Fires when a row is double clicked
59076 * @param {Grid} this
59077 * @param {Number} rowIndex
59078 * @param {Roo.EventObject} e
59080 "rowdblclick" : true,
59082 * @event headerclick
59083 * Fires when a header is clicked
59084 * @param {Grid} this
59085 * @param {Number} columnIndex
59086 * @param {Roo.EventObject} e
59088 "headerclick" : true,
59090 * @event headerdblclick
59091 * Fires when a header cell is double clicked
59092 * @param {Grid} this
59093 * @param {Number} columnIndex
59094 * @param {Roo.EventObject} e
59096 "headerdblclick" : true,
59098 * @event rowcontextmenu
59099 * Fires when a row is right clicked
59100 * @param {Grid} this
59101 * @param {Number} rowIndex
59102 * @param {Roo.EventObject} e
59104 "rowcontextmenu" : true,
59106 * @event cellcontextmenu
59107 * Fires when a cell is right clicked
59108 * @param {Grid} this
59109 * @param {Number} rowIndex
59110 * @param {Number} cellIndex
59111 * @param {Roo.EventObject} e
59113 "cellcontextmenu" : true,
59115 * @event headercontextmenu
59116 * Fires when a header is right clicked
59117 * @param {Grid} this
59118 * @param {Number} columnIndex
59119 * @param {Roo.EventObject} e
59121 "headercontextmenu" : true,
59123 * @event bodyscroll
59124 * Fires when the body element is scrolled
59125 * @param {Number} scrollLeft
59126 * @param {Number} scrollTop
59128 "bodyscroll" : true,
59130 * @event columnresize
59131 * Fires when the user resizes a column
59132 * @param {Number} columnIndex
59133 * @param {Number} newSize
59135 "columnresize" : true,
59137 * @event columnmove
59138 * Fires when the user moves a column
59139 * @param {Number} oldIndex
59140 * @param {Number} newIndex
59142 "columnmove" : true,
59145 * Fires when row(s) start being dragged
59146 * @param {Grid} this
59147 * @param {Roo.GridDD} dd The drag drop object
59148 * @param {event} e The raw browser event
59150 "startdrag" : true,
59153 * Fires when a drag operation is complete
59154 * @param {Grid} this
59155 * @param {Roo.GridDD} dd The drag drop object
59156 * @param {event} e The raw browser event
59161 * Fires when dragged row(s) are dropped on a valid DD target
59162 * @param {Grid} this
59163 * @param {Roo.GridDD} dd The drag drop object
59164 * @param {String} targetId The target drag drop object
59165 * @param {event} e The raw browser event
59170 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59171 * @param {Grid} this
59172 * @param {Roo.GridDD} dd The drag drop object
59173 * @param {String} targetId The target drag drop object
59174 * @param {event} e The raw browser event
59179 * Fires when the dragged row(s) first cross another DD target while being dragged
59180 * @param {Grid} this
59181 * @param {Roo.GridDD} dd The drag drop object
59182 * @param {String} targetId The target drag drop object
59183 * @param {event} e The raw browser event
59185 "dragenter" : true,
59188 * Fires when the dragged row(s) leave another DD target while being dragged
59189 * @param {Grid} this
59190 * @param {Roo.GridDD} dd The drag drop object
59191 * @param {String} targetId The target drag drop object
59192 * @param {event} e The raw browser event
59197 * Fires when a row is rendered, so you can change add a style to it.
59198 * @param {GridView} gridview The grid view
59199 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59205 * Fires when the grid is rendered
59206 * @param {Grid} grid
59211 * Fires when a date is selected
59212 * @param {DatePicker} this
59213 * @param {Date} date The selected date
59217 * @event monthchange
59218 * Fires when the displayed month changes
59219 * @param {DatePicker} this
59220 * @param {Date} date The selected month
59222 'monthchange': true,
59224 * @event evententer
59225 * Fires when mouse over an event
59226 * @param {Calendar} this
59227 * @param {event} Event
59229 'evententer': true,
59231 * @event eventleave
59232 * Fires when the mouse leaves an
59233 * @param {Calendar} this
59236 'eventleave': true,
59238 * @event eventclick
59239 * Fires when the mouse click an
59240 * @param {Calendar} this
59243 'eventclick': true,
59245 * @event eventrender
59246 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59247 * @param {Calendar} this
59248 * @param {data} data to be modified
59250 'eventrender': true
59254 Roo.grid.Grid.superclass.constructor.call(this);
59255 this.on('render', function() {
59256 this.view.el.addClass('x-grid-cal');
59258 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59262 if (!Roo.grid.Calendar.style) {
59263 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59266 '.x-grid-cal .x-grid-col' : {
59267 height: 'auto !important',
59268 'vertical-align': 'top'
59270 '.x-grid-cal .fc-event-hori' : {
59281 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59283 * @cfg {Store} eventStore The store that loads events.
59288 activeDate : false,
59291 monitorWindowResize : false,
59294 resizeColumns : function() {
59295 var col = (this.view.el.getWidth() / 7) - 3;
59296 // loop through cols, and setWidth
59297 for(var i =0 ; i < 7 ; i++){
59298 this.cm.setColumnWidth(i, col);
59301 setDate :function(date) {
59303 Roo.log('setDate?');
59305 this.resizeColumns();
59306 var vd = this.activeDate;
59307 this.activeDate = date;
59308 // if(vd && this.el){
59309 // var t = date.getTime();
59310 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59311 // Roo.log('using add remove');
59313 // this.fireEvent('monthchange', this, date);
59315 // this.cells.removeClass("fc-state-highlight");
59316 // this.cells.each(function(c){
59317 // if(c.dateValue == t){
59318 // c.addClass("fc-state-highlight");
59319 // setTimeout(function(){
59320 // try{c.dom.firstChild.focus();}catch(e){}
59330 var days = date.getDaysInMonth();
59332 var firstOfMonth = date.getFirstDateOfMonth();
59333 var startingPos = firstOfMonth.getDay()-this.startDay;
59335 if(startingPos < this.startDay){
59339 var pm = date.add(Date.MONTH, -1);
59340 var prevStart = pm.getDaysInMonth()-startingPos;
59344 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59346 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59347 //this.cells.addClassOnOver('fc-state-hover');
59349 var cells = this.cells.elements;
59350 var textEls = this.textNodes;
59352 //Roo.each(cells, function(cell){
59353 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59356 days += startingPos;
59358 // convert everything to numbers so it's fast
59359 var day = 86400000;
59360 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59363 //Roo.log(prevStart);
59365 var today = new Date().clearTime().getTime();
59366 var sel = date.clearTime().getTime();
59367 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59368 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59369 var ddMatch = this.disabledDatesRE;
59370 var ddText = this.disabledDatesText;
59371 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59372 var ddaysText = this.disabledDaysText;
59373 var format = this.format;
59375 var setCellClass = function(cal, cell){
59377 //Roo.log('set Cell Class');
59379 var t = d.getTime();
59384 cell.dateValue = t;
59386 cell.className += " fc-today";
59387 cell.className += " fc-state-highlight";
59388 cell.title = cal.todayText;
59391 // disable highlight in other month..
59392 cell.className += " fc-state-highlight";
59397 //cell.className = " fc-state-disabled";
59398 cell.title = cal.minText;
59402 //cell.className = " fc-state-disabled";
59403 cell.title = cal.maxText;
59407 if(ddays.indexOf(d.getDay()) != -1){
59408 // cell.title = ddaysText;
59409 // cell.className = " fc-state-disabled";
59412 if(ddMatch && format){
59413 var fvalue = d.dateFormat(format);
59414 if(ddMatch.test(fvalue)){
59415 cell.title = ddText.replace("%0", fvalue);
59416 cell.className = " fc-state-disabled";
59420 if (!cell.initialClassName) {
59421 cell.initialClassName = cell.dom.className;
59424 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59429 for(; i < startingPos; i++) {
59430 cells[i].dayName = (++prevStart);
59431 Roo.log(textEls[i]);
59432 d.setDate(d.getDate()+1);
59434 //cells[i].className = "fc-past fc-other-month";
59435 setCellClass(this, cells[i]);
59440 for(; i < days; i++){
59441 intDay = i - startingPos + 1;
59442 cells[i].dayName = (intDay);
59443 d.setDate(d.getDate()+1);
59445 cells[i].className = ''; // "x-date-active";
59446 setCellClass(this, cells[i]);
59450 for(; i < 42; i++) {
59451 //textEls[i].innerHTML = (++extraDays);
59453 d.setDate(d.getDate()+1);
59454 cells[i].dayName = (++extraDays);
59455 cells[i].className = "fc-future fc-other-month";
59456 setCellClass(this, cells[i]);
59459 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59461 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59463 // this will cause all the cells to mis
59466 for (var r = 0;r < 6;r++) {
59467 for (var c =0;c < 7;c++) {
59468 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59472 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59473 for(i=0;i<cells.length;i++) {
59475 this.cells.elements[i].dayName = cells[i].dayName ;
59476 this.cells.elements[i].className = cells[i].className;
59477 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59478 this.cells.elements[i].title = cells[i].title ;
59479 this.cells.elements[i].dateValue = cells[i].dateValue ;
59485 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59486 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59488 ////if(totalRows != 6){
59489 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59490 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59493 this.fireEvent('monthchange', this, date);
59498 * Returns the grid's SelectionModel.
59499 * @return {SelectionModel}
59501 getSelectionModel : function(){
59502 if(!this.selModel){
59503 this.selModel = new Roo.grid.CellSelectionModel();
59505 return this.selModel;
59509 this.eventStore.load()
59515 findCell : function(dt) {
59516 dt = dt.clearTime().getTime();
59518 this.cells.each(function(c){
59519 //Roo.log("check " +c.dateValue + '?=' + dt);
59520 if(c.dateValue == dt){
59530 findCells : function(rec) {
59531 var s = rec.data.start_dt.clone().clearTime().getTime();
59533 var e= rec.data.end_dt.clone().clearTime().getTime();
59536 this.cells.each(function(c){
59537 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59539 if(c.dateValue > e){
59542 if(c.dateValue < s){
59551 findBestRow: function(cells)
59555 for (var i =0 ; i < cells.length;i++) {
59556 ret = Math.max(cells[i].rows || 0,ret);
59563 addItem : function(rec)
59565 // look for vertical location slot in
59566 var cells = this.findCells(rec);
59568 rec.row = this.findBestRow(cells);
59570 // work out the location.
59574 for(var i =0; i < cells.length; i++) {
59582 if (crow.start.getY() == cells[i].getY()) {
59584 crow.end = cells[i];
59600 for (var i = 0; i < cells.length;i++) {
59601 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59608 clearEvents: function() {
59610 if (!this.eventStore.getCount()) {
59613 // reset number of rows in cells.
59614 Roo.each(this.cells.elements, function(c){
59618 this.eventStore.each(function(e) {
59619 this.clearEvent(e);
59624 clearEvent : function(ev)
59627 Roo.each(ev.els, function(el) {
59628 el.un('mouseenter' ,this.onEventEnter, this);
59629 el.un('mouseleave' ,this.onEventLeave, this);
59637 renderEvent : function(ev,ctr) {
59639 ctr = this.view.el.select('.fc-event-container',true).first();
59643 this.clearEvent(ev);
59649 var cells = ev.cells;
59650 var rows = ev.rows;
59651 this.fireEvent('eventrender', this, ev);
59653 for(var i =0; i < rows.length; i++) {
59657 cls += ' fc-event-start';
59659 if ((i+1) == rows.length) {
59660 cls += ' fc-event-end';
59663 //Roo.log(ev.data);
59664 // how many rows should it span..
59665 var cg = this.eventTmpl.append(ctr,Roo.apply({
59668 }, ev.data) , true);
59671 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59672 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59673 cg.on('click', this.onEventClick, this, ev);
59677 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59678 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59681 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59682 cg.setWidth(ebox.right - sbox.x -2);
59686 renderEvents: function()
59688 // first make sure there is enough space..
59690 if (!this.eventTmpl) {
59691 this.eventTmpl = new Roo.Template(
59692 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59693 '<div class="fc-event-inner">' +
59694 '<span class="fc-event-time">{time}</span>' +
59695 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59697 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59705 this.cells.each(function(c) {
59706 //Roo.log(c.select('.fc-day-content div',true).first());
59707 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59710 var ctr = this.view.el.select('.fc-event-container',true).first();
59713 this.eventStore.each(function(ev){
59715 this.renderEvent(ev);
59719 this.view.layout();
59723 onEventEnter: function (e, el,event,d) {
59724 this.fireEvent('evententer', this, el, event);
59727 onEventLeave: function (e, el,event,d) {
59728 this.fireEvent('eventleave', this, el, event);
59731 onEventClick: function (e, el,event,d) {
59732 this.fireEvent('eventclick', this, el, event);
59735 onMonthChange: function () {
59739 onLoad: function () {
59741 //Roo.log('calendar onload');
59743 if(this.eventStore.getCount() > 0){
59747 this.eventStore.each(function(d){
59752 if (typeof(add.end_dt) == 'undefined') {
59753 Roo.log("Missing End time in calendar data: ");
59757 if (typeof(add.start_dt) == 'undefined') {
59758 Roo.log("Missing Start time in calendar data: ");
59762 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59763 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59764 add.id = add.id || d.id;
59765 add.title = add.title || '??';
59773 this.renderEvents();
59783 render : function ()
59787 if (!this.view.el.hasClass('course-timesheet')) {
59788 this.view.el.addClass('course-timesheet');
59790 if (this.tsStyle) {
59795 Roo.log(_this.grid.view.el.getWidth());
59798 this.tsStyle = Roo.util.CSS.createStyleSheet({
59799 '.course-timesheet .x-grid-row' : {
59802 '.x-grid-row td' : {
59803 'vertical-align' : 0
59805 '.course-edit-link' : {
59807 'text-overflow' : 'ellipsis',
59808 'overflow' : 'hidden',
59809 'white-space' : 'nowrap',
59810 'cursor' : 'pointer'
59815 '.de-act-sup-link' : {
59816 'color' : 'purple',
59817 'text-decoration' : 'line-through'
59821 'text-decoration' : 'line-through'
59823 '.course-timesheet .course-highlight' : {
59824 'border-top-style': 'dashed !important',
59825 'border-bottom-bottom': 'dashed !important'
59827 '.course-timesheet .course-item' : {
59828 'font-family' : 'tahoma, arial, helvetica',
59829 'font-size' : '11px',
59830 'overflow' : 'hidden',
59831 'padding-left' : '10px',
59832 'padding-right' : '10px',
59833 'padding-top' : '10px'
59841 monitorWindowResize : false,
59842 cellrenderer : function(v,x,r)
59847 xtype: 'CellSelectionModel',
59854 beforeload : function (_self, options)
59856 options.params = options.params || {};
59857 options.params._month = _this.monthField.getValue();
59858 options.params.limit = 9999;
59859 options.params['sort'] = 'when_dt';
59860 options.params['dir'] = 'ASC';
59861 this.proxy.loadResponse = this.loadResponse;
59863 //this.addColumns();
59865 load : function (_self, records, options)
59867 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59868 // if you click on the translation.. you can edit it...
59869 var el = Roo.get(this);
59870 var id = el.dom.getAttribute('data-id');
59871 var d = el.dom.getAttribute('data-date');
59872 var t = el.dom.getAttribute('data-time');
59873 //var id = this.child('span').dom.textContent;
59876 Pman.Dialog.CourseCalendar.show({
59880 productitem_active : id ? 1 : 0
59882 _this.grid.ds.load({});
59887 _this.panel.fireEvent('resize', [ '', '' ]);
59890 loadResponse : function(o, success, response){
59891 // this is overridden on before load..
59893 Roo.log("our code?");
59894 //Roo.log(success);
59895 //Roo.log(response)
59896 delete this.activeRequest;
59898 this.fireEvent("loadexception", this, o, response);
59899 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59904 result = o.reader.read(response);
59906 Roo.log("load exception?");
59907 this.fireEvent("loadexception", this, o, response, e);
59908 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59911 Roo.log("ready...");
59912 // loop through result.records;
59913 // and set this.tdate[date] = [] << array of records..
59915 Roo.each(result.records, function(r){
59917 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59918 _this.tdata[r.data.when_dt.format('j')] = [];
59920 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59923 //Roo.log(_this.tdata);
59925 result.records = [];
59926 result.totalRecords = 6;
59928 // let's generate some duumy records for the rows.
59929 //var st = _this.dateField.getValue();
59931 // work out monday..
59932 //st = st.add(Date.DAY, -1 * st.format('w'));
59934 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59936 var firstOfMonth = date.getFirstDayOfMonth();
59937 var days = date.getDaysInMonth();
59939 var firstAdded = false;
59940 for (var i = 0; i < result.totalRecords ; i++) {
59941 //var d= st.add(Date.DAY, i);
59944 for(var w = 0 ; w < 7 ; w++){
59945 if(!firstAdded && firstOfMonth != w){
59952 var dd = (d > 0 && d < 10) ? "0"+d : d;
59953 row['weekday'+w] = String.format(
59954 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59955 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59957 date.format('Y-m-')+dd
59960 if(typeof(_this.tdata[d]) != 'undefined'){
59961 Roo.each(_this.tdata[d], function(r){
59965 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59966 if(r.parent_id*1>0){
59967 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59970 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59971 deactive = 'de-act-link';
59974 row['weekday'+w] += String.format(
59975 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59977 r.product_id_name, //1
59978 r.when_dt.format('h:ia'), //2
59988 // only do this if something added..
59990 result.records.push(_this.grid.dataSource.reader.newRow(row));
59994 // push it twice. (second one with an hour..
59998 this.fireEvent("load", this, o, o.request.arg);
59999 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60001 sortInfo : {field: 'when_dt', direction : 'ASC' },
60003 xtype: 'HttpProxy',
60006 url : baseURL + '/Roo/Shop_course.php'
60009 xtype: 'JsonReader',
60026 'name': 'parent_id',
60030 'name': 'product_id',
60034 'name': 'productitem_id',
60052 click : function (_self, e)
60054 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60055 sd.setMonth(sd.getMonth()-1);
60056 _this.monthField.setValue(sd.format('Y-m-d'));
60057 _this.grid.ds.load({});
60063 xtype: 'Separator',
60067 xtype: 'MonthField',
60070 render : function (_self)
60072 _this.monthField = _self;
60073 // _this.monthField.set today
60075 select : function (combo, date)
60077 _this.grid.ds.load({});
60080 value : (function() { return new Date(); })()
60083 xtype: 'Separator',
60089 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60099 click : function (_self, e)
60101 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60102 sd.setMonth(sd.getMonth()+1);
60103 _this.monthField.setValue(sd.format('Y-m-d'));
60104 _this.grid.ds.load({});
60117 * Ext JS Library 1.1.1
60118 * Copyright(c) 2006-2007, Ext JS, LLC.
60120 * Originally Released Under LGPL - original licence link has changed is not relivant.
60123 * <script type="text/javascript">
60127 * @class Roo.LoadMask
60128 * A simple utility class for generically masking elements while loading data. If the element being masked has
60129 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60130 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60131 * element's UpdateManager load indicator and will be destroyed after the initial load.
60133 * Create a new LoadMask
60134 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60135 * @param {Object} config The config object
60137 Roo.LoadMask = function(el, config){
60138 this.el = Roo.get(el);
60139 Roo.apply(this, config);
60141 this.store.on('beforeload', this.onBeforeLoad, this);
60142 this.store.on('load', this.onLoad, this);
60143 this.store.on('loadexception', this.onLoadException, this);
60144 this.removeMask = false;
60146 var um = this.el.getUpdateManager();
60147 um.showLoadIndicator = false; // disable the default indicator
60148 um.on('beforeupdate', this.onBeforeLoad, this);
60149 um.on('update', this.onLoad, this);
60150 um.on('failure', this.onLoad, this);
60151 this.removeMask = true;
60155 Roo.LoadMask.prototype = {
60157 * @cfg {Boolean} removeMask
60158 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60159 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60162 * @cfg {String} msg
60163 * The text to display in a centered loading message box (defaults to 'Loading...')
60165 msg : 'Loading...',
60167 * @cfg {String} msgCls
60168 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60170 msgCls : 'x-mask-loading',
60173 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60179 * Disables the mask to prevent it from being displayed
60181 disable : function(){
60182 this.disabled = true;
60186 * Enables the mask so that it can be displayed
60188 enable : function(){
60189 this.disabled = false;
60192 onLoadException : function()
60194 Roo.log(arguments);
60196 if (typeof(arguments[3]) != 'undefined') {
60197 Roo.MessageBox.alert("Error loading",arguments[3]);
60201 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60202 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60209 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60212 onLoad : function()
60214 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60218 onBeforeLoad : function(){
60219 if(!this.disabled){
60220 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60225 destroy : function(){
60227 this.store.un('beforeload', this.onBeforeLoad, this);
60228 this.store.un('load', this.onLoad, this);
60229 this.store.un('loadexception', this.onLoadException, this);
60231 var um = this.el.getUpdateManager();
60232 um.un('beforeupdate', this.onBeforeLoad, this);
60233 um.un('update', this.onLoad, this);
60234 um.un('failure', this.onLoad, this);
60239 * Ext JS Library 1.1.1
60240 * Copyright(c) 2006-2007, Ext JS, LLC.
60242 * Originally Released Under LGPL - original licence link has changed is not relivant.
60245 * <script type="text/javascript">
60250 * @class Roo.XTemplate
60251 * @extends Roo.Template
60252 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60254 var t = new Roo.XTemplate(
60255 '<select name="{name}">',
60256 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60260 // then append, applying the master template values
60263 * Supported features:
60268 {a_variable} - output encoded.
60269 {a_variable.format:("Y-m-d")} - call a method on the variable
60270 {a_variable:raw} - unencoded output
60271 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60272 {a_variable:this.method_on_template(...)} - call a method on the template object.
60277 <tpl for="a_variable or condition.."></tpl>
60278 <tpl if="a_variable or condition"></tpl>
60279 <tpl exec="some javascript"></tpl>
60280 <tpl name="named_template"></tpl> (experimental)
60282 <tpl for="."></tpl> - just iterate the property..
60283 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60287 Roo.XTemplate = function()
60289 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60296 Roo.extend(Roo.XTemplate, Roo.Template, {
60299 * The various sub templates
60304 * basic tag replacing syntax
60307 * // you can fake an object call by doing this
60311 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60314 * compile the template
60316 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60319 compile: function()
60323 s = ['<tpl>', s, '</tpl>'].join('');
60325 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60326 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60327 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60328 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60329 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60334 while(true == !!(m = s.match(re))){
60335 var forMatch = m[0].match(nameRe),
60336 ifMatch = m[0].match(ifRe),
60337 execMatch = m[0].match(execRe),
60338 namedMatch = m[0].match(namedRe),
60343 name = forMatch && forMatch[1] ? forMatch[1] : '';
60346 // if - puts fn into test..
60347 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60349 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60354 // exec - calls a function... returns empty if true is returned.
60355 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60357 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60365 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60366 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60367 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60370 var uid = namedMatch ? namedMatch[1] : id;
60374 id: namedMatch ? namedMatch[1] : id,
60381 s = s.replace(m[0], '');
60383 s = s.replace(m[0], '{xtpl'+ id + '}');
60388 for(var i = tpls.length-1; i >= 0; --i){
60389 this.compileTpl(tpls[i]);
60390 this.tpls[tpls[i].id] = tpls[i];
60392 this.master = tpls[tpls.length-1];
60396 * same as applyTemplate, except it's done to one of the subTemplates
60397 * when using named templates, you can do:
60399 * var str = pl.applySubTemplate('your-name', values);
60402 * @param {Number} id of the template
60403 * @param {Object} values to apply to template
60404 * @param {Object} parent (normaly the instance of this object)
60406 applySubTemplate : function(id, values, parent)
60410 var t = this.tpls[id];
60414 if(t.test && !t.test.call(this, values, parent)){
60418 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60419 Roo.log(e.toString());
60425 if(t.exec && t.exec.call(this, values, parent)){
60429 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60430 Roo.log(e.toString());
60435 var vs = t.target ? t.target.call(this, values, parent) : values;
60436 parent = t.target ? values : parent;
60437 if(t.target && vs instanceof Array){
60439 for(var i = 0, len = vs.length; i < len; i++){
60440 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60442 return buf.join('');
60444 return t.compiled.call(this, vs, parent);
60446 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60447 Roo.log(e.toString());
60448 Roo.log(t.compiled);
60453 compileTpl : function(tpl)
60455 var fm = Roo.util.Format;
60456 var useF = this.disableFormats !== true;
60457 var sep = Roo.isGecko ? "+" : ",";
60458 var undef = function(str) {
60459 Roo.log("Property not found :" + str);
60463 var fn = function(m, name, format, args)
60465 //Roo.log(arguments);
60466 args = args ? args.replace(/\\'/g,"'") : args;
60467 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60468 if (typeof(format) == 'undefined') {
60469 format= 'htmlEncode';
60471 if (format == 'raw' ) {
60475 if(name.substr(0, 4) == 'xtpl'){
60476 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60479 // build an array of options to determine if value is undefined..
60481 // basically get 'xxxx.yyyy' then do
60482 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60483 // (function () { Roo.log("Property not found"); return ''; })() :
60488 Roo.each(name.split('.'), function(st) {
60489 lookfor += (lookfor.length ? '.': '') + st;
60490 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60493 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60496 if(format && useF){
60498 args = args ? ',' + args : "";
60500 if(format.substr(0, 5) != "this."){
60501 format = "fm." + format + '(';
60503 format = 'this.call("'+ format.substr(5) + '", ';
60507 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60511 // called with xxyx.yuu:(test,test)
60513 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60515 // raw.. - :raw modifier..
60516 return "'"+ sep + udef_st + name + ")"+sep+"'";
60520 // branched to use + in gecko and [].join() in others
60522 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60523 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60526 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60527 body.push(tpl.body.replace(/(\r\n|\n)/g,
60528 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60529 body.push("'].join('');};};");
60530 body = body.join('');
60533 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60535 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60541 applyTemplate : function(values){
60542 return this.master.compiled.call(this, values, {});
60543 //var s = this.subs;
60546 apply : function(){
60547 return this.applyTemplate.apply(this, arguments);
60552 Roo.XTemplate.from = function(el){
60553 el = Roo.getDom(el);
60554 return new Roo.XTemplate(el.value || el.innerHTML);