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'){
7194 alert('is android : ' + Roo.isAndroid);
7195 alert('is ios : ' + Roo.isIOS);
7198 alert('Is Android');
7199 return Roo.get(document.documentElement);
7203 alert('not android');
7206 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7210 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7214 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7215 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7216 * @param {String} selector The simple selector to test
7217 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7218 search as a number or element (defaults to 10 || document.body)
7219 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7221 up : function(simpleSelector, maxDepth){
7222 return this.findParentNode(simpleSelector, maxDepth, true);
7228 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7229 * @param {String} selector The simple selector to test
7230 * @return {Boolean} True if this element matches the selector, else false
7232 is : function(simpleSelector){
7233 return Roo.DomQuery.is(this.dom, simpleSelector);
7237 * Perform animation on this element.
7238 * @param {Object} args The YUI animation control args
7239 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7240 * @param {Function} onComplete (optional) Function to call when animation completes
7241 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7242 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7243 * @return {Roo.Element} this
7245 animate : function(args, duration, onComplete, easing, animType){
7246 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7251 * @private Internal animation call
7253 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7254 animType = animType || 'run';
7256 var anim = Roo.lib.Anim[animType](
7258 (opt.duration || defaultDur) || .35,
7259 (opt.easing || defaultEase) || 'easeOut',
7261 Roo.callback(cb, this);
7262 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7270 // private legacy anim prep
7271 preanim : function(a, i){
7272 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7276 * Removes worthless text nodes
7277 * @param {Boolean} forceReclean (optional) By default the element
7278 * keeps track if it has been cleaned already so
7279 * you can call this over and over. However, if you update the element and
7280 * need to force a reclean, you can pass true.
7282 clean : function(forceReclean){
7283 if(this.isCleaned && forceReclean !== true){
7287 var d = this.dom, n = d.firstChild, ni = -1;
7289 var nx = n.nextSibling;
7290 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7297 this.isCleaned = true;
7302 calcOffsetsTo : function(el){
7305 var restorePos = false;
7306 if(el.getStyle('position') == 'static'){
7307 el.position('relative');
7312 while(op && op != d && op.tagName != 'HTML'){
7315 op = op.offsetParent;
7318 el.position('static');
7324 * Scrolls this element into view within the passed container.
7325 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7326 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7327 * @return {Roo.Element} this
7329 scrollIntoView : function(container, hscroll){
7330 var c = Roo.getDom(container) || document.body;
7333 var o = this.calcOffsetsTo(c),
7336 b = t+el.offsetHeight,
7337 r = l+el.offsetWidth;
7339 var ch = c.clientHeight;
7340 var ct = parseInt(c.scrollTop, 10);
7341 var cl = parseInt(c.scrollLeft, 10);
7343 var cr = cl + c.clientWidth;
7351 if(hscroll !== false){
7355 c.scrollLeft = r-c.clientWidth;
7362 scrollChildIntoView : function(child, hscroll){
7363 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7367 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7368 * the new height may not be available immediately.
7369 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7370 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7371 * @param {Function} onComplete (optional) Function to call when animation completes
7372 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7373 * @return {Roo.Element} this
7375 autoHeight : function(animate, duration, onComplete, easing){
7376 var oldHeight = this.getHeight();
7378 this.setHeight(1); // force clipping
7379 setTimeout(function(){
7380 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7382 this.setHeight(height);
7384 if(typeof onComplete == "function"){
7388 this.setHeight(oldHeight); // restore original height
7389 this.setHeight(height, animate, duration, function(){
7391 if(typeof onComplete == "function") { onComplete(); }
7392 }.createDelegate(this), easing);
7394 }.createDelegate(this), 0);
7399 * Returns true if this element is an ancestor of the passed element
7400 * @param {HTMLElement/String} el The element to check
7401 * @return {Boolean} True if this element is an ancestor of el, else false
7403 contains : function(el){
7404 if(!el){return false;}
7405 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7409 * Checks whether the element is currently visible using both visibility and display properties.
7410 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7411 * @return {Boolean} True if the element is currently visible, else false
7413 isVisible : function(deep) {
7414 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7415 if(deep !== true || !vis){
7418 var p = this.dom.parentNode;
7419 while(p && p.tagName.toLowerCase() != "body"){
7420 if(!Roo.fly(p, '_isVisible').isVisible()){
7429 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7430 * @param {String} selector The CSS selector
7431 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7432 * @return {CompositeElement/CompositeElementLite} The composite element
7434 select : function(selector, unique){
7435 return El.select(selector, unique, this.dom);
7439 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7440 * @param {String} selector The CSS selector
7441 * @return {Array} An array of the matched nodes
7443 query : function(selector, unique){
7444 return Roo.DomQuery.select(selector, this.dom);
7448 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7449 * @param {String} selector The CSS selector
7450 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7451 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7453 child : function(selector, returnDom){
7454 var n = Roo.DomQuery.selectNode(selector, this.dom);
7455 return returnDom ? n : Roo.get(n);
7459 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7460 * @param {String} selector The CSS selector
7461 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7462 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7464 down : function(selector, returnDom){
7465 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7466 return returnDom ? n : Roo.get(n);
7470 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7471 * @param {String} group The group the DD object is member of
7472 * @param {Object} config The DD config object
7473 * @param {Object} overrides An object containing methods to override/implement on the DD object
7474 * @return {Roo.dd.DD} The DD object
7476 initDD : function(group, config, overrides){
7477 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7478 return Roo.apply(dd, overrides);
7482 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7483 * @param {String} group The group the DDProxy object is member of
7484 * @param {Object} config The DDProxy config object
7485 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7486 * @return {Roo.dd.DDProxy} The DDProxy object
7488 initDDProxy : function(group, config, overrides){
7489 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7490 return Roo.apply(dd, overrides);
7494 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7495 * @param {String} group The group the DDTarget object is member of
7496 * @param {Object} config The DDTarget config object
7497 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7498 * @return {Roo.dd.DDTarget} The DDTarget object
7500 initDDTarget : function(group, config, overrides){
7501 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7502 return Roo.apply(dd, overrides);
7506 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7507 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7508 * @param {Boolean} visible Whether the element is visible
7509 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7510 * @return {Roo.Element} this
7512 setVisible : function(visible, animate){
7514 if(this.visibilityMode == El.DISPLAY){
7515 this.setDisplayed(visible);
7518 this.dom.style.visibility = visible ? "visible" : "hidden";
7521 // closure for composites
7523 var visMode = this.visibilityMode;
7525 this.setOpacity(.01);
7526 this.setVisible(true);
7528 this.anim({opacity: { to: (visible?1:0) }},
7529 this.preanim(arguments, 1),
7530 null, .35, 'easeIn', function(){
7532 if(visMode == El.DISPLAY){
7533 dom.style.display = "none";
7535 dom.style.visibility = "hidden";
7537 Roo.get(dom).setOpacity(1);
7545 * Returns true if display is not "none"
7548 isDisplayed : function() {
7549 return this.getStyle("display") != "none";
7553 * Toggles the element's visibility or display, depending on visibility mode.
7554 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7555 * @return {Roo.Element} this
7557 toggle : function(animate){
7558 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7563 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7564 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7565 * @return {Roo.Element} this
7567 setDisplayed : function(value) {
7568 if(typeof value == "boolean"){
7569 value = value ? this.originalDisplay : "none";
7571 this.setStyle("display", value);
7576 * Tries to focus the element. Any exceptions are caught and ignored.
7577 * @return {Roo.Element} this
7579 focus : function() {
7587 * Tries to blur the element. Any exceptions are caught and ignored.
7588 * @return {Roo.Element} this
7598 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7599 * @param {String/Array} className The CSS class to add, or an array of classes
7600 * @return {Roo.Element} this
7602 addClass : function(className){
7603 if(className instanceof Array){
7604 for(var i = 0, len = className.length; i < len; i++) {
7605 this.addClass(className[i]);
7608 if(className && !this.hasClass(className)){
7609 this.dom.className = this.dom.className + " " + className;
7616 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7617 * @param {String/Array} className The CSS class to add, or an array of classes
7618 * @return {Roo.Element} this
7620 radioClass : function(className){
7621 var siblings = this.dom.parentNode.childNodes;
7622 for(var i = 0; i < siblings.length; i++) {
7623 var s = siblings[i];
7624 if(s.nodeType == 1){
7625 Roo.get(s).removeClass(className);
7628 this.addClass(className);
7633 * Removes one or more CSS classes from the element.
7634 * @param {String/Array} className The CSS class to remove, or an array of classes
7635 * @return {Roo.Element} this
7637 removeClass : function(className){
7638 if(!className || !this.dom.className){
7641 if(className instanceof Array){
7642 for(var i = 0, len = className.length; i < len; i++) {
7643 this.removeClass(className[i]);
7646 if(this.hasClass(className)){
7647 var re = this.classReCache[className];
7649 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7650 this.classReCache[className] = re;
7652 this.dom.className =
7653 this.dom.className.replace(re, " ");
7663 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7664 * @param {String} className The CSS class to toggle
7665 * @return {Roo.Element} this
7667 toggleClass : function(className){
7668 if(this.hasClass(className)){
7669 this.removeClass(className);
7671 this.addClass(className);
7677 * Checks if the specified CSS class exists on this element's DOM node.
7678 * @param {String} className The CSS class to check for
7679 * @return {Boolean} True if the class exists, else false
7681 hasClass : function(className){
7682 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7686 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7687 * @param {String} oldClassName The CSS class to replace
7688 * @param {String} newClassName The replacement CSS class
7689 * @return {Roo.Element} this
7691 replaceClass : function(oldClassName, newClassName){
7692 this.removeClass(oldClassName);
7693 this.addClass(newClassName);
7698 * Returns an object with properties matching the styles requested.
7699 * For example, el.getStyles('color', 'font-size', 'width') might return
7700 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7701 * @param {String} style1 A style name
7702 * @param {String} style2 A style name
7703 * @param {String} etc.
7704 * @return {Object} The style object
7706 getStyles : function(){
7707 var a = arguments, len = a.length, r = {};
7708 for(var i = 0; i < len; i++){
7709 r[a[i]] = this.getStyle(a[i]);
7715 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7716 * @param {String} property The style property whose value is returned.
7717 * @return {String} The current value of the style property for this element.
7719 getStyle : function(){
7720 return view && view.getComputedStyle ?
7722 var el = this.dom, v, cs, camel;
7723 if(prop == 'float'){
7726 if(el.style && (v = el.style[prop])){
7729 if(cs = view.getComputedStyle(el, "")){
7730 if(!(camel = propCache[prop])){
7731 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7738 var el = this.dom, v, cs, camel;
7739 if(prop == 'opacity'){
7740 if(typeof el.style.filter == 'string'){
7741 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7743 var fv = parseFloat(m[1]);
7745 return fv ? fv / 100 : 0;
7750 }else if(prop == 'float'){
7751 prop = "styleFloat";
7753 if(!(camel = propCache[prop])){
7754 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7756 if(v = el.style[camel]){
7759 if(cs = el.currentStyle){
7767 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7768 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7769 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7770 * @return {Roo.Element} this
7772 setStyle : function(prop, value){
7773 if(typeof prop == "string"){
7775 if (prop == 'float') {
7776 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7781 if(!(camel = propCache[prop])){
7782 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7785 if(camel == 'opacity') {
7786 this.setOpacity(value);
7788 this.dom.style[camel] = value;
7791 for(var style in prop){
7792 if(typeof prop[style] != "function"){
7793 this.setStyle(style, prop[style]);
7801 * More flexible version of {@link #setStyle} for setting style properties.
7802 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7803 * a function which returns such a specification.
7804 * @return {Roo.Element} this
7806 applyStyles : function(style){
7807 Roo.DomHelper.applyStyles(this.dom, style);
7812 * 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).
7813 * @return {Number} The X position of the element
7816 return D.getX(this.dom);
7820 * 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).
7821 * @return {Number} The Y position of the element
7824 return D.getY(this.dom);
7828 * 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).
7829 * @return {Array} The XY position of the element
7832 return D.getXY(this.dom);
7836 * 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).
7837 * @param {Number} The X position of the element
7838 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839 * @return {Roo.Element} this
7841 setX : function(x, animate){
7843 D.setX(this.dom, x);
7845 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7851 * 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).
7852 * @param {Number} The Y position of the element
7853 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7854 * @return {Roo.Element} this
7856 setY : function(y, animate){
7858 D.setY(this.dom, y);
7860 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7866 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7867 * @param {String} left The left CSS property value
7868 * @return {Roo.Element} this
7870 setLeft : function(left){
7871 this.setStyle("left", this.addUnits(left));
7876 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7877 * @param {String} top The top CSS property value
7878 * @return {Roo.Element} this
7880 setTop : function(top){
7881 this.setStyle("top", this.addUnits(top));
7886 * Sets the element's CSS right style.
7887 * @param {String} right The right CSS property value
7888 * @return {Roo.Element} this
7890 setRight : function(right){
7891 this.setStyle("right", this.addUnits(right));
7896 * Sets the element's CSS bottom style.
7897 * @param {String} bottom The bottom CSS property value
7898 * @return {Roo.Element} this
7900 setBottom : function(bottom){
7901 this.setStyle("bottom", this.addUnits(bottom));
7906 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7907 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7908 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7909 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setXY : function(pos, animate){
7914 D.setXY(this.dom, pos);
7916 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7922 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7923 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7924 * @param {Number} x X value for new position (coordinates are page-based)
7925 * @param {Number} y Y value for new position (coordinates are page-based)
7926 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 setLocation : function(x, y, animate){
7930 this.setXY([x, y], this.preanim(arguments, 2));
7935 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7936 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7937 * @param {Number} x X value for new position (coordinates are page-based)
7938 * @param {Number} y Y value for new position (coordinates are page-based)
7939 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7940 * @return {Roo.Element} this
7942 moveTo : function(x, y, animate){
7943 this.setXY([x, y], this.preanim(arguments, 2));
7948 * Returns the region of the given element.
7949 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7950 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7952 getRegion : function(){
7953 return D.getRegion(this.dom);
7957 * Returns the offset height of the element
7958 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7959 * @return {Number} The element's height
7961 getHeight : function(contentHeight){
7962 var h = this.dom.offsetHeight || 0;
7963 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7967 * Returns the offset width of the element
7968 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7969 * @return {Number} The element's width
7971 getWidth : function(contentWidth){
7972 var w = this.dom.offsetWidth || 0;
7973 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7977 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7978 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7979 * if a height has not been set using CSS.
7982 getComputedHeight : function(){
7983 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7985 h = parseInt(this.getStyle('height'), 10) || 0;
7986 if(!this.isBorderBox()){
7987 h += this.getFrameWidth('tb');
7994 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7995 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7996 * if a width has not been set using CSS.
7999 getComputedWidth : function(){
8000 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8002 w = parseInt(this.getStyle('width'), 10) || 0;
8003 if(!this.isBorderBox()){
8004 w += this.getFrameWidth('lr');
8011 * Returns the size of the element.
8012 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8013 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8015 getSize : function(contentSize){
8016 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8020 * Returns the width and height of the viewport.
8021 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8023 getViewSize : function(){
8024 var d = this.dom, doc = document, aw = 0, ah = 0;
8025 if(d == doc || d == doc.body){
8026 return {width : D.getViewWidth(), height: D.getViewHeight()};
8029 width : d.clientWidth,
8030 height: d.clientHeight
8036 * Returns the value of the "value" attribute
8037 * @param {Boolean} asNumber true to parse the value as a number
8038 * @return {String/Number}
8040 getValue : function(asNumber){
8041 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8045 adjustWidth : function(width){
8046 if(typeof width == "number"){
8047 if(this.autoBoxAdjust && !this.isBorderBox()){
8048 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8058 adjustHeight : function(height){
8059 if(typeof height == "number"){
8060 if(this.autoBoxAdjust && !this.isBorderBox()){
8061 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8071 * Set the width of the element
8072 * @param {Number} width The new width
8073 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8074 * @return {Roo.Element} this
8076 setWidth : function(width, animate){
8077 width = this.adjustWidth(width);
8079 this.dom.style.width = this.addUnits(width);
8081 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8087 * Set the height of the element
8088 * @param {Number} height The new height
8089 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8090 * @return {Roo.Element} this
8092 setHeight : function(height, animate){
8093 height = this.adjustHeight(height);
8095 this.dom.style.height = this.addUnits(height);
8097 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8103 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8104 * @param {Number} width The new width
8105 * @param {Number} height The new height
8106 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8107 * @return {Roo.Element} this
8109 setSize : function(width, height, animate){
8110 if(typeof width == "object"){ // in case of object from getSize()
8111 height = width.height; width = width.width;
8113 width = this.adjustWidth(width); height = this.adjustHeight(height);
8115 this.dom.style.width = this.addUnits(width);
8116 this.dom.style.height = this.addUnits(height);
8118 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8124 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8125 * @param {Number} x X value for new position (coordinates are page-based)
8126 * @param {Number} y Y value for new position (coordinates are page-based)
8127 * @param {Number} width The new width
8128 * @param {Number} height The new height
8129 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8130 * @return {Roo.Element} this
8132 setBounds : function(x, y, width, height, animate){
8134 this.setSize(width, height);
8135 this.setLocation(x, y);
8137 width = this.adjustWidth(width); height = this.adjustHeight(height);
8138 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8139 this.preanim(arguments, 4), 'motion');
8145 * 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.
8146 * @param {Roo.lib.Region} region The region to fill
8147 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8148 * @return {Roo.Element} this
8150 setRegion : function(region, animate){
8151 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8156 * Appends an event handler
8158 * @param {String} eventName The type of event to append
8159 * @param {Function} fn The method the event invokes
8160 * @param {Object} scope (optional) The scope (this object) of the fn
8161 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8163 addListener : function(eventName, fn, scope, options){
8165 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8170 * Removes an event handler from this element
8171 * @param {String} eventName the type of event to remove
8172 * @param {Function} fn the method the event invokes
8173 * @return {Roo.Element} this
8175 removeListener : function(eventName, fn){
8176 Roo.EventManager.removeListener(this.dom, eventName, fn);
8181 * Removes all previous added listeners from this element
8182 * @return {Roo.Element} this
8184 removeAllListeners : function(){
8185 E.purgeElement(this.dom);
8189 relayEvent : function(eventName, observable){
8190 this.on(eventName, function(e){
8191 observable.fireEvent(eventName, e);
8196 * Set the opacity of the element
8197 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8198 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8199 * @return {Roo.Element} this
8201 setOpacity : function(opacity, animate){
8203 var s = this.dom.style;
8206 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8207 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8209 s.opacity = opacity;
8212 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8218 * Gets the left X coordinate
8219 * @param {Boolean} local True to get the local css position instead of page coordinate
8222 getLeft : function(local){
8226 return parseInt(this.getStyle("left"), 10) || 0;
8231 * Gets the right X coordinate of the element (element X position + element width)
8232 * @param {Boolean} local True to get the local css position instead of page coordinate
8235 getRight : function(local){
8237 return this.getX() + this.getWidth();
8239 return (this.getLeft(true) + this.getWidth()) || 0;
8244 * Gets the top Y coordinate
8245 * @param {Boolean} local True to get the local css position instead of page coordinate
8248 getTop : function(local) {
8252 return parseInt(this.getStyle("top"), 10) || 0;
8257 * Gets the bottom Y coordinate of the element (element Y position + element height)
8258 * @param {Boolean} local True to get the local css position instead of page coordinate
8261 getBottom : function(local){
8263 return this.getY() + this.getHeight();
8265 return (this.getTop(true) + this.getHeight()) || 0;
8270 * Initializes positioning on this element. If a desired position is not passed, it will make the
8271 * the element positioned relative IF it is not already positioned.
8272 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8273 * @param {Number} zIndex (optional) The zIndex to apply
8274 * @param {Number} x (optional) Set the page X position
8275 * @param {Number} y (optional) Set the page Y position
8277 position : function(pos, zIndex, x, y){
8279 if(this.getStyle('position') == 'static'){
8280 this.setStyle('position', 'relative');
8283 this.setStyle("position", pos);
8286 this.setStyle("z-index", zIndex);
8288 if(x !== undefined && y !== undefined){
8290 }else if(x !== undefined){
8292 }else if(y !== undefined){
8298 * Clear positioning back to the default when the document was loaded
8299 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8300 * @return {Roo.Element} this
8302 clearPositioning : function(value){
8310 "position" : "static"
8316 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8317 * snapshot before performing an update and then restoring the element.
8320 getPositioning : function(){
8321 var l = this.getStyle("left");
8322 var t = this.getStyle("top");
8324 "position" : this.getStyle("position"),
8326 "right" : l ? "" : this.getStyle("right"),
8328 "bottom" : t ? "" : this.getStyle("bottom"),
8329 "z-index" : this.getStyle("z-index")
8334 * Gets the width of the border(s) for the specified side(s)
8335 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8336 * passing lr would get the border (l)eft width + the border (r)ight width.
8337 * @return {Number} The width of the sides passed added together
8339 getBorderWidth : function(side){
8340 return this.addStyles(side, El.borders);
8344 * Gets the width of the padding(s) for the specified side(s)
8345 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8346 * passing lr would get the padding (l)eft + the padding (r)ight.
8347 * @return {Number} The padding of the sides passed added together
8349 getPadding : function(side){
8350 return this.addStyles(side, El.paddings);
8354 * Set positioning with an object returned by getPositioning().
8355 * @param {Object} posCfg
8356 * @return {Roo.Element} this
8358 setPositioning : function(pc){
8359 this.applyStyles(pc);
8360 if(pc.right == "auto"){
8361 this.dom.style.right = "";
8363 if(pc.bottom == "auto"){
8364 this.dom.style.bottom = "";
8370 fixDisplay : function(){
8371 if(this.getStyle("display") == "none"){
8372 this.setStyle("visibility", "hidden");
8373 this.setStyle("display", this.originalDisplay); // first try reverting to default
8374 if(this.getStyle("display") == "none"){ // if that fails, default to block
8375 this.setStyle("display", "block");
8381 * Quick set left and top adding default units
8382 * @param {String} left The left CSS property value
8383 * @param {String} top The top CSS property value
8384 * @return {Roo.Element} this
8386 setLeftTop : function(left, top){
8387 this.dom.style.left = this.addUnits(left);
8388 this.dom.style.top = this.addUnits(top);
8393 * Move this element relative to its current position.
8394 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8395 * @param {Number} distance How far to move the element in pixels
8396 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8397 * @return {Roo.Element} this
8399 move : function(direction, distance, animate){
8400 var xy = this.getXY();
8401 direction = direction.toLowerCase();
8405 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8409 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8414 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8419 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8426 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8427 * @return {Roo.Element} this
8430 if(!this.isClipped){
8431 this.isClipped = true;
8432 this.originalClip = {
8433 "o": this.getStyle("overflow"),
8434 "x": this.getStyle("overflow-x"),
8435 "y": this.getStyle("overflow-y")
8437 this.setStyle("overflow", "hidden");
8438 this.setStyle("overflow-x", "hidden");
8439 this.setStyle("overflow-y", "hidden");
8445 * Return clipping (overflow) to original clipping before clip() was called
8446 * @return {Roo.Element} this
8448 unclip : function(){
8450 this.isClipped = false;
8451 var o = this.originalClip;
8452 if(o.o){this.setStyle("overflow", o.o);}
8453 if(o.x){this.setStyle("overflow-x", o.x);}
8454 if(o.y){this.setStyle("overflow-y", o.y);}
8461 * Gets the x,y coordinates specified by the anchor position on the element.
8462 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8463 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8464 * {width: (target width), height: (target height)} (defaults to the element's current size)
8465 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8466 * @return {Array} [x, y] An array containing the element's x and y coordinates
8468 getAnchorXY : function(anchor, local, s){
8469 //Passing a different size is useful for pre-calculating anchors,
8470 //especially for anchored animations that change the el size.
8472 var w, h, vp = false;
8475 if(d == document.body || d == document){
8477 w = D.getViewWidth(); h = D.getViewHeight();
8479 w = this.getWidth(); h = this.getHeight();
8482 w = s.width; h = s.height;
8484 var x = 0, y = 0, r = Math.round;
8485 switch((anchor || "tl").toLowerCase()){
8527 var sc = this.getScroll();
8528 return [x + sc.left, y + sc.top];
8530 //Add the element's offset xy
8531 var o = this.getXY();
8532 return [x+o[0], y+o[1]];
8536 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8537 * supported position values.
8538 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8539 * @param {String} position The position to align to.
8540 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8541 * @return {Array} [x, y]
8543 getAlignToXY : function(el, p, o){
8547 throw "Element.alignTo with an element that doesn't exist";
8549 var c = false; //constrain to viewport
8550 var p1 = "", p2 = "";
8557 }else if(p.indexOf("-") == -1){
8560 p = p.toLowerCase();
8561 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8563 throw "Element.alignTo with an invalid alignment " + p;
8565 p1 = m[1]; p2 = m[2]; c = !!m[3];
8567 //Subtract the aligned el's internal xy from the target's offset xy
8568 //plus custom offset to get the aligned el's new offset xy
8569 var a1 = this.getAnchorXY(p1, true);
8570 var a2 = el.getAnchorXY(p2, false);
8571 var x = a2[0] - a1[0] + o[0];
8572 var y = a2[1] - a1[1] + o[1];
8574 //constrain the aligned el to viewport if necessary
8575 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8576 // 5px of margin for ie
8577 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8579 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8580 //perpendicular to the vp border, allow the aligned el to slide on that border,
8581 //otherwise swap the aligned el to the opposite border of the target.
8582 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8583 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8584 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8585 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8588 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8589 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8591 if((x+w) > dw + scrollX){
8592 x = swapX ? r.left-w : dw+scrollX-w;
8595 x = swapX ? r.right : scrollX;
8597 if((y+h) > dh + scrollY){
8598 y = swapY ? r.top-h : dh+scrollY-h;
8601 y = swapY ? r.bottom : scrollY;
8608 getConstrainToXY : function(){
8609 var os = {top:0, left:0, bottom:0, right: 0};
8611 return function(el, local, offsets, proposedXY){
8613 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8615 var vw, vh, vx = 0, vy = 0;
8616 if(el.dom == document.body || el.dom == document){
8617 vw = Roo.lib.Dom.getViewWidth();
8618 vh = Roo.lib.Dom.getViewHeight();
8620 vw = el.dom.clientWidth;
8621 vh = el.dom.clientHeight;
8623 var vxy = el.getXY();
8629 var s = el.getScroll();
8631 vx += offsets.left + s.left;
8632 vy += offsets.top + s.top;
8634 vw -= offsets.right;
8635 vh -= offsets.bottom;
8640 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8641 var x = xy[0], y = xy[1];
8642 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8644 // only move it if it needs it
8647 // first validate right/bottom
8656 // then make sure top/left isn't negative
8665 return moved ? [x, y] : false;
8670 adjustForConstraints : function(xy, parent, offsets){
8671 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8675 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8676 * document it aligns it to the viewport.
8677 * The position parameter is optional, and can be specified in any one of the following formats:
8679 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8680 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8681 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8682 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8683 * <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
8684 * element's anchor point, and the second value is used as the target's anchor point.</li>
8686 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8687 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8688 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8689 * that specified in order to enforce the viewport constraints.
8690 * Following are all of the supported anchor positions:
8693 ----- -----------------------------
8694 tl The top left corner (default)
8695 t The center of the top edge
8696 tr The top right corner
8697 l The center of the left edge
8698 c In the center of the element
8699 r The center of the right edge
8700 bl The bottom left corner
8701 b The center of the bottom edge
8702 br The bottom right corner
8706 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8707 el.alignTo("other-el");
8709 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8710 el.alignTo("other-el", "tr?");
8712 // align the bottom right corner of el with the center left edge of other-el
8713 el.alignTo("other-el", "br-l?");
8715 // align the center of el with the bottom left corner of other-el and
8716 // adjust the x position by -6 pixels (and the y position by 0)
8717 el.alignTo("other-el", "c-bl", [-6, 0]);
8719 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8720 * @param {String} position The position to align to.
8721 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8722 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8723 * @return {Roo.Element} this
8725 alignTo : function(element, position, offsets, animate){
8726 var xy = this.getAlignToXY(element, position, offsets);
8727 this.setXY(xy, this.preanim(arguments, 3));
8732 * Anchors an element to another element and realigns it when the window is resized.
8733 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8734 * @param {String} position The position to align to.
8735 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8736 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8737 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8738 * is a number, it is used as the buffer delay (defaults to 50ms).
8739 * @param {Function} callback The function to call after the animation finishes
8740 * @return {Roo.Element} this
8742 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8743 var action = function(){
8744 this.alignTo(el, alignment, offsets, animate);
8745 Roo.callback(callback, this);
8747 Roo.EventManager.onWindowResize(action, this);
8748 var tm = typeof monitorScroll;
8749 if(tm != 'undefined'){
8750 Roo.EventManager.on(window, 'scroll', action, this,
8751 {buffer: tm == 'number' ? monitorScroll : 50});
8753 action.call(this); // align immediately
8757 * Clears any opacity settings from this element. Required in some cases for IE.
8758 * @return {Roo.Element} this
8760 clearOpacity : function(){
8761 if (window.ActiveXObject) {
8762 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8763 this.dom.style.filter = "";
8766 this.dom.style.opacity = "";
8767 this.dom.style["-moz-opacity"] = "";
8768 this.dom.style["-khtml-opacity"] = "";
8774 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8775 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8776 * @return {Roo.Element} this
8778 hide : function(animate){
8779 this.setVisible(false, this.preanim(arguments, 0));
8784 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8785 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8786 * @return {Roo.Element} this
8788 show : function(animate){
8789 this.setVisible(true, this.preanim(arguments, 0));
8794 * @private Test if size has a unit, otherwise appends the default
8796 addUnits : function(size){
8797 return Roo.Element.addUnits(size, this.defaultUnit);
8801 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8802 * @return {Roo.Element} this
8804 beginMeasure : function(){
8806 if(el.offsetWidth || el.offsetHeight){
8807 return this; // offsets work already
8810 var p = this.dom, b = document.body; // start with this element
8811 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8812 var pe = Roo.get(p);
8813 if(pe.getStyle('display') == 'none'){
8814 changed.push({el: p, visibility: pe.getStyle("visibility")});
8815 p.style.visibility = "hidden";
8816 p.style.display = "block";
8820 this._measureChanged = changed;
8826 * Restores displays to before beginMeasure was called
8827 * @return {Roo.Element} this
8829 endMeasure : function(){
8830 var changed = this._measureChanged;
8832 for(var i = 0, len = changed.length; i < len; i++) {
8834 r.el.style.visibility = r.visibility;
8835 r.el.style.display = "none";
8837 this._measureChanged = null;
8843 * Update the innerHTML of this element, optionally searching for and processing scripts
8844 * @param {String} html The new HTML
8845 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8846 * @param {Function} callback For async script loading you can be noticed when the update completes
8847 * @return {Roo.Element} this
8849 update : function(html, loadScripts, callback){
8850 if(typeof html == "undefined"){
8853 if(loadScripts !== true){
8854 this.dom.innerHTML = html;
8855 if(typeof callback == "function"){
8863 html += '<span id="' + id + '"></span>';
8865 E.onAvailable(id, function(){
8866 var hd = document.getElementsByTagName("head")[0];
8867 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8868 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8869 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8872 while(match = re.exec(html)){
8873 var attrs = match[1];
8874 var srcMatch = attrs ? attrs.match(srcRe) : false;
8875 if(srcMatch && srcMatch[2]){
8876 var s = document.createElement("script");
8877 s.src = srcMatch[2];
8878 var typeMatch = attrs.match(typeRe);
8879 if(typeMatch && typeMatch[2]){
8880 s.type = typeMatch[2];
8883 }else if(match[2] && match[2].length > 0){
8884 if(window.execScript) {
8885 window.execScript(match[2]);
8893 window.eval(match[2]);
8897 var el = document.getElementById(id);
8898 if(el){el.parentNode.removeChild(el);}
8899 if(typeof callback == "function"){
8903 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8908 * Direct access to the UpdateManager update() method (takes the same parameters).
8909 * @param {String/Function} url The url for this request or a function to call to get the url
8910 * @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}
8911 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8912 * @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.
8913 * @return {Roo.Element} this
8916 var um = this.getUpdateManager();
8917 um.update.apply(um, arguments);
8922 * Gets this element's UpdateManager
8923 * @return {Roo.UpdateManager} The UpdateManager
8925 getUpdateManager : function(){
8926 if(!this.updateManager){
8927 this.updateManager = new Roo.UpdateManager(this);
8929 return this.updateManager;
8933 * Disables text selection for this element (normalized across browsers)
8934 * @return {Roo.Element} this
8936 unselectable : function(){
8937 this.dom.unselectable = "on";
8938 this.swallowEvent("selectstart", true);
8939 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8940 this.addClass("x-unselectable");
8945 * Calculates the x, y to center this element on the screen
8946 * @return {Array} The x, y values [x, y]
8948 getCenterXY : function(){
8949 return this.getAlignToXY(document, 'c-c');
8953 * Centers the Element in either the viewport, or another Element.
8954 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8956 center : function(centerIn){
8957 this.alignTo(centerIn || document, 'c-c');
8962 * Tests various css rules/browsers to determine if this element uses a border box
8965 isBorderBox : function(){
8966 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8970 * Return a box {x, y, width, height} that can be used to set another elements
8971 * size/location to match this element.
8972 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8973 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8974 * @return {Object} box An object in the format {x, y, width, height}
8976 getBox : function(contentBox, local){
8981 var left = parseInt(this.getStyle("left"), 10) || 0;
8982 var top = parseInt(this.getStyle("top"), 10) || 0;
8985 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8987 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8989 var l = this.getBorderWidth("l")+this.getPadding("l");
8990 var r = this.getBorderWidth("r")+this.getPadding("r");
8991 var t = this.getBorderWidth("t")+this.getPadding("t");
8992 var b = this.getBorderWidth("b")+this.getPadding("b");
8993 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)};
8995 bx.right = bx.x + bx.width;
8996 bx.bottom = bx.y + bx.height;
9001 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9002 for more information about the sides.
9003 * @param {String} sides
9006 getFrameWidth : function(sides, onlyContentBox){
9007 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9011 * 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.
9012 * @param {Object} box The box to fill {x, y, width, height}
9013 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9014 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9015 * @return {Roo.Element} this
9017 setBox : function(box, adjust, animate){
9018 var w = box.width, h = box.height;
9019 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9020 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9021 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9023 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9028 * Forces the browser to repaint this element
9029 * @return {Roo.Element} this
9031 repaint : function(){
9033 this.addClass("x-repaint");
9034 setTimeout(function(){
9035 Roo.get(dom).removeClass("x-repaint");
9041 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9042 * then it returns the calculated width of the sides (see getPadding)
9043 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9044 * @return {Object/Number}
9046 getMargins : function(side){
9049 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9050 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9051 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9052 right: parseInt(this.getStyle("margin-right"), 10) || 0
9055 return this.addStyles(side, El.margins);
9060 addStyles : function(sides, styles){
9062 for(var i = 0, len = sides.length; i < len; i++){
9063 v = this.getStyle(styles[sides.charAt(i)]);
9065 w = parseInt(v, 10);
9073 * Creates a proxy element of this element
9074 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9075 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9076 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9077 * @return {Roo.Element} The new proxy element
9079 createProxy : function(config, renderTo, matchBox){
9081 renderTo = Roo.getDom(renderTo);
9083 renderTo = document.body;
9085 config = typeof config == "object" ?
9086 config : {tag : "div", cls: config};
9087 var proxy = Roo.DomHelper.append(renderTo, config, true);
9089 proxy.setBox(this.getBox());
9095 * Puts a mask over this element to disable user interaction. Requires core.css.
9096 * This method can only be applied to elements which accept child nodes.
9097 * @param {String} msg (optional) A message to display in the mask
9098 * @param {String} msgCls (optional) A css class to apply to the msg element
9099 * @return {Element} The mask element
9101 mask : function(msg, msgCls)
9103 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9104 this.setStyle("position", "relative");
9107 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9109 this.addClass("x-masked");
9110 this._mask.setDisplayed(true);
9115 while (dom && dom.style) {
9116 if (!isNaN(parseInt(dom.style.zIndex))) {
9117 z = Math.max(z, parseInt(dom.style.zIndex));
9119 dom = dom.parentNode;
9121 // if we are masking the body - then it hides everything..
9122 if (this.dom == document.body) {
9124 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9125 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9128 if(typeof msg == 'string'){
9130 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9132 var mm = this._maskMsg;
9133 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9134 if (mm.dom.firstChild) { // weird IE issue?
9135 mm.dom.firstChild.innerHTML = msg;
9137 mm.setDisplayed(true);
9139 mm.setStyle('z-index', z + 102);
9141 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9142 this._mask.setHeight(this.getHeight());
9144 this._mask.setStyle('z-index', z + 100);
9150 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9151 * it is cached for reuse.
9153 unmask : function(removeEl){
9155 if(removeEl === true){
9156 this._mask.remove();
9159 this._maskMsg.remove();
9160 delete this._maskMsg;
9163 this._mask.setDisplayed(false);
9165 this._maskMsg.setDisplayed(false);
9169 this.removeClass("x-masked");
9173 * Returns true if this element is masked
9176 isMasked : function(){
9177 return this._mask && this._mask.isVisible();
9181 * Creates an iframe shim for this element to keep selects and other windowed objects from
9183 * @return {Roo.Element} The new shim element
9185 createShim : function(){
9186 var el = document.createElement('iframe');
9187 el.frameBorder = 'no';
9188 el.className = 'roo-shim';
9189 if(Roo.isIE && Roo.isSecure){
9190 el.src = Roo.SSL_SECURE_URL;
9192 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9193 shim.autoBoxAdjust = false;
9198 * Removes this element from the DOM and deletes it from the cache
9200 remove : function(){
9201 if(this.dom.parentNode){
9202 this.dom.parentNode.removeChild(this.dom);
9204 delete El.cache[this.dom.id];
9208 * Sets up event handlers to add and remove a css class when the mouse is over this element
9209 * @param {String} className
9210 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9211 * mouseout events for children elements
9212 * @return {Roo.Element} this
9214 addClassOnOver : function(className, preventFlicker){
9215 this.on("mouseover", function(){
9216 Roo.fly(this, '_internal').addClass(className);
9218 var removeFn = function(e){
9219 if(preventFlicker !== true || !e.within(this, true)){
9220 Roo.fly(this, '_internal').removeClass(className);
9223 this.on("mouseout", removeFn, this.dom);
9228 * Sets up event handlers to add and remove a css class when this element has the focus
9229 * @param {String} className
9230 * @return {Roo.Element} this
9232 addClassOnFocus : function(className){
9233 this.on("focus", function(){
9234 Roo.fly(this, '_internal').addClass(className);
9236 this.on("blur", function(){
9237 Roo.fly(this, '_internal').removeClass(className);
9242 * 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)
9243 * @param {String} className
9244 * @return {Roo.Element} this
9246 addClassOnClick : function(className){
9248 this.on("mousedown", function(){
9249 Roo.fly(dom, '_internal').addClass(className);
9250 var d = Roo.get(document);
9251 var fn = function(){
9252 Roo.fly(dom, '_internal').removeClass(className);
9253 d.removeListener("mouseup", fn);
9255 d.on("mouseup", fn);
9261 * Stops the specified event from bubbling and optionally prevents the default action
9262 * @param {String} eventName
9263 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9264 * @return {Roo.Element} this
9266 swallowEvent : function(eventName, preventDefault){
9267 var fn = function(e){
9268 e.stopPropagation();
9273 if(eventName instanceof Array){
9274 for(var i = 0, len = eventName.length; i < len; i++){
9275 this.on(eventName[i], fn);
9279 this.on(eventName, fn);
9286 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9289 * Sizes this element to its parent element's dimensions performing
9290 * neccessary box adjustments.
9291 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9292 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9293 * @return {Roo.Element} this
9295 fitToParent : function(monitorResize, targetParent) {
9296 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9297 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9298 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9301 var p = Roo.get(targetParent || this.dom.parentNode);
9302 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9303 if (monitorResize === true) {
9304 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9305 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9311 * Gets the next sibling, skipping text nodes
9312 * @return {HTMLElement} The next sibling or null
9314 getNextSibling : function(){
9315 var n = this.dom.nextSibling;
9316 while(n && n.nodeType != 1){
9323 * Gets the previous sibling, skipping text nodes
9324 * @return {HTMLElement} The previous sibling or null
9326 getPrevSibling : function(){
9327 var n = this.dom.previousSibling;
9328 while(n && n.nodeType != 1){
9329 n = n.previousSibling;
9336 * Appends the passed element(s) to this element
9337 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9338 * @return {Roo.Element} this
9340 appendChild: function(el){
9347 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9348 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9349 * automatically generated with the specified attributes.
9350 * @param {HTMLElement} insertBefore (optional) a child element of this element
9351 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9352 * @return {Roo.Element} The new child element
9354 createChild: function(config, insertBefore, returnDom){
9355 config = config || {tag:'div'};
9357 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9359 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9363 * Appends this element to the passed element
9364 * @param {String/HTMLElement/Element} el The new parent element
9365 * @return {Roo.Element} this
9367 appendTo: function(el){
9368 el = Roo.getDom(el);
9369 el.appendChild(this.dom);
9374 * Inserts this element before the passed element in the DOM
9375 * @param {String/HTMLElement/Element} el The element to insert before
9376 * @return {Roo.Element} this
9378 insertBefore: function(el){
9379 el = Roo.getDom(el);
9380 el.parentNode.insertBefore(this.dom, el);
9385 * Inserts this element after the passed element in the DOM
9386 * @param {String/HTMLElement/Element} el The element to insert after
9387 * @return {Roo.Element} this
9389 insertAfter: function(el){
9390 el = Roo.getDom(el);
9391 el.parentNode.insertBefore(this.dom, el.nextSibling);
9396 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9397 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9398 * @return {Roo.Element} The new child
9400 insertFirst: function(el, returnDom){
9402 if(typeof el == 'object' && !el.nodeType){ // dh config
9403 return this.createChild(el, this.dom.firstChild, returnDom);
9405 el = Roo.getDom(el);
9406 this.dom.insertBefore(el, this.dom.firstChild);
9407 return !returnDom ? Roo.get(el) : el;
9412 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9413 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9414 * @param {String} where (optional) 'before' or 'after' defaults to before
9415 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9416 * @return {Roo.Element} the inserted Element
9418 insertSibling: function(el, where, returnDom){
9419 where = where ? where.toLowerCase() : 'before';
9421 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9423 if(typeof el == 'object' && !el.nodeType){ // dh config
9424 if(where == 'after' && !this.dom.nextSibling){
9425 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9427 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9431 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9432 where == 'before' ? this.dom : this.dom.nextSibling);
9441 * Creates and wraps this element with another element
9442 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9443 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9444 * @return {HTMLElement/Element} The newly created wrapper element
9446 wrap: function(config, returnDom){
9448 config = {tag: "div"};
9450 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9451 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9456 * Replaces the passed element with this element
9457 * @param {String/HTMLElement/Element} el The element to replace
9458 * @return {Roo.Element} this
9460 replace: function(el){
9462 this.insertBefore(el);
9468 * Inserts an html fragment into this element
9469 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9470 * @param {String} html The HTML fragment
9471 * @param {Boolean} returnEl True to return an Roo.Element
9472 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9474 insertHtml : function(where, html, returnEl){
9475 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9476 return returnEl ? Roo.get(el) : el;
9480 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9481 * @param {Object} o The object with the attributes
9482 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9483 * @return {Roo.Element} this
9485 set : function(o, useSet){
9487 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9489 if(attr == "style" || typeof o[attr] == "function") { continue; }
9491 el.className = o["cls"];
9494 el.setAttribute(attr, o[attr]);
9501 Roo.DomHelper.applyStyles(el, o.style);
9507 * Convenience method for constructing a KeyMap
9508 * @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:
9509 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9510 * @param {Function} fn The function to call
9511 * @param {Object} scope (optional) The scope of the function
9512 * @return {Roo.KeyMap} The KeyMap created
9514 addKeyListener : function(key, fn, scope){
9516 if(typeof key != "object" || key instanceof Array){
9532 return new Roo.KeyMap(this, config);
9536 * Creates a KeyMap for this element
9537 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9538 * @return {Roo.KeyMap} The KeyMap created
9540 addKeyMap : function(config){
9541 return new Roo.KeyMap(this, config);
9545 * Returns true if this element is scrollable.
9548 isScrollable : function(){
9550 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9554 * 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().
9555 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9556 * @param {Number} value The new scroll value
9557 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9558 * @return {Element} this
9561 scrollTo : function(side, value, animate){
9562 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9564 this.dom[prop] = value;
9566 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9567 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9573 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9574 * within this element's scrollable range.
9575 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9576 * @param {Number} distance How far to scroll the element in pixels
9577 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9578 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9579 * was scrolled as far as it could go.
9581 scroll : function(direction, distance, animate){
9582 if(!this.isScrollable()){
9586 var l = el.scrollLeft, t = el.scrollTop;
9587 var w = el.scrollWidth, h = el.scrollHeight;
9588 var cw = el.clientWidth, ch = el.clientHeight;
9589 direction = direction.toLowerCase();
9590 var scrolled = false;
9591 var a = this.preanim(arguments, 2);
9596 var v = Math.min(l + distance, w-cw);
9597 this.scrollTo("left", v, a);
9604 var v = Math.max(l - distance, 0);
9605 this.scrollTo("left", v, a);
9613 var v = Math.max(t - distance, 0);
9614 this.scrollTo("top", v, a);
9622 var v = Math.min(t + distance, h-ch);
9623 this.scrollTo("top", v, a);
9632 * Translates the passed page coordinates into left/top css values for this element
9633 * @param {Number/Array} x The page x or an array containing [x, y]
9634 * @param {Number} y The page y
9635 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9637 translatePoints : function(x, y){
9638 if(typeof x == 'object' || x instanceof Array){
9641 var p = this.getStyle('position');
9642 var o = this.getXY();
9644 var l = parseInt(this.getStyle('left'), 10);
9645 var t = parseInt(this.getStyle('top'), 10);
9648 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9651 t = (p == "relative") ? 0 : this.dom.offsetTop;
9654 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9658 * Returns the current scroll position of the element.
9659 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9661 getScroll : function(){
9662 var d = this.dom, doc = document;
9663 if(d == doc || d == doc.body){
9664 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9665 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9666 return {left: l, top: t};
9668 return {left: d.scrollLeft, top: d.scrollTop};
9673 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9674 * are convert to standard 6 digit hex color.
9675 * @param {String} attr The css attribute
9676 * @param {String} defaultValue The default value to use when a valid color isn't found
9677 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9680 getColor : function(attr, defaultValue, prefix){
9681 var v = this.getStyle(attr);
9682 if(!v || v == "transparent" || v == "inherit") {
9683 return defaultValue;
9685 var color = typeof prefix == "undefined" ? "#" : prefix;
9686 if(v.substr(0, 4) == "rgb("){
9687 var rvs = v.slice(4, v.length -1).split(",");
9688 for(var i = 0; i < 3; i++){
9689 var h = parseInt(rvs[i]).toString(16);
9696 if(v.substr(0, 1) == "#"){
9698 for(var i = 1; i < 4; i++){
9699 var c = v.charAt(i);
9702 }else if(v.length == 7){
9703 color += v.substr(1);
9707 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9711 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9712 * gradient background, rounded corners and a 4-way shadow.
9713 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9714 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9715 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9716 * @return {Roo.Element} this
9718 boxWrap : function(cls){
9719 cls = cls || 'x-box';
9720 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9721 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9726 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9727 * @param {String} namespace The namespace in which to look for the attribute
9728 * @param {String} name The attribute name
9729 * @return {String} The attribute value
9731 getAttributeNS : Roo.isIE ? function(ns, name){
9733 var type = typeof d[ns+":"+name];
9734 if(type != 'undefined' && type != 'unknown'){
9735 return d[ns+":"+name];
9738 } : function(ns, name){
9740 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9745 * Sets or Returns the value the dom attribute value
9746 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9747 * @param {String} value (optional) The value to set the attribute to
9748 * @return {String} The attribute value
9750 attr : function(name){
9751 if (arguments.length > 1) {
9752 this.dom.setAttribute(name, arguments[1]);
9753 return arguments[1];
9755 if (typeof(name) == 'object') {
9756 for(var i in name) {
9757 this.attr(i, name[i]);
9763 if (!this.dom.hasAttribute(name)) {
9766 return this.dom.getAttribute(name);
9773 var ep = El.prototype;
9776 * Appends an event handler (Shorthand for addListener)
9777 * @param {String} eventName The type of event to append
9778 * @param {Function} fn The method the event invokes
9779 * @param {Object} scope (optional) The scope (this object) of the fn
9780 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9783 ep.on = ep.addListener;
9785 ep.mon = ep.addListener;
9788 * Removes an event handler from this element (shorthand for removeListener)
9789 * @param {String} eventName the type of event to remove
9790 * @param {Function} fn the method the event invokes
9791 * @return {Roo.Element} this
9794 ep.un = ep.removeListener;
9797 * true to automatically adjust width and height settings for box-model issues (default to true)
9799 ep.autoBoxAdjust = true;
9802 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9805 El.addUnits = function(v, defaultUnit){
9806 if(v === "" || v == "auto"){
9809 if(v === undefined){
9812 if(typeof v == "number" || !El.unitPattern.test(v)){
9813 return v + (defaultUnit || 'px');
9818 // special markup used throughout Roo when box wrapping elements
9819 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>';
9821 * Visibility mode constant - Use visibility to hide element
9827 * Visibility mode constant - Use display to hide element
9833 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9834 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9835 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9847 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9848 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9849 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9850 * @return {Element} The Element object
9853 El.get = function(el){
9855 if(!el){ return null; }
9856 if(typeof el == "string"){ // element id
9857 if(!(elm = document.getElementById(el))){
9860 if(ex = El.cache[el]){
9863 ex = El.cache[el] = new El(elm);
9866 }else if(el.tagName){ // dom element
9870 if(ex = El.cache[id]){
9873 ex = El.cache[id] = new El(el);
9876 }else if(el instanceof El){
9878 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9879 // catch case where it hasn't been appended
9880 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9883 }else if(el.isComposite){
9885 }else if(el instanceof Array){
9886 return El.select(el);
9887 }else if(el == document){
9888 // create a bogus element object representing the document object
9890 var f = function(){};
9891 f.prototype = El.prototype;
9893 docEl.dom = document;
9901 El.uncache = function(el){
9902 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9904 delete El.cache[a[i].id || a[i]];
9910 // Garbage collection - uncache elements/purge listeners on orphaned elements
9911 // so we don't hold a reference and cause the browser to retain them
9912 El.garbageCollect = function(){
9913 if(!Roo.enableGarbageCollector){
9914 clearInterval(El.collectorThread);
9917 for(var eid in El.cache){
9918 var el = El.cache[eid], d = el.dom;
9919 // -------------------------------------------------------
9920 // Determining what is garbage:
9921 // -------------------------------------------------------
9923 // dom node is null, definitely garbage
9924 // -------------------------------------------------------
9926 // no parentNode == direct orphan, definitely garbage
9927 // -------------------------------------------------------
9928 // !d.offsetParent && !document.getElementById(eid)
9929 // display none elements have no offsetParent so we will
9930 // also try to look it up by it's id. However, check
9931 // offsetParent first so we don't do unneeded lookups.
9932 // This enables collection of elements that are not orphans
9933 // directly, but somewhere up the line they have an orphan
9935 // -------------------------------------------------------
9936 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9937 delete El.cache[eid];
9938 if(d && Roo.enableListenerCollection){
9944 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9948 El.Flyweight = function(dom){
9951 El.Flyweight.prototype = El.prototype;
9953 El._flyweights = {};
9955 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9956 * the dom node can be overwritten by other code.
9957 * @param {String/HTMLElement} el The dom node or id
9958 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9959 * prevent conflicts (e.g. internally Roo uses "_internal")
9961 * @return {Element} The shared Element object
9963 El.fly = function(el, named){
9964 named = named || '_global';
9965 el = Roo.getDom(el);
9969 if(!El._flyweights[named]){
9970 El._flyweights[named] = new El.Flyweight();
9972 El._flyweights[named].dom = el;
9973 return El._flyweights[named];
9977 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9978 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9979 * Shorthand of {@link Roo.Element#get}
9980 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9981 * @return {Element} The Element object
9987 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9988 * the dom node can be overwritten by other code.
9989 * Shorthand of {@link Roo.Element#fly}
9990 * @param {String/HTMLElement} el The dom node or id
9991 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9992 * prevent conflicts (e.g. internally Roo uses "_internal")
9994 * @return {Element} The shared Element object
10000 // speedy lookup for elements never to box adjust
10001 var noBoxAdjust = Roo.isStrict ? {
10004 input:1, select:1, textarea:1
10006 if(Roo.isIE || Roo.isGecko){
10007 noBoxAdjust['button'] = 1;
10011 Roo.EventManager.on(window, 'unload', function(){
10013 delete El._flyweights;
10021 Roo.Element.selectorFunction = Roo.DomQuery.select;
10024 Roo.Element.select = function(selector, unique, root){
10026 if(typeof selector == "string"){
10027 els = Roo.Element.selectorFunction(selector, root);
10028 }else if(selector.length !== undefined){
10031 throw "Invalid selector";
10033 if(unique === true){
10034 return new Roo.CompositeElement(els);
10036 return new Roo.CompositeElementLite(els);
10040 * Selects elements based on the passed CSS selector to enable working on them as 1.
10041 * @param {String/Array} selector The CSS selector or an array of elements
10042 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10043 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10044 * @return {CompositeElementLite/CompositeElement}
10048 Roo.select = Roo.Element.select;
10065 * Ext JS Library 1.1.1
10066 * Copyright(c) 2006-2007, Ext JS, LLC.
10068 * Originally Released Under LGPL - original licence link has changed is not relivant.
10071 * <script type="text/javascript">
10076 //Notifies Element that fx methods are available
10077 Roo.enableFx = true;
10081 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10082 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10083 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10084 * Element effects to work.</p><br/>
10086 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10087 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10088 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10089 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10090 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10091 * expected results and should be done with care.</p><br/>
10093 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10094 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10097 ----- -----------------------------
10098 tl The top left corner
10099 t The center of the top edge
10100 tr The top right corner
10101 l The center of the left edge
10102 r The center of the right edge
10103 bl The bottom left corner
10104 b The center of the bottom edge
10105 br The bottom right corner
10107 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10108 * below are common options that can be passed to any Fx method.</b>
10109 * @cfg {Function} callback A function called when the effect is finished
10110 * @cfg {Object} scope The scope of the effect function
10111 * @cfg {String} easing A valid Easing value for the effect
10112 * @cfg {String} afterCls A css class to apply after the effect
10113 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10114 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10115 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10116 * effects that end with the element being visually hidden, ignored otherwise)
10117 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10118 * a function which returns such a specification that will be applied to the Element after the effect finishes
10119 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10120 * @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
10121 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10125 * Slides the element into view. An anchor point can be optionally passed to set the point of
10126 * origin for the slide effect. This function automatically handles wrapping the element with
10127 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10130 // default: slide the element in from the top
10133 // custom: slide the element in from the right with a 2-second duration
10134 el.slideIn('r', { duration: 2 });
10136 // common config options shown with default values
10142 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10143 * @param {Object} options (optional) Object literal with any of the Fx config options
10144 * @return {Roo.Element} The Element
10146 slideIn : function(anchor, o){
10147 var el = this.getFxEl();
10150 el.queueFx(o, function(){
10152 anchor = anchor || "t";
10154 // fix display to visibility
10157 // restore values after effect
10158 var r = this.getFxRestore();
10159 var b = this.getBox();
10160 // fixed size for slide
10164 var wrap = this.fxWrap(r.pos, o, "hidden");
10166 var st = this.dom.style;
10167 st.visibility = "visible";
10168 st.position = "absolute";
10170 // clear out temp styles after slide and unwrap
10171 var after = function(){
10172 el.fxUnwrap(wrap, r.pos, o);
10173 st.width = r.width;
10174 st.height = r.height;
10177 // time to calc the positions
10178 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10180 switch(anchor.toLowerCase()){
10182 wrap.setSize(b.width, 0);
10183 st.left = st.bottom = "0";
10187 wrap.setSize(0, b.height);
10188 st.right = st.top = "0";
10192 wrap.setSize(0, b.height);
10193 wrap.setX(b.right);
10194 st.left = st.top = "0";
10195 a = {width: bw, points: pt};
10198 wrap.setSize(b.width, 0);
10199 wrap.setY(b.bottom);
10200 st.left = st.top = "0";
10201 a = {height: bh, points: pt};
10204 wrap.setSize(0, 0);
10205 st.right = st.bottom = "0";
10206 a = {width: bw, height: bh};
10209 wrap.setSize(0, 0);
10210 wrap.setY(b.y+b.height);
10211 st.right = st.top = "0";
10212 a = {width: bw, height: bh, points: pt};
10215 wrap.setSize(0, 0);
10216 wrap.setXY([b.right, b.bottom]);
10217 st.left = st.top = "0";
10218 a = {width: bw, height: bh, points: pt};
10221 wrap.setSize(0, 0);
10222 wrap.setX(b.x+b.width);
10223 st.left = st.bottom = "0";
10224 a = {width: bw, height: bh, points: pt};
10227 this.dom.style.visibility = "visible";
10230 arguments.callee.anim = wrap.fxanim(a,
10240 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10241 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10242 * 'hidden') but block elements will still take up space in the document. The element must be removed
10243 * from the DOM using the 'remove' config option if desired. This function automatically handles
10244 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10247 // default: slide the element out to the top
10250 // custom: slide the element out to the right with a 2-second duration
10251 el.slideOut('r', { duration: 2 });
10253 // common config options shown with default values
10261 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10262 * @param {Object} options (optional) Object literal with any of the Fx config options
10263 * @return {Roo.Element} The Element
10265 slideOut : function(anchor, o){
10266 var el = this.getFxEl();
10269 el.queueFx(o, function(){
10271 anchor = anchor || "t";
10273 // restore values after effect
10274 var r = this.getFxRestore();
10276 var b = this.getBox();
10277 // fixed size for slide
10281 var wrap = this.fxWrap(r.pos, o, "visible");
10283 var st = this.dom.style;
10284 st.visibility = "visible";
10285 st.position = "absolute";
10289 var after = function(){
10291 el.setDisplayed(false);
10296 el.fxUnwrap(wrap, r.pos, o);
10298 st.width = r.width;
10299 st.height = r.height;
10304 var a, zero = {to: 0};
10305 switch(anchor.toLowerCase()){
10307 st.left = st.bottom = "0";
10308 a = {height: zero};
10311 st.right = st.top = "0";
10315 st.left = st.top = "0";
10316 a = {width: zero, points: {to:[b.right, b.y]}};
10319 st.left = st.top = "0";
10320 a = {height: zero, points: {to:[b.x, b.bottom]}};
10323 st.right = st.bottom = "0";
10324 a = {width: zero, height: zero};
10327 st.right = st.top = "0";
10328 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10331 st.left = st.top = "0";
10332 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10335 st.left = st.bottom = "0";
10336 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10340 arguments.callee.anim = wrap.fxanim(a,
10350 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10351 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10352 * The element must be removed from the DOM using the 'remove' config option if desired.
10358 // common config options shown with default values
10366 * @param {Object} options (optional) Object literal with any of the Fx config options
10367 * @return {Roo.Element} The Element
10369 puff : function(o){
10370 var el = this.getFxEl();
10373 el.queueFx(o, function(){
10374 this.clearOpacity();
10377 // restore values after effect
10378 var r = this.getFxRestore();
10379 var st = this.dom.style;
10381 var after = function(){
10383 el.setDisplayed(false);
10390 el.setPositioning(r.pos);
10391 st.width = r.width;
10392 st.height = r.height;
10397 var width = this.getWidth();
10398 var height = this.getHeight();
10400 arguments.callee.anim = this.fxanim({
10401 width : {to: this.adjustWidth(width * 2)},
10402 height : {to: this.adjustHeight(height * 2)},
10403 points : {by: [-(width * .5), -(height * .5)]},
10405 fontSize: {to:200, unit: "%"}
10416 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10417 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10418 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10424 // all config options shown with default values
10432 * @param {Object} options (optional) Object literal with any of the Fx config options
10433 * @return {Roo.Element} The Element
10435 switchOff : function(o){
10436 var el = this.getFxEl();
10439 el.queueFx(o, function(){
10440 this.clearOpacity();
10443 // restore values after effect
10444 var r = this.getFxRestore();
10445 var st = this.dom.style;
10447 var after = function(){
10449 el.setDisplayed(false);
10455 el.setPositioning(r.pos);
10456 st.width = r.width;
10457 st.height = r.height;
10462 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10463 this.clearOpacity();
10467 points:{by:[0, this.getHeight() * .5]}
10468 }, o, 'motion', 0.3, 'easeIn', after);
10469 }).defer(100, this);
10476 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10477 * changed using the "attr" config option) and then fading back to the original color. If no original
10478 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10481 // default: highlight background to yellow
10484 // custom: highlight foreground text to blue for 2 seconds
10485 el.highlight("0000ff", { attr: 'color', duration: 2 });
10487 // common config options shown with default values
10488 el.highlight("ffff9c", {
10489 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10490 endColor: (current color) or "ffffff",
10495 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10496 * @param {Object} options (optional) Object literal with any of the Fx config options
10497 * @return {Roo.Element} The Element
10499 highlight : function(color, o){
10500 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 color = color || "ffff9c";
10505 attr = o.attr || "backgroundColor";
10507 this.clearOpacity();
10510 var origColor = this.getColor(attr);
10511 var restoreColor = this.dom.style[attr];
10512 endColor = (o.endColor || origColor) || "ffffff";
10514 var after = function(){
10515 el.dom.style[attr] = restoreColor;
10520 a[attr] = {from: color, to: endColor};
10521 arguments.callee.anim = this.fxanim(a,
10531 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10534 // default: a single light blue ripple
10537 // custom: 3 red ripples lasting 3 seconds total
10538 el.frame("ff0000", 3, { duration: 3 });
10540 // common config options shown with default values
10541 el.frame("C3DAF9", 1, {
10542 duration: 1 //duration of entire animation (not each individual ripple)
10543 // Note: Easing is not configurable and will be ignored if included
10546 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10547 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10548 * @param {Object} options (optional) Object literal with any of the Fx config options
10549 * @return {Roo.Element} The Element
10551 frame : function(color, count, o){
10552 var el = this.getFxEl();
10555 el.queueFx(o, function(){
10556 color = color || "#C3DAF9";
10557 if(color.length == 6){
10558 color = "#" + color;
10560 count = count || 1;
10561 duration = o.duration || 1;
10564 var b = this.getBox();
10565 var animFn = function(){
10566 var proxy = this.createProxy({
10569 visbility:"hidden",
10570 position:"absolute",
10571 "z-index":"35000", // yee haw
10572 border:"0px solid " + color
10575 var scale = Roo.isBorderBox ? 2 : 1;
10577 top:{from:b.y, to:b.y - 20},
10578 left:{from:b.x, to:b.x - 20},
10579 borderWidth:{from:0, to:10},
10580 opacity:{from:1, to:0},
10581 height:{from:b.height, to:(b.height + (20*scale))},
10582 width:{from:b.width, to:(b.width + (20*scale))}
10583 }, duration, function(){
10587 animFn.defer((duration/2)*1000, this);
10598 * Creates a pause before any subsequent queued effects begin. If there are
10599 * no effects queued after the pause it will have no effect.
10604 * @param {Number} seconds The length of time to pause (in seconds)
10605 * @return {Roo.Element} The Element
10607 pause : function(seconds){
10608 var el = this.getFxEl();
10611 el.queueFx(o, function(){
10612 setTimeout(function(){
10614 }, seconds * 1000);
10620 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10621 * using the "endOpacity" config option.
10624 // default: fade in from opacity 0 to 100%
10627 // custom: fade in from opacity 0 to 75% over 2 seconds
10628 el.fadeIn({ endOpacity: .75, duration: 2});
10630 // common config options shown with default values
10632 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10637 * @param {Object} options (optional) Object literal with any of the Fx config options
10638 * @return {Roo.Element} The Element
10640 fadeIn : function(o){
10641 var el = this.getFxEl();
10643 el.queueFx(o, function(){
10644 this.setOpacity(0);
10646 this.dom.style.visibility = 'visible';
10647 var to = o.endOpacity || 1;
10648 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10649 o, null, .5, "easeOut", function(){
10651 this.clearOpacity();
10660 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10661 * using the "endOpacity" config option.
10664 // default: fade out from the element's current opacity to 0
10667 // custom: fade out from the element's current opacity to 25% over 2 seconds
10668 el.fadeOut({ endOpacity: .25, duration: 2});
10670 // common config options shown with default values
10672 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10679 * @param {Object} options (optional) Object literal with any of the Fx config options
10680 * @return {Roo.Element} The Element
10682 fadeOut : function(o){
10683 var el = this.getFxEl();
10685 el.queueFx(o, function(){
10686 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10687 o, null, .5, "easeOut", function(){
10688 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10689 this.dom.style.display = "none";
10691 this.dom.style.visibility = "hidden";
10693 this.clearOpacity();
10701 * Animates the transition of an element's dimensions from a starting height/width
10702 * to an ending height/width.
10705 // change height and width to 100x100 pixels
10706 el.scale(100, 100);
10708 // common config options shown with default values. The height and width will default to
10709 // the element's existing values if passed as null.
10712 [element's height], {
10717 * @param {Number} width The new width (pass undefined to keep the original width)
10718 * @param {Number} height The new height (pass undefined to keep the original height)
10719 * @param {Object} options (optional) Object literal with any of the Fx config options
10720 * @return {Roo.Element} The Element
10722 scale : function(w, h, o){
10723 this.shift(Roo.apply({}, o, {
10731 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10732 * Any of these properties not specified in the config object will not be changed. This effect
10733 * requires that at least one new dimension, position or opacity setting must be passed in on
10734 * the config object in order for the function to have any effect.
10737 // slide the element horizontally to x position 200 while changing the height and opacity
10738 el.shift({ x: 200, height: 50, opacity: .8 });
10740 // common config options shown with default values.
10742 width: [element's width],
10743 height: [element's height],
10744 x: [element's x position],
10745 y: [element's y position],
10746 opacity: [element's opacity],
10751 * @param {Object} options Object literal with any of the Fx config options
10752 * @return {Roo.Element} The Element
10754 shift : function(o){
10755 var el = this.getFxEl();
10757 el.queueFx(o, function(){
10758 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10759 if(w !== undefined){
10760 a.width = {to: this.adjustWidth(w)};
10762 if(h !== undefined){
10763 a.height = {to: this.adjustHeight(h)};
10765 if(x !== undefined || y !== undefined){
10767 x !== undefined ? x : this.getX(),
10768 y !== undefined ? y : this.getY()
10771 if(op !== undefined){
10772 a.opacity = {to: op};
10774 if(o.xy !== undefined){
10775 a.points = {to: o.xy};
10777 arguments.callee.anim = this.fxanim(a,
10778 o, 'motion', .35, "easeOut", function(){
10786 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10787 * ending point of the effect.
10790 // default: slide the element downward while fading out
10793 // custom: slide the element out to the right with a 2-second duration
10794 el.ghost('r', { duration: 2 });
10796 // common config options shown with default values
10804 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10805 * @param {Object} options (optional) Object literal with any of the Fx config options
10806 * @return {Roo.Element} The Element
10808 ghost : function(anchor, o){
10809 var el = this.getFxEl();
10812 el.queueFx(o, function(){
10813 anchor = anchor || "b";
10815 // restore values after effect
10816 var r = this.getFxRestore();
10817 var w = this.getWidth(),
10818 h = this.getHeight();
10820 var st = this.dom.style;
10822 var after = function(){
10824 el.setDisplayed(false);
10830 el.setPositioning(r.pos);
10831 st.width = r.width;
10832 st.height = r.height;
10837 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10838 switch(anchor.toLowerCase()){
10865 arguments.callee.anim = this.fxanim(a,
10875 * Ensures that all effects queued after syncFx is called on the element are
10876 * run concurrently. This is the opposite of {@link #sequenceFx}.
10877 * @return {Roo.Element} The Element
10879 syncFx : function(){
10880 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10889 * Ensures that all effects queued after sequenceFx is called on the element are
10890 * run in sequence. This is the opposite of {@link #syncFx}.
10891 * @return {Roo.Element} The Element
10893 sequenceFx : function(){
10894 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10896 concurrent : false,
10903 nextFx : function(){
10904 var ef = this.fxQueue[0];
10911 * Returns true if the element has any effects actively running or queued, else returns false.
10912 * @return {Boolean} True if element has active effects, else false
10914 hasActiveFx : function(){
10915 return this.fxQueue && this.fxQueue[0];
10919 * Stops any running effects and clears the element's internal effects queue if it contains
10920 * any additional effects that haven't started yet.
10921 * @return {Roo.Element} The Element
10923 stopFx : function(){
10924 if(this.hasActiveFx()){
10925 var cur = this.fxQueue[0];
10926 if(cur && cur.anim && cur.anim.isAnimated()){
10927 this.fxQueue = [cur]; // clear out others
10928 cur.anim.stop(true);
10935 beforeFx : function(o){
10936 if(this.hasActiveFx() && !o.concurrent){
10947 * Returns true if the element is currently blocking so that no other effect can be queued
10948 * until this effect is finished, else returns false if blocking is not set. This is commonly
10949 * used to ensure that an effect initiated by a user action runs to completion prior to the
10950 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10951 * @return {Boolean} True if blocking, else false
10953 hasFxBlock : function(){
10954 var q = this.fxQueue;
10955 return q && q[0] && q[0].block;
10959 queueFx : function(o, fn){
10963 if(!this.hasFxBlock()){
10964 Roo.applyIf(o, this.fxDefaults);
10966 var run = this.beforeFx(o);
10967 fn.block = o.block;
10968 this.fxQueue.push(fn);
10980 fxWrap : function(pos, o, vis){
10982 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10985 wrapXY = this.getXY();
10987 var div = document.createElement("div");
10988 div.style.visibility = vis;
10989 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10990 wrap.setPositioning(pos);
10991 if(wrap.getStyle("position") == "static"){
10992 wrap.position("relative");
10994 this.clearPositioning('auto');
10996 wrap.dom.appendChild(this.dom);
10998 wrap.setXY(wrapXY);
11005 fxUnwrap : function(wrap, pos, o){
11006 this.clearPositioning();
11007 this.setPositioning(pos);
11009 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11015 getFxRestore : function(){
11016 var st = this.dom.style;
11017 return {pos: this.getPositioning(), width: st.width, height : st.height};
11021 afterFx : function(o){
11023 this.applyStyles(o.afterStyle);
11026 this.addClass(o.afterCls);
11028 if(o.remove === true){
11031 Roo.callback(o.callback, o.scope, [this]);
11033 this.fxQueue.shift();
11039 getFxEl : function(){ // support for composite element fx
11040 return Roo.get(this.dom);
11044 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11045 animType = animType || 'run';
11047 var anim = Roo.lib.Anim[animType](
11049 (opt.duration || defaultDur) || .35,
11050 (opt.easing || defaultEase) || 'easeOut',
11052 Roo.callback(cb, this);
11061 // backwords compat
11062 Roo.Fx.resize = Roo.Fx.scale;
11064 //When included, Roo.Fx is automatically applied to Element so that all basic
11065 //effects are available directly via the Element API
11066 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11068 * Ext JS Library 1.1.1
11069 * Copyright(c) 2006-2007, Ext JS, LLC.
11071 * Originally Released Under LGPL - original licence link has changed is not relivant.
11074 * <script type="text/javascript">
11079 * @class Roo.CompositeElement
11080 * Standard composite class. Creates a Roo.Element for every element in the collection.
11082 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11083 * actions will be performed on all the elements in this collection.</b>
11085 * All methods return <i>this</i> and can be chained.
11087 var els = Roo.select("#some-el div.some-class", true);
11088 // or select directly from an existing element
11089 var el = Roo.get('some-el');
11090 el.select('div.some-class', true);
11092 els.setWidth(100); // all elements become 100 width
11093 els.hide(true); // all elements fade out and hide
11095 els.setWidth(100).hide(true);
11098 Roo.CompositeElement = function(els){
11099 this.elements = [];
11100 this.addElements(els);
11102 Roo.CompositeElement.prototype = {
11104 addElements : function(els){
11108 if(typeof els == "string"){
11109 els = Roo.Element.selectorFunction(els);
11111 var yels = this.elements;
11112 var index = yels.length-1;
11113 for(var i = 0, len = els.length; i < len; i++) {
11114 yels[++index] = Roo.get(els[i]);
11120 * Clears this composite and adds the elements returned by the passed selector.
11121 * @param {String/Array} els A string CSS selector, an array of elements or an element
11122 * @return {CompositeElement} this
11124 fill : function(els){
11125 this.elements = [];
11131 * Filters this composite to only elements that match the passed selector.
11132 * @param {String} selector A string CSS selector
11133 * @param {Boolean} inverse return inverse filter (not matches)
11134 * @return {CompositeElement} this
11136 filter : function(selector, inverse){
11138 inverse = inverse || false;
11139 this.each(function(el){
11140 var match = inverse ? !el.is(selector) : el.is(selector);
11142 els[els.length] = el.dom;
11149 invoke : function(fn, args){
11150 var els = this.elements;
11151 for(var i = 0, len = els.length; i < len; i++) {
11152 Roo.Element.prototype[fn].apply(els[i], args);
11157 * Adds elements to this composite.
11158 * @param {String/Array} els A string CSS selector, an array of elements or an element
11159 * @return {CompositeElement} this
11161 add : function(els){
11162 if(typeof els == "string"){
11163 this.addElements(Roo.Element.selectorFunction(els));
11164 }else if(els.length !== undefined){
11165 this.addElements(els);
11167 this.addElements([els]);
11172 * Calls the passed function passing (el, this, index) for each element in this composite.
11173 * @param {Function} fn The function to call
11174 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11175 * @return {CompositeElement} this
11177 each : function(fn, scope){
11178 var els = this.elements;
11179 for(var i = 0, len = els.length; i < len; i++){
11180 if(fn.call(scope || els[i], els[i], this, i) === false) {
11188 * Returns the Element object at the specified index
11189 * @param {Number} index
11190 * @return {Roo.Element}
11192 item : function(index){
11193 return this.elements[index] || null;
11197 * Returns the first Element
11198 * @return {Roo.Element}
11200 first : function(){
11201 return this.item(0);
11205 * Returns the last Element
11206 * @return {Roo.Element}
11209 return this.item(this.elements.length-1);
11213 * Returns the number of elements in this composite
11216 getCount : function(){
11217 return this.elements.length;
11221 * Returns true if this composite contains the passed element
11224 contains : function(el){
11225 return this.indexOf(el) !== -1;
11229 * Returns true if this composite contains the passed element
11232 indexOf : function(el){
11233 return this.elements.indexOf(Roo.get(el));
11238 * Removes the specified element(s).
11239 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11240 * or an array of any of those.
11241 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11242 * @return {CompositeElement} this
11244 removeElement : function(el, removeDom){
11245 if(el instanceof Array){
11246 for(var i = 0, len = el.length; i < len; i++){
11247 this.removeElement(el[i]);
11251 var index = typeof el == 'number' ? el : this.indexOf(el);
11254 var d = this.elements[index];
11258 d.parentNode.removeChild(d);
11261 this.elements.splice(index, 1);
11267 * Replaces the specified element with the passed element.
11268 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11270 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11271 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11272 * @return {CompositeElement} this
11274 replaceElement : function(el, replacement, domReplace){
11275 var index = typeof el == 'number' ? el : this.indexOf(el);
11278 this.elements[index].replaceWith(replacement);
11280 this.elements.splice(index, 1, Roo.get(replacement))
11287 * Removes all elements.
11289 clear : function(){
11290 this.elements = [];
11294 Roo.CompositeElement.createCall = function(proto, fnName){
11295 if(!proto[fnName]){
11296 proto[fnName] = function(){
11297 return this.invoke(fnName, arguments);
11301 for(var fnName in Roo.Element.prototype){
11302 if(typeof Roo.Element.prototype[fnName] == "function"){
11303 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11309 * Ext JS Library 1.1.1
11310 * Copyright(c) 2006-2007, Ext JS, LLC.
11312 * Originally Released Under LGPL - original licence link has changed is not relivant.
11315 * <script type="text/javascript">
11319 * @class Roo.CompositeElementLite
11320 * @extends Roo.CompositeElement
11321 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11323 var els = Roo.select("#some-el div.some-class");
11324 // or select directly from an existing element
11325 var el = Roo.get('some-el');
11326 el.select('div.some-class');
11328 els.setWidth(100); // all elements become 100 width
11329 els.hide(true); // all elements fade out and hide
11331 els.setWidth(100).hide(true);
11332 </code></pre><br><br>
11333 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11334 * actions will be performed on all the elements in this collection.</b>
11336 Roo.CompositeElementLite = function(els){
11337 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11338 this.el = new Roo.Element.Flyweight();
11340 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11341 addElements : function(els){
11343 if(els instanceof Array){
11344 this.elements = this.elements.concat(els);
11346 var yels = this.elements;
11347 var index = yels.length-1;
11348 for(var i = 0, len = els.length; i < len; i++) {
11349 yels[++index] = els[i];
11355 invoke : function(fn, args){
11356 var els = this.elements;
11358 for(var i = 0, len = els.length; i < len; i++) {
11360 Roo.Element.prototype[fn].apply(el, args);
11365 * Returns a flyweight Element of the dom element object at the specified index
11366 * @param {Number} index
11367 * @return {Roo.Element}
11369 item : function(index){
11370 if(!this.elements[index]){
11373 this.el.dom = this.elements[index];
11377 // fixes scope with flyweight
11378 addListener : function(eventName, handler, scope, opt){
11379 var els = this.elements;
11380 for(var i = 0, len = els.length; i < len; i++) {
11381 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11387 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11388 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11389 * a reference to the dom node, use el.dom.</b>
11390 * @param {Function} fn The function to call
11391 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11392 * @return {CompositeElement} this
11394 each : function(fn, scope){
11395 var els = this.elements;
11397 for(var i = 0, len = els.length; i < len; i++){
11399 if(fn.call(scope || el, el, this, i) === false){
11406 indexOf : function(el){
11407 return this.elements.indexOf(Roo.getDom(el));
11410 replaceElement : function(el, replacement, domReplace){
11411 var index = typeof el == 'number' ? el : this.indexOf(el);
11413 replacement = Roo.getDom(replacement);
11415 var d = this.elements[index];
11416 d.parentNode.insertBefore(replacement, d);
11417 d.parentNode.removeChild(d);
11419 this.elements.splice(index, 1, replacement);
11424 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11428 * Ext JS Library 1.1.1
11429 * Copyright(c) 2006-2007, Ext JS, LLC.
11431 * Originally Released Under LGPL - original licence link has changed is not relivant.
11434 * <script type="text/javascript">
11440 * @class Roo.data.Connection
11441 * @extends Roo.util.Observable
11442 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11443 * either to a configured URL, or to a URL specified at request time.<br><br>
11445 * Requests made by this class are asynchronous, and will return immediately. No data from
11446 * the server will be available to the statement immediately following the {@link #request} call.
11447 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11449 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11450 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11451 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11452 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11453 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11454 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11455 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11456 * standard DOM methods.
11458 * @param {Object} config a configuration object.
11460 Roo.data.Connection = function(config){
11461 Roo.apply(this, config);
11464 * @event beforerequest
11465 * Fires before a network request is made to retrieve a data object.
11466 * @param {Connection} conn This Connection object.
11467 * @param {Object} options The options config object passed to the {@link #request} method.
11469 "beforerequest" : true,
11471 * @event requestcomplete
11472 * Fires if the request was successfully completed.
11473 * @param {Connection} conn This Connection object.
11474 * @param {Object} response The XHR object containing the response data.
11475 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11476 * @param {Object} options The options config object passed to the {@link #request} method.
11478 "requestcomplete" : true,
11480 * @event requestexception
11481 * Fires if an error HTTP status was returned from the server.
11482 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11483 * @param {Connection} conn This Connection object.
11484 * @param {Object} response The XHR object containing the response data.
11485 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11486 * @param {Object} options The options config object passed to the {@link #request} method.
11488 "requestexception" : true
11490 Roo.data.Connection.superclass.constructor.call(this);
11493 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11495 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11498 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11499 * extra parameters to each request made by this object. (defaults to undefined)
11502 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11503 * to each request made by this object. (defaults to undefined)
11506 * @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)
11509 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11513 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11519 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11522 disableCaching: true,
11525 * Sends an HTTP request to a remote server.
11526 * @param {Object} options An object which may contain the following properties:<ul>
11527 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11528 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11529 * request, a url encoded string or a function to call to get either.</li>
11530 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11531 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11532 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11533 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11534 * <li>options {Object} The parameter to the request call.</li>
11535 * <li>success {Boolean} True if the request succeeded.</li>
11536 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11538 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11539 * The callback is passed the following parameters:<ul>
11540 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11541 * <li>options {Object} The parameter to the request call.</li>
11543 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11544 * The callback is passed the following parameters:<ul>
11545 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11546 * <li>options {Object} The parameter to the request call.</li>
11548 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11549 * for the callback function. Defaults to the browser window.</li>
11550 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11551 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11552 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11553 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11554 * params for the post data. Any params will be appended to the URL.</li>
11555 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11557 * @return {Number} transactionId
11559 request : function(o){
11560 if(this.fireEvent("beforerequest", this, o) !== false){
11563 if(typeof p == "function"){
11564 p = p.call(o.scope||window, o);
11566 if(typeof p == "object"){
11567 p = Roo.urlEncode(o.params);
11569 if(this.extraParams){
11570 var extras = Roo.urlEncode(this.extraParams);
11571 p = p ? (p + '&' + extras) : extras;
11574 var url = o.url || this.url;
11575 if(typeof url == 'function'){
11576 url = url.call(o.scope||window, o);
11580 var form = Roo.getDom(o.form);
11581 url = url || form.action;
11583 var enctype = form.getAttribute("enctype");
11584 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11585 return this.doFormUpload(o, p, url);
11587 var f = Roo.lib.Ajax.serializeForm(form);
11588 p = p ? (p + '&' + f) : f;
11591 var hs = o.headers;
11592 if(this.defaultHeaders){
11593 hs = Roo.apply(hs || {}, this.defaultHeaders);
11600 success: this.handleResponse,
11601 failure: this.handleFailure,
11603 argument: {options: o},
11604 timeout : o.timeout || this.timeout
11607 var method = o.method||this.method||(p ? "POST" : "GET");
11609 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11610 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11613 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11617 }else if(this.autoAbort !== false){
11621 if((method == 'GET' && p) || o.xmlData){
11622 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11625 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11626 return this.transId;
11628 Roo.callback(o.callback, o.scope, [o, null, null]);
11634 * Determine whether this object has a request outstanding.
11635 * @param {Number} transactionId (Optional) defaults to the last transaction
11636 * @return {Boolean} True if there is an outstanding request.
11638 isLoading : function(transId){
11640 return Roo.lib.Ajax.isCallInProgress(transId);
11642 return this.transId ? true : false;
11647 * Aborts any outstanding request.
11648 * @param {Number} transactionId (Optional) defaults to the last transaction
11650 abort : function(transId){
11651 if(transId || this.isLoading()){
11652 Roo.lib.Ajax.abort(transId || this.transId);
11657 handleResponse : function(response){
11658 this.transId = false;
11659 var options = response.argument.options;
11660 response.argument = options ? options.argument : null;
11661 this.fireEvent("requestcomplete", this, response, options);
11662 Roo.callback(options.success, options.scope, [response, options]);
11663 Roo.callback(options.callback, options.scope, [options, true, response]);
11667 handleFailure : function(response, e){
11668 this.transId = false;
11669 var options = response.argument.options;
11670 response.argument = options ? options.argument : null;
11671 this.fireEvent("requestexception", this, response, options, e);
11672 Roo.callback(options.failure, options.scope, [response, options]);
11673 Roo.callback(options.callback, options.scope, [options, false, response]);
11677 doFormUpload : function(o, ps, url){
11679 var frame = document.createElement('iframe');
11682 frame.className = 'x-hidden';
11684 frame.src = Roo.SSL_SECURE_URL;
11686 document.body.appendChild(frame);
11689 document.frames[id].name = id;
11692 var form = Roo.getDom(o.form);
11694 form.method = 'POST';
11695 form.enctype = form.encoding = 'multipart/form-data';
11701 if(ps){ // add dynamic params
11703 ps = Roo.urlDecode(ps, false);
11705 if(ps.hasOwnProperty(k)){
11706 hd = document.createElement('input');
11707 hd.type = 'hidden';
11710 form.appendChild(hd);
11717 var r = { // bogus response object
11722 r.argument = o ? o.argument : null;
11727 doc = frame.contentWindow.document;
11729 doc = (frame.contentDocument || window.frames[id].document);
11731 if(doc && doc.body){
11732 r.responseText = doc.body.innerHTML;
11734 if(doc && doc.XMLDocument){
11735 r.responseXML = doc.XMLDocument;
11737 r.responseXML = doc;
11744 Roo.EventManager.removeListener(frame, 'load', cb, this);
11746 this.fireEvent("requestcomplete", this, r, o);
11747 Roo.callback(o.success, o.scope, [r, o]);
11748 Roo.callback(o.callback, o.scope, [o, true, r]);
11750 setTimeout(function(){document.body.removeChild(frame);}, 100);
11753 Roo.EventManager.on(frame, 'load', cb, this);
11756 if(hiddens){ // remove dynamic params
11757 for(var i = 0, len = hiddens.length; i < len; i++){
11758 form.removeChild(hiddens[i]);
11765 * Ext JS Library 1.1.1
11766 * Copyright(c) 2006-2007, Ext JS, LLC.
11768 * Originally Released Under LGPL - original licence link has changed is not relivant.
11771 * <script type="text/javascript">
11775 * Global Ajax request class.
11778 * @extends Roo.data.Connection
11781 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11782 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11783 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11784 * @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)
11785 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11786 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11787 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11789 Roo.Ajax = new Roo.data.Connection({
11798 * Serialize the passed form into a url encoded string
11800 * @param {String/HTMLElement} form
11803 serializeForm : function(form){
11804 return Roo.lib.Ajax.serializeForm(form);
11808 * Ext JS Library 1.1.1
11809 * Copyright(c) 2006-2007, Ext JS, LLC.
11811 * Originally Released Under LGPL - original licence link has changed is not relivant.
11814 * <script type="text/javascript">
11819 * @class Roo.UpdateManager
11820 * @extends Roo.util.Observable
11821 * Provides AJAX-style update for Element object.<br><br>
11824 * // Get it from a Roo.Element object
11825 * var el = Roo.get("foo");
11826 * var mgr = el.getUpdateManager();
11827 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11829 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11831 * // or directly (returns the same UpdateManager instance)
11832 * var mgr = new Roo.UpdateManager("myElementId");
11833 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11834 * mgr.on("update", myFcnNeedsToKnow);
11836 // short handed call directly from the element object
11837 Roo.get("foo").load({
11841 text: "Loading Foo..."
11845 * Create new UpdateManager directly.
11846 * @param {String/HTMLElement/Roo.Element} el The element to update
11847 * @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).
11849 Roo.UpdateManager = function(el, forceNew){
11851 if(!forceNew && el.updateManager){
11852 return el.updateManager;
11855 * The Element object
11856 * @type Roo.Element
11860 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11863 this.defaultUrl = null;
11867 * @event beforeupdate
11868 * Fired before an update is made, return false from your handler and the update is cancelled.
11869 * @param {Roo.Element} el
11870 * @param {String/Object/Function} url
11871 * @param {String/Object} params
11873 "beforeupdate": true,
11876 * Fired after successful update is made.
11877 * @param {Roo.Element} el
11878 * @param {Object} oResponseObject The response Object
11883 * Fired on update failure.
11884 * @param {Roo.Element} el
11885 * @param {Object} oResponseObject The response Object
11889 var d = Roo.UpdateManager.defaults;
11891 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11894 this.sslBlankUrl = d.sslBlankUrl;
11896 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11899 this.disableCaching = d.disableCaching;
11901 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11904 this.indicatorText = d.indicatorText;
11906 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11909 this.showLoadIndicator = d.showLoadIndicator;
11911 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11914 this.timeout = d.timeout;
11917 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11920 this.loadScripts = d.loadScripts;
11923 * Transaction object of current executing transaction
11925 this.transaction = null;
11930 this.autoRefreshProcId = null;
11932 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11935 this.refreshDelegate = this.refresh.createDelegate(this);
11937 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11940 this.updateDelegate = this.update.createDelegate(this);
11942 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11945 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11949 this.successDelegate = this.processSuccess.createDelegate(this);
11953 this.failureDelegate = this.processFailure.createDelegate(this);
11955 if(!this.renderer){
11957 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11959 this.renderer = new Roo.UpdateManager.BasicRenderer();
11962 Roo.UpdateManager.superclass.constructor.call(this);
11965 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11967 * Get the Element this UpdateManager is bound to
11968 * @return {Roo.Element} The element
11970 getEl : function(){
11974 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11975 * @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:
11978 url: "your-url.php",<br/>
11979 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11980 callback: yourFunction,<br/>
11981 scope: yourObject, //(optional scope) <br/>
11982 discardUrl: false, <br/>
11983 nocache: false,<br/>
11984 text: "Loading...",<br/>
11986 scripts: false<br/>
11989 * The only required property is url. The optional properties nocache, text and scripts
11990 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11991 * @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}
11992 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11993 * @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.
11995 update : function(url, params, callback, discardUrl){
11996 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11997 var method = this.method,
11999 if(typeof url == "object"){ // must be config object
12002 params = params || cfg.params;
12003 callback = callback || cfg.callback;
12004 discardUrl = discardUrl || cfg.discardUrl;
12005 if(callback && cfg.scope){
12006 callback = callback.createDelegate(cfg.scope);
12008 if(typeof cfg.method != "undefined"){method = cfg.method;};
12009 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12010 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12011 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12012 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12014 this.showLoading();
12016 this.defaultUrl = url;
12018 if(typeof url == "function"){
12019 url = url.call(this);
12022 method = method || (params ? "POST" : "GET");
12023 if(method == "GET"){
12024 url = this.prepareUrl(url);
12027 var o = Roo.apply(cfg ||{}, {
12030 success: this.successDelegate,
12031 failure: this.failureDelegate,
12032 callback: undefined,
12033 timeout: (this.timeout*1000),
12034 argument: {"url": url, "form": null, "callback": callback, "params": params}
12036 Roo.log("updated manager called with timeout of " + o.timeout);
12037 this.transaction = Roo.Ajax.request(o);
12042 * 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.
12043 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12044 * @param {String/HTMLElement} form The form Id or form element
12045 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12046 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12047 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12049 formUpdate : function(form, url, reset, callback){
12050 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12051 if(typeof url == "function"){
12052 url = url.call(this);
12054 form = Roo.getDom(form);
12055 this.transaction = Roo.Ajax.request({
12058 success: this.successDelegate,
12059 failure: this.failureDelegate,
12060 timeout: (this.timeout*1000),
12061 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12063 this.showLoading.defer(1, this);
12068 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12069 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12071 refresh : function(callback){
12072 if(this.defaultUrl == null){
12075 this.update(this.defaultUrl, null, callback, true);
12079 * Set this element to auto refresh.
12080 * @param {Number} interval How often to update (in seconds).
12081 * @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)
12082 * @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}
12083 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12084 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12086 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12088 this.update(url || this.defaultUrl, params, callback, true);
12090 if(this.autoRefreshProcId){
12091 clearInterval(this.autoRefreshProcId);
12093 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12097 * Stop auto refresh on this element.
12099 stopAutoRefresh : function(){
12100 if(this.autoRefreshProcId){
12101 clearInterval(this.autoRefreshProcId);
12102 delete this.autoRefreshProcId;
12106 isAutoRefreshing : function(){
12107 return this.autoRefreshProcId ? true : false;
12110 * Called to update the element to "Loading" state. Override to perform custom action.
12112 showLoading : function(){
12113 if(this.showLoadIndicator){
12114 this.el.update(this.indicatorText);
12119 * Adds unique parameter to query string if disableCaching = true
12122 prepareUrl : function(url){
12123 if(this.disableCaching){
12124 var append = "_dc=" + (new Date().getTime());
12125 if(url.indexOf("?") !== -1){
12126 url += "&" + append;
12128 url += "?" + append;
12137 processSuccess : function(response){
12138 this.transaction = null;
12139 if(response.argument.form && response.argument.reset){
12140 try{ // put in try/catch since some older FF releases had problems with this
12141 response.argument.form.reset();
12144 if(this.loadScripts){
12145 this.renderer.render(this.el, response, this,
12146 this.updateComplete.createDelegate(this, [response]));
12148 this.renderer.render(this.el, response, this);
12149 this.updateComplete(response);
12153 updateComplete : function(response){
12154 this.fireEvent("update", this.el, response);
12155 if(typeof response.argument.callback == "function"){
12156 response.argument.callback(this.el, true, response);
12163 processFailure : function(response){
12164 this.transaction = null;
12165 this.fireEvent("failure", this.el, response);
12166 if(typeof response.argument.callback == "function"){
12167 response.argument.callback(this.el, false, response);
12172 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12173 * @param {Object} renderer The object implementing the render() method
12175 setRenderer : function(renderer){
12176 this.renderer = renderer;
12179 getRenderer : function(){
12180 return this.renderer;
12184 * Set the defaultUrl used for updates
12185 * @param {String/Function} defaultUrl The url or a function to call to get the url
12187 setDefaultUrl : function(defaultUrl){
12188 this.defaultUrl = defaultUrl;
12192 * Aborts the executing transaction
12194 abort : function(){
12195 if(this.transaction){
12196 Roo.Ajax.abort(this.transaction);
12201 * Returns true if an update is in progress
12202 * @return {Boolean}
12204 isUpdating : function(){
12205 if(this.transaction){
12206 return Roo.Ajax.isLoading(this.transaction);
12213 * @class Roo.UpdateManager.defaults
12214 * @static (not really - but it helps the doc tool)
12215 * The defaults collection enables customizing the default properties of UpdateManager
12217 Roo.UpdateManager.defaults = {
12219 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12225 * True to process scripts by default (Defaults to false).
12228 loadScripts : false,
12231 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12234 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12236 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12239 disableCaching : false,
12241 * Whether to show indicatorText when loading (Defaults to true).
12244 showLoadIndicator : true,
12246 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12249 indicatorText : '<div class="loading-indicator">Loading...</div>'
12253 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12255 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12256 * @param {String/HTMLElement/Roo.Element} el The element to update
12257 * @param {String} url The url
12258 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12259 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12262 * @member Roo.UpdateManager
12264 Roo.UpdateManager.updateElement = function(el, url, params, options){
12265 var um = Roo.get(el, true).getUpdateManager();
12266 Roo.apply(um, options);
12267 um.update(url, params, options ? options.callback : null);
12269 // alias for backwards compat
12270 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12272 * @class Roo.UpdateManager.BasicRenderer
12273 * Default Content renderer. Updates the elements innerHTML with the responseText.
12275 Roo.UpdateManager.BasicRenderer = function(){};
12277 Roo.UpdateManager.BasicRenderer.prototype = {
12279 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12280 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12281 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12282 * @param {Roo.Element} el The element being rendered
12283 * @param {Object} response The YUI Connect response object
12284 * @param {UpdateManager} updateManager The calling update manager
12285 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12287 render : function(el, response, updateManager, callback){
12288 el.update(response.responseText, updateManager.loadScripts, callback);
12294 * (c)) Alan Knowles
12300 * @class Roo.DomTemplate
12301 * @extends Roo.Template
12302 * An effort at a dom based template engine..
12304 * Similar to XTemplate, except it uses dom parsing to create the template..
12306 * Supported features:
12311 {a_variable} - output encoded.
12312 {a_variable.format:("Y-m-d")} - call a method on the variable
12313 {a_variable:raw} - unencoded output
12314 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12315 {a_variable:this.method_on_template(...)} - call a method on the template object.
12320 <div roo-for="a_variable or condition.."></div>
12321 <div roo-if="a_variable or condition"></div>
12322 <div roo-exec="some javascript"></div>
12323 <div roo-name="named_template"></div>
12328 Roo.DomTemplate = function()
12330 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12337 Roo.extend(Roo.DomTemplate, Roo.Template, {
12339 * id counter for sub templates.
12343 * flag to indicate if dom parser is inside a pre,
12344 * it will strip whitespace if not.
12349 * The various sub templates
12357 * basic tag replacing syntax
12360 * // you can fake an object call by doing this
12364 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12365 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12367 iterChild : function (node, method) {
12369 var oldPre = this.inPre;
12370 if (node.tagName == 'PRE') {
12373 for( var i = 0; i < node.childNodes.length; i++) {
12374 method.call(this, node.childNodes[i]);
12376 this.inPre = oldPre;
12382 * compile the template
12384 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12387 compile: function()
12391 // covert the html into DOM...
12395 doc = document.implementation.createHTMLDocument("");
12396 doc.documentElement.innerHTML = this.html ;
12397 div = doc.documentElement;
12399 // old IE... - nasty -- it causes all sorts of issues.. with
12400 // images getting pulled from server..
12401 div = document.createElement('div');
12402 div.innerHTML = this.html;
12404 //doc.documentElement.innerHTML = htmlBody
12410 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12412 var tpls = this.tpls;
12414 // create a top level template from the snippet..
12416 //Roo.log(div.innerHTML);
12423 body : div.innerHTML,
12436 Roo.each(tpls, function(tp){
12437 this.compileTpl(tp);
12438 this.tpls[tp.id] = tp;
12441 this.master = tpls[0];
12447 compileNode : function(node, istop) {
12452 // skip anything not a tag..
12453 if (node.nodeType != 1) {
12454 if (node.nodeType == 3 && !this.inPre) {
12455 // reduce white space..
12456 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12479 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12480 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12481 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12482 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12488 // just itterate children..
12489 this.iterChild(node,this.compileNode);
12492 tpl.uid = this.id++;
12493 tpl.value = node.getAttribute('roo-' + tpl.attr);
12494 node.removeAttribute('roo-'+ tpl.attr);
12495 if (tpl.attr != 'name') {
12496 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12497 node.parentNode.replaceChild(placeholder, node);
12500 var placeholder = document.createElement('span');
12501 placeholder.className = 'roo-tpl-' + tpl.value;
12502 node.parentNode.replaceChild(placeholder, node);
12505 // parent now sees '{domtplXXXX}
12506 this.iterChild(node,this.compileNode);
12508 // we should now have node body...
12509 var div = document.createElement('div');
12510 div.appendChild(node);
12512 // this has the unfortunate side effect of converting tagged attributes
12513 // eg. href="{...}" into %7C...%7D
12514 // this has been fixed by searching for those combo's although it's a bit hacky..
12517 tpl.body = div.innerHTML;
12524 switch (tpl.value) {
12525 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12526 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12527 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12532 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12536 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12540 tpl.id = tpl.value; // replace non characters???
12546 this.tpls.push(tpl);
12556 * Compile a segment of the template into a 'sub-template'
12562 compileTpl : function(tpl)
12564 var fm = Roo.util.Format;
12565 var useF = this.disableFormats !== true;
12567 var sep = Roo.isGecko ? "+\n" : ",\n";
12569 var undef = function(str) {
12570 Roo.debug && Roo.log("Property not found :" + str);
12574 //Roo.log(tpl.body);
12578 var fn = function(m, lbrace, name, format, args)
12581 //Roo.log(arguments);
12582 args = args ? args.replace(/\\'/g,"'") : args;
12583 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12584 if (typeof(format) == 'undefined') {
12585 format = 'htmlEncode';
12587 if (format == 'raw' ) {
12591 if(name.substr(0, 6) == 'domtpl'){
12592 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12595 // build an array of options to determine if value is undefined..
12597 // basically get 'xxxx.yyyy' then do
12598 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12599 // (function () { Roo.log("Property not found"); return ''; })() :
12604 Roo.each(name.split('.'), function(st) {
12605 lookfor += (lookfor.length ? '.': '') + st;
12606 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12609 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12612 if(format && useF){
12614 args = args ? ',' + args : "";
12616 if(format.substr(0, 5) != "this."){
12617 format = "fm." + format + '(';
12619 format = 'this.call("'+ format.substr(5) + '", ';
12623 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12626 if (args && args.length) {
12627 // called with xxyx.yuu:(test,test)
12629 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12631 // raw.. - :raw modifier..
12632 return "'"+ sep + udef_st + name + ")"+sep+"'";
12636 // branched to use + in gecko and [].join() in others
12638 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12639 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12642 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12643 body.push(tpl.body.replace(/(\r\n|\n)/g,
12644 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12645 body.push("'].join('');};};");
12646 body = body.join('');
12649 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12651 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12658 * same as applyTemplate, except it's done to one of the subTemplates
12659 * when using named templates, you can do:
12661 * var str = pl.applySubTemplate('your-name', values);
12664 * @param {Number} id of the template
12665 * @param {Object} values to apply to template
12666 * @param {Object} parent (normaly the instance of this object)
12668 applySubTemplate : function(id, values, parent)
12672 var t = this.tpls[id];
12676 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12677 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12681 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12688 if(t.execCall && t.execCall.call(this, values, parent)){
12692 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12698 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12699 parent = t.target ? values : parent;
12700 if(t.forCall && vs instanceof Array){
12702 for(var i = 0, len = vs.length; i < len; i++){
12704 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12706 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12708 //Roo.log(t.compiled);
12712 return buf.join('');
12715 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12720 return t.compiled.call(this, vs, parent);
12722 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12724 //Roo.log(t.compiled);
12732 applyTemplate : function(values){
12733 return this.master.compiled.call(this, values, {});
12734 //var s = this.subs;
12737 apply : function(){
12738 return this.applyTemplate.apply(this, arguments);
12743 Roo.DomTemplate.from = function(el){
12744 el = Roo.getDom(el);
12745 return new Roo.Domtemplate(el.value || el.innerHTML);
12748 * Ext JS Library 1.1.1
12749 * Copyright(c) 2006-2007, Ext JS, LLC.
12751 * Originally Released Under LGPL - original licence link has changed is not relivant.
12754 * <script type="text/javascript">
12758 * @class Roo.util.DelayedTask
12759 * Provides a convenient method of performing setTimeout where a new
12760 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12761 * You can use this class to buffer
12762 * the keypress events for a certain number of milliseconds, and perform only if they stop
12763 * for that amount of time.
12764 * @constructor The parameters to this constructor serve as defaults and are not required.
12765 * @param {Function} fn (optional) The default function to timeout
12766 * @param {Object} scope (optional) The default scope of that timeout
12767 * @param {Array} args (optional) The default Array of arguments
12769 Roo.util.DelayedTask = function(fn, scope, args){
12770 var id = null, d, t;
12772 var call = function(){
12773 var now = new Date().getTime();
12777 fn.apply(scope, args || []);
12781 * Cancels any pending timeout and queues a new one
12782 * @param {Number} delay The milliseconds to delay
12783 * @param {Function} newFn (optional) Overrides function passed to constructor
12784 * @param {Object} newScope (optional) Overrides scope passed to constructor
12785 * @param {Array} newArgs (optional) Overrides args passed to constructor
12787 this.delay = function(delay, newFn, newScope, newArgs){
12788 if(id && delay != d){
12792 t = new Date().getTime();
12794 scope = newScope || scope;
12795 args = newArgs || args;
12797 id = setInterval(call, d);
12802 * Cancel the last queued timeout
12804 this.cancel = function(){
12812 * Ext JS Library 1.1.1
12813 * Copyright(c) 2006-2007, Ext JS, LLC.
12815 * Originally Released Under LGPL - original licence link has changed is not relivant.
12818 * <script type="text/javascript">
12822 Roo.util.TaskRunner = function(interval){
12823 interval = interval || 10;
12824 var tasks = [], removeQueue = [];
12826 var running = false;
12828 var stopThread = function(){
12834 var startThread = function(){
12837 id = setInterval(runTasks, interval);
12841 var removeTask = function(task){
12842 removeQueue.push(task);
12848 var runTasks = function(){
12849 if(removeQueue.length > 0){
12850 for(var i = 0, len = removeQueue.length; i < len; i++){
12851 tasks.remove(removeQueue[i]);
12854 if(tasks.length < 1){
12859 var now = new Date().getTime();
12860 for(var i = 0, len = tasks.length; i < len; ++i){
12862 var itime = now - t.taskRunTime;
12863 if(t.interval <= itime){
12864 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12865 t.taskRunTime = now;
12866 if(rt === false || t.taskRunCount === t.repeat){
12871 if(t.duration && t.duration <= (now - t.taskStartTime)){
12878 * Queues a new task.
12879 * @param {Object} task
12881 this.start = function(task){
12883 task.taskStartTime = new Date().getTime();
12884 task.taskRunTime = 0;
12885 task.taskRunCount = 0;
12890 this.stop = function(task){
12895 this.stopAll = function(){
12897 for(var i = 0, len = tasks.length; i < len; i++){
12898 if(tasks[i].onStop){
12907 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12909 * Ext JS Library 1.1.1
12910 * Copyright(c) 2006-2007, Ext JS, LLC.
12912 * Originally Released Under LGPL - original licence link has changed is not relivant.
12915 * <script type="text/javascript">
12920 * @class Roo.util.MixedCollection
12921 * @extends Roo.util.Observable
12922 * A Collection class that maintains both numeric indexes and keys and exposes events.
12924 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12925 * collection (defaults to false)
12926 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12927 * and return the key value for that item. This is used when available to look up the key on items that
12928 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12929 * equivalent to providing an implementation for the {@link #getKey} method.
12931 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12939 * Fires when the collection is cleared.
12944 * Fires when an item is added to the collection.
12945 * @param {Number} index The index at which the item was added.
12946 * @param {Object} o The item added.
12947 * @param {String} key The key associated with the added item.
12952 * Fires when an item is replaced in the collection.
12953 * @param {String} key he key associated with the new added.
12954 * @param {Object} old The item being replaced.
12955 * @param {Object} new The new item.
12960 * Fires when an item is removed from the collection.
12961 * @param {Object} o The item being removed.
12962 * @param {String} key (optional) The key associated with the removed item.
12967 this.allowFunctions = allowFunctions === true;
12969 this.getKey = keyFn;
12971 Roo.util.MixedCollection.superclass.constructor.call(this);
12974 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12975 allowFunctions : false,
12978 * Adds an item to the collection.
12979 * @param {String} key The key to associate with the item
12980 * @param {Object} o The item to add.
12981 * @return {Object} The item added.
12983 add : function(key, o){
12984 if(arguments.length == 1){
12986 key = this.getKey(o);
12988 if(typeof key == "undefined" || key === null){
12990 this.items.push(o);
12991 this.keys.push(null);
12993 var old = this.map[key];
12995 return this.replace(key, o);
12998 this.items.push(o);
13000 this.keys.push(key);
13002 this.fireEvent("add", this.length-1, o, key);
13007 * MixedCollection has a generic way to fetch keys if you implement getKey.
13010 var mc = new Roo.util.MixedCollection();
13011 mc.add(someEl.dom.id, someEl);
13012 mc.add(otherEl.dom.id, otherEl);
13016 var mc = new Roo.util.MixedCollection();
13017 mc.getKey = function(el){
13023 // or via the constructor
13024 var mc = new Roo.util.MixedCollection(false, function(el){
13030 * @param o {Object} The item for which to find the key.
13031 * @return {Object} The key for the passed item.
13033 getKey : function(o){
13038 * Replaces an item in the collection.
13039 * @param {String} key The key associated with the item to replace, or the item to replace.
13040 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13041 * @return {Object} The new item.
13043 replace : function(key, o){
13044 if(arguments.length == 1){
13046 key = this.getKey(o);
13048 var old = this.item(key);
13049 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13050 return this.add(key, o);
13052 var index = this.indexOfKey(key);
13053 this.items[index] = o;
13055 this.fireEvent("replace", key, old, o);
13060 * Adds all elements of an Array or an Object to the collection.
13061 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13062 * an Array of values, each of which are added to the collection.
13064 addAll : function(objs){
13065 if(arguments.length > 1 || objs instanceof Array){
13066 var args = arguments.length > 1 ? arguments : objs;
13067 for(var i = 0, len = args.length; i < len; i++){
13071 for(var key in objs){
13072 if(this.allowFunctions || typeof objs[key] != "function"){
13073 this.add(key, objs[key]);
13080 * Executes the specified function once for every item in the collection, passing each
13081 * item as the first and only parameter. returning false from the function will stop the iteration.
13082 * @param {Function} fn The function to execute for each item.
13083 * @param {Object} scope (optional) The scope in which to execute the function.
13085 each : function(fn, scope){
13086 var items = [].concat(this.items); // each safe for removal
13087 for(var i = 0, len = items.length; i < len; i++){
13088 if(fn.call(scope || items[i], items[i], i, len) === false){
13095 * Executes the specified function once for every key in the collection, passing each
13096 * key, and its associated item as the first two parameters.
13097 * @param {Function} fn The function to execute for each item.
13098 * @param {Object} scope (optional) The scope in which to execute the function.
13100 eachKey : function(fn, scope){
13101 for(var i = 0, len = this.keys.length; i < len; i++){
13102 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13107 * Returns the first item in the collection which elicits a true return value from the
13108 * passed selection function.
13109 * @param {Function} fn The selection function to execute for each item.
13110 * @param {Object} scope (optional) The scope in which to execute the function.
13111 * @return {Object} The first item in the collection which returned true from the selection function.
13113 find : function(fn, scope){
13114 for(var i = 0, len = this.items.length; i < len; i++){
13115 if(fn.call(scope || window, this.items[i], this.keys[i])){
13116 return this.items[i];
13123 * Inserts an item at the specified index in the collection.
13124 * @param {Number} index The index to insert the item at.
13125 * @param {String} key The key to associate with the new item, or the item itself.
13126 * @param {Object} o (optional) If the second parameter was a key, the new item.
13127 * @return {Object} The item inserted.
13129 insert : function(index, key, o){
13130 if(arguments.length == 2){
13132 key = this.getKey(o);
13134 if(index >= this.length){
13135 return this.add(key, o);
13138 this.items.splice(index, 0, o);
13139 if(typeof key != "undefined" && key != null){
13142 this.keys.splice(index, 0, key);
13143 this.fireEvent("add", index, o, key);
13148 * Removed an item from the collection.
13149 * @param {Object} o The item to remove.
13150 * @return {Object} The item removed.
13152 remove : function(o){
13153 return this.removeAt(this.indexOf(o));
13157 * Remove an item from a specified index in the collection.
13158 * @param {Number} index The index within the collection of the item to remove.
13160 removeAt : function(index){
13161 if(index < this.length && index >= 0){
13163 var o = this.items[index];
13164 this.items.splice(index, 1);
13165 var key = this.keys[index];
13166 if(typeof key != "undefined"){
13167 delete this.map[key];
13169 this.keys.splice(index, 1);
13170 this.fireEvent("remove", o, key);
13175 * Removed an item associated with the passed key fom the collection.
13176 * @param {String} key The key of the item to remove.
13178 removeKey : function(key){
13179 return this.removeAt(this.indexOfKey(key));
13183 * Returns the number of items in the collection.
13184 * @return {Number} the number of items in the collection.
13186 getCount : function(){
13187 return this.length;
13191 * Returns index within the collection of the passed Object.
13192 * @param {Object} o The item to find the index of.
13193 * @return {Number} index of the item.
13195 indexOf : function(o){
13196 if(!this.items.indexOf){
13197 for(var i = 0, len = this.items.length; i < len; i++){
13198 if(this.items[i] == o) {
13204 return this.items.indexOf(o);
13209 * Returns index within the collection of the passed key.
13210 * @param {String} key The key to find the index of.
13211 * @return {Number} index of the key.
13213 indexOfKey : function(key){
13214 if(!this.keys.indexOf){
13215 for(var i = 0, len = this.keys.length; i < len; i++){
13216 if(this.keys[i] == key) {
13222 return this.keys.indexOf(key);
13227 * Returns the item associated with the passed key OR index. Key has priority over index.
13228 * @param {String/Number} key The key or index of the item.
13229 * @return {Object} The item associated with the passed key.
13231 item : function(key){
13232 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13233 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13237 * Returns the item at the specified index.
13238 * @param {Number} index The index of the item.
13241 itemAt : function(index){
13242 return this.items[index];
13246 * Returns the item associated with the passed key.
13247 * @param {String/Number} key The key of the item.
13248 * @return {Object} The item associated with the passed key.
13250 key : function(key){
13251 return this.map[key];
13255 * Returns true if the collection contains the passed Object as an item.
13256 * @param {Object} o The Object to look for in the collection.
13257 * @return {Boolean} True if the collection contains the Object as an item.
13259 contains : function(o){
13260 return this.indexOf(o) != -1;
13264 * Returns true if the collection contains the passed Object as a key.
13265 * @param {String} key The key to look for in the collection.
13266 * @return {Boolean} True if the collection contains the Object as a key.
13268 containsKey : function(key){
13269 return typeof this.map[key] != "undefined";
13273 * Removes all items from the collection.
13275 clear : function(){
13280 this.fireEvent("clear");
13284 * Returns the first item in the collection.
13285 * @return {Object} the first item in the collection..
13287 first : function(){
13288 return this.items[0];
13292 * Returns the last item in the collection.
13293 * @return {Object} the last item in the collection..
13296 return this.items[this.length-1];
13299 _sort : function(property, dir, fn){
13300 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13301 fn = fn || function(a, b){
13304 var c = [], k = this.keys, items = this.items;
13305 for(var i = 0, len = items.length; i < len; i++){
13306 c[c.length] = {key: k[i], value: items[i], index: i};
13308 c.sort(function(a, b){
13309 var v = fn(a[property], b[property]) * dsc;
13311 v = (a.index < b.index ? -1 : 1);
13315 for(var i = 0, len = c.length; i < len; i++){
13316 items[i] = c[i].value;
13319 this.fireEvent("sort", this);
13323 * Sorts this collection with the passed comparison function
13324 * @param {String} direction (optional) "ASC" or "DESC"
13325 * @param {Function} fn (optional) comparison function
13327 sort : function(dir, fn){
13328 this._sort("value", dir, fn);
13332 * Sorts this collection by keys
13333 * @param {String} direction (optional) "ASC" or "DESC"
13334 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13336 keySort : function(dir, fn){
13337 this._sort("key", dir, fn || function(a, b){
13338 return String(a).toUpperCase()-String(b).toUpperCase();
13343 * Returns a range of items in this collection
13344 * @param {Number} startIndex (optional) defaults to 0
13345 * @param {Number} endIndex (optional) default to the last item
13346 * @return {Array} An array of items
13348 getRange : function(start, end){
13349 var items = this.items;
13350 if(items.length < 1){
13353 start = start || 0;
13354 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13357 for(var i = start; i <= end; i++) {
13358 r[r.length] = items[i];
13361 for(var i = start; i >= end; i--) {
13362 r[r.length] = items[i];
13369 * Filter the <i>objects</i> in this collection by a specific property.
13370 * Returns a new collection that has been filtered.
13371 * @param {String} property A property on your objects
13372 * @param {String/RegExp} value Either string that the property values
13373 * should start with or a RegExp to test against the property
13374 * @return {MixedCollection} The new filtered collection
13376 filter : function(property, value){
13377 if(!value.exec){ // not a regex
13378 value = String(value);
13379 if(value.length == 0){
13380 return this.clone();
13382 value = new RegExp("^" + Roo.escapeRe(value), "i");
13384 return this.filterBy(function(o){
13385 return o && value.test(o[property]);
13390 * Filter by a function. * Returns a new collection that has been filtered.
13391 * The passed function will be called with each
13392 * object in the collection. If the function returns true, the value is included
13393 * otherwise it is filtered.
13394 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13395 * @param {Object} scope (optional) The scope of the function (defaults to this)
13396 * @return {MixedCollection} The new filtered collection
13398 filterBy : function(fn, scope){
13399 var r = new Roo.util.MixedCollection();
13400 r.getKey = this.getKey;
13401 var k = this.keys, it = this.items;
13402 for(var i = 0, len = it.length; i < len; i++){
13403 if(fn.call(scope||this, it[i], k[i])){
13404 r.add(k[i], it[i]);
13411 * Creates a duplicate of this collection
13412 * @return {MixedCollection}
13414 clone : function(){
13415 var r = new Roo.util.MixedCollection();
13416 var k = this.keys, it = this.items;
13417 for(var i = 0, len = it.length; i < len; i++){
13418 r.add(k[i], it[i]);
13420 r.getKey = this.getKey;
13425 * Returns the item associated with the passed key or index.
13427 * @param {String/Number} key The key or index of the item.
13428 * @return {Object} The item associated with the passed key.
13430 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13432 * Ext JS Library 1.1.1
13433 * Copyright(c) 2006-2007, Ext JS, LLC.
13435 * Originally Released Under LGPL - original licence link has changed is not relivant.
13438 * <script type="text/javascript">
13441 * @class Roo.util.JSON
13442 * Modified version of Douglas Crockford"s json.js that doesn"t
13443 * mess with the Object prototype
13444 * http://www.json.org/js.html
13447 Roo.util.JSON = new (function(){
13448 var useHasOwn = {}.hasOwnProperty ? true : false;
13450 // crashes Safari in some instances
13451 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13453 var pad = function(n) {
13454 return n < 10 ? "0" + n : n;
13467 var encodeString = function(s){
13468 if (/["\\\x00-\x1f]/.test(s)) {
13469 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13474 c = b.charCodeAt();
13476 Math.floor(c / 16).toString(16) +
13477 (c % 16).toString(16);
13480 return '"' + s + '"';
13483 var encodeArray = function(o){
13484 var a = ["["], b, i, l = o.length, v;
13485 for (i = 0; i < l; i += 1) {
13487 switch (typeof v) {
13496 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13504 var encodeDate = function(o){
13505 return '"' + o.getFullYear() + "-" +
13506 pad(o.getMonth() + 1) + "-" +
13507 pad(o.getDate()) + "T" +
13508 pad(o.getHours()) + ":" +
13509 pad(o.getMinutes()) + ":" +
13510 pad(o.getSeconds()) + '"';
13514 * Encodes an Object, Array or other value
13515 * @param {Mixed} o The variable to encode
13516 * @return {String} The JSON string
13518 this.encode = function(o)
13520 // should this be extended to fully wrap stringify..
13522 if(typeof o == "undefined" || o === null){
13524 }else if(o instanceof Array){
13525 return encodeArray(o);
13526 }else if(o instanceof Date){
13527 return encodeDate(o);
13528 }else if(typeof o == "string"){
13529 return encodeString(o);
13530 }else if(typeof o == "number"){
13531 return isFinite(o) ? String(o) : "null";
13532 }else if(typeof o == "boolean"){
13535 var a = ["{"], b, i, v;
13537 if(!useHasOwn || o.hasOwnProperty(i)) {
13539 switch (typeof v) {
13548 a.push(this.encode(i), ":",
13549 v === null ? "null" : this.encode(v));
13560 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13561 * @param {String} json The JSON string
13562 * @return {Object} The resulting object
13564 this.decode = function(json){
13566 return /** eval:var:json */ eval("(" + json + ')');
13570 * Shorthand for {@link Roo.util.JSON#encode}
13571 * @member Roo encode
13573 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13575 * Shorthand for {@link Roo.util.JSON#decode}
13576 * @member Roo decode
13578 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13581 * Ext JS Library 1.1.1
13582 * Copyright(c) 2006-2007, Ext JS, LLC.
13584 * Originally Released Under LGPL - original licence link has changed is not relivant.
13587 * <script type="text/javascript">
13591 * @class Roo.util.Format
13592 * Reusable data formatting functions
13595 Roo.util.Format = function(){
13596 var trimRe = /^\s+|\s+$/g;
13599 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13600 * @param {String} value The string to truncate
13601 * @param {Number} length The maximum length to allow before truncating
13602 * @return {String} The converted text
13604 ellipsis : function(value, len){
13605 if(value && value.length > len){
13606 return value.substr(0, len-3)+"...";
13612 * Checks a reference and converts it to empty string if it is undefined
13613 * @param {Mixed} value Reference to check
13614 * @return {Mixed} Empty string if converted, otherwise the original value
13616 undef : function(value){
13617 return typeof value != "undefined" ? value : "";
13621 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13622 * @param {String} value The string to encode
13623 * @return {String} The encoded text
13625 htmlEncode : function(value){
13626 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13630 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13631 * @param {String} value The string to decode
13632 * @return {String} The decoded text
13634 htmlDecode : function(value){
13635 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13639 * Trims any whitespace from either side of a string
13640 * @param {String} value The text to trim
13641 * @return {String} The trimmed text
13643 trim : function(value){
13644 return String(value).replace(trimRe, "");
13648 * Returns a substring from within an original string
13649 * @param {String} value The original text
13650 * @param {Number} start The start index of the substring
13651 * @param {Number} length The length of the substring
13652 * @return {String} The substring
13654 substr : function(value, start, length){
13655 return String(value).substr(start, length);
13659 * Converts a string to all lower case letters
13660 * @param {String} value The text to convert
13661 * @return {String} The converted text
13663 lowercase : function(value){
13664 return String(value).toLowerCase();
13668 * Converts a string to all upper case letters
13669 * @param {String} value The text to convert
13670 * @return {String} The converted text
13672 uppercase : function(value){
13673 return String(value).toUpperCase();
13677 * Converts the first character only of a string to upper case
13678 * @param {String} value The text to convert
13679 * @return {String} The converted text
13681 capitalize : function(value){
13682 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13686 call : function(value, fn){
13687 if(arguments.length > 2){
13688 var args = Array.prototype.slice.call(arguments, 2);
13689 args.unshift(value);
13691 return /** eval:var:value */ eval(fn).apply(window, args);
13693 /** eval:var:value */
13694 return /** eval:var:value */ eval(fn).call(window, value);
13700 * safer version of Math.toFixed..??/
13701 * @param {Number/String} value The numeric value to format
13702 * @param {Number/String} value Decimal places
13703 * @return {String} The formatted currency string
13705 toFixed : function(v, n)
13707 // why not use to fixed - precision is buggered???
13709 return Math.round(v-0);
13711 var fact = Math.pow(10,n+1);
13712 v = (Math.round((v-0)*fact))/fact;
13713 var z = (''+fact).substring(2);
13714 if (v == Math.floor(v)) {
13715 return Math.floor(v) + '.' + z;
13718 // now just padd decimals..
13719 var ps = String(v).split('.');
13720 var fd = (ps[1] + z);
13721 var r = fd.substring(0,n);
13722 var rm = fd.substring(n);
13724 return ps[0] + '.' + r;
13726 r*=1; // turn it into a number;
13728 if (String(r).length != n) {
13731 r = String(r).substring(1); // chop the end off.
13734 return ps[0] + '.' + r;
13739 * Format a number as US currency
13740 * @param {Number/String} value The numeric value to format
13741 * @return {String} The formatted currency string
13743 usMoney : function(v){
13744 return '$' + Roo.util.Format.number(v);
13749 * eventually this should probably emulate php's number_format
13750 * @param {Number/String} value The numeric value to format
13751 * @param {Number} decimals number of decimal places
13752 * @return {String} The formatted currency string
13754 number : function(v,decimals)
13756 // multiply and round.
13757 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13758 var mul = Math.pow(10, decimals);
13759 var zero = String(mul).substring(1);
13760 v = (Math.round((v-0)*mul))/mul;
13762 // if it's '0' number.. then
13764 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13766 var ps = v.split('.');
13770 var r = /(\d+)(\d{3})/;
13772 while (r.test(whole)) {
13773 whole = whole.replace(r, '$1' + ',' + '$2');
13779 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13780 // does not have decimals
13781 (decimals ? ('.' + zero) : '');
13784 return whole + sub ;
13788 * Parse a value into a formatted date using the specified format pattern.
13789 * @param {Mixed} value The value to format
13790 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13791 * @return {String} The formatted date string
13793 date : function(v, format){
13797 if(!(v instanceof Date)){
13798 v = new Date(Date.parse(v));
13800 return v.dateFormat(format || Roo.util.Format.defaults.date);
13804 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13805 * @param {String} format Any valid date format string
13806 * @return {Function} The date formatting function
13808 dateRenderer : function(format){
13809 return function(v){
13810 return Roo.util.Format.date(v, format);
13815 stripTagsRE : /<\/?[^>]+>/gi,
13818 * Strips all HTML tags
13819 * @param {Mixed} value The text from which to strip tags
13820 * @return {String} The stripped text
13822 stripTags : function(v){
13823 return !v ? v : String(v).replace(this.stripTagsRE, "");
13827 Roo.util.Format.defaults = {
13831 * Ext JS Library 1.1.1
13832 * Copyright(c) 2006-2007, Ext JS, LLC.
13834 * Originally Released Under LGPL - original licence link has changed is not relivant.
13837 * <script type="text/javascript">
13844 * @class Roo.MasterTemplate
13845 * @extends Roo.Template
13846 * Provides a template that can have child templates. The syntax is:
13848 var t = new Roo.MasterTemplate(
13849 '<select name="{name}">',
13850 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13853 t.add('options', {value: 'foo', text: 'bar'});
13854 // or you can add multiple child elements in one shot
13855 t.addAll('options', [
13856 {value: 'foo', text: 'bar'},
13857 {value: 'foo2', text: 'bar2'},
13858 {value: 'foo3', text: 'bar3'}
13860 // then append, applying the master template values
13861 t.append('my-form', {name: 'my-select'});
13863 * A name attribute for the child template is not required if you have only one child
13864 * template or you want to refer to them by index.
13866 Roo.MasterTemplate = function(){
13867 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13868 this.originalHtml = this.html;
13870 var m, re = this.subTemplateRe;
13873 while(m = re.exec(this.html)){
13874 var name = m[1], content = m[2];
13879 tpl : new Roo.Template(content)
13882 st[name] = st[subIndex];
13884 st[subIndex].tpl.compile();
13885 st[subIndex].tpl.call = this.call.createDelegate(this);
13888 this.subCount = subIndex;
13891 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13893 * The regular expression used to match sub templates
13897 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13900 * Applies the passed values to a child template.
13901 * @param {String/Number} name (optional) The name or index of the child template
13902 * @param {Array/Object} values The values to be applied to the template
13903 * @return {MasterTemplate} this
13905 add : function(name, values){
13906 if(arguments.length == 1){
13907 values = arguments[0];
13910 var s = this.subs[name];
13911 s.buffer[s.buffer.length] = s.tpl.apply(values);
13916 * Applies all the passed values to a child template.
13917 * @param {String/Number} name (optional) The name or index of the child template
13918 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13919 * @param {Boolean} reset (optional) True to reset the template first
13920 * @return {MasterTemplate} this
13922 fill : function(name, values, reset){
13924 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13932 for(var i = 0, len = values.length; i < len; i++){
13933 this.add(name, values[i]);
13939 * Resets the template for reuse
13940 * @return {MasterTemplate} this
13942 reset : function(){
13944 for(var i = 0; i < this.subCount; i++){
13950 applyTemplate : function(values){
13952 var replaceIndex = -1;
13953 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13954 return s[++replaceIndex].buffer.join("");
13956 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13959 apply : function(){
13960 return this.applyTemplate.apply(this, arguments);
13963 compile : function(){return this;}
13967 * Alias for fill().
13970 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13972 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13973 * var tpl = Roo.MasterTemplate.from('element-id');
13974 * @param {String/HTMLElement} el
13975 * @param {Object} config
13978 Roo.MasterTemplate.from = function(el, config){
13979 el = Roo.getDom(el);
13980 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13983 * Ext JS Library 1.1.1
13984 * Copyright(c) 2006-2007, Ext JS, LLC.
13986 * Originally Released Under LGPL - original licence link has changed is not relivant.
13989 * <script type="text/javascript">
13994 * @class Roo.util.CSS
13995 * Utility class for manipulating CSS rules
13998 Roo.util.CSS = function(){
14000 var doc = document;
14002 var camelRe = /(-[a-z])/gi;
14003 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14007 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14008 * tag and appended to the HEAD of the document.
14009 * @param {String|Object} cssText The text containing the css rules
14010 * @param {String} id An id to add to the stylesheet for later removal
14011 * @return {StyleSheet}
14013 createStyleSheet : function(cssText, id){
14015 var head = doc.getElementsByTagName("head")[0];
14016 var nrules = doc.createElement("style");
14017 nrules.setAttribute("type", "text/css");
14019 nrules.setAttribute("id", id);
14021 if (typeof(cssText) != 'string') {
14022 // support object maps..
14023 // not sure if this a good idea..
14024 // perhaps it should be merged with the general css handling
14025 // and handle js style props.
14026 var cssTextNew = [];
14027 for(var n in cssText) {
14029 for(var k in cssText[n]) {
14030 citems.push( k + ' : ' +cssText[n][k] + ';' );
14032 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14035 cssText = cssTextNew.join("\n");
14041 head.appendChild(nrules);
14042 ss = nrules.styleSheet;
14043 ss.cssText = cssText;
14046 nrules.appendChild(doc.createTextNode(cssText));
14048 nrules.cssText = cssText;
14050 head.appendChild(nrules);
14051 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14053 this.cacheStyleSheet(ss);
14058 * Removes a style or link tag by id
14059 * @param {String} id The id of the tag
14061 removeStyleSheet : function(id){
14062 var existing = doc.getElementById(id);
14064 existing.parentNode.removeChild(existing);
14069 * Dynamically swaps an existing stylesheet reference for a new one
14070 * @param {String} id The id of an existing link tag to remove
14071 * @param {String} url The href of the new stylesheet to include
14073 swapStyleSheet : function(id, url){
14074 this.removeStyleSheet(id);
14075 var ss = doc.createElement("link");
14076 ss.setAttribute("rel", "stylesheet");
14077 ss.setAttribute("type", "text/css");
14078 ss.setAttribute("id", id);
14079 ss.setAttribute("href", url);
14080 doc.getElementsByTagName("head")[0].appendChild(ss);
14084 * Refresh the rule cache if you have dynamically added stylesheets
14085 * @return {Object} An object (hash) of rules indexed by selector
14087 refreshCache : function(){
14088 return this.getRules(true);
14092 cacheStyleSheet : function(stylesheet){
14096 try{// try catch for cross domain access issue
14097 var ssRules = stylesheet.cssRules || stylesheet.rules;
14098 for(var j = ssRules.length-1; j >= 0; --j){
14099 rules[ssRules[j].selectorText] = ssRules[j];
14105 * Gets all css rules for the document
14106 * @param {Boolean} refreshCache true to refresh the internal cache
14107 * @return {Object} An object (hash) of rules indexed by selector
14109 getRules : function(refreshCache){
14110 if(rules == null || refreshCache){
14112 var ds = doc.styleSheets;
14113 for(var i =0, len = ds.length; i < len; i++){
14115 this.cacheStyleSheet(ds[i]);
14123 * Gets an an individual CSS rule by selector(s)
14124 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14125 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14126 * @return {CSSRule} The CSS rule or null if one is not found
14128 getRule : function(selector, refreshCache){
14129 var rs = this.getRules(refreshCache);
14130 if(!(selector instanceof Array)){
14131 return rs[selector];
14133 for(var i = 0; i < selector.length; i++){
14134 if(rs[selector[i]]){
14135 return rs[selector[i]];
14143 * Updates a rule property
14144 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14145 * @param {String} property The css property
14146 * @param {String} value The new value for the property
14147 * @return {Boolean} true If a rule was found and updated
14149 updateRule : function(selector, property, value){
14150 if(!(selector instanceof Array)){
14151 var rule = this.getRule(selector);
14153 rule.style[property.replace(camelRe, camelFn)] = value;
14157 for(var i = 0; i < selector.length; i++){
14158 if(this.updateRule(selector[i], property, value)){
14168 * Ext JS Library 1.1.1
14169 * Copyright(c) 2006-2007, Ext JS, LLC.
14171 * Originally Released Under LGPL - original licence link has changed is not relivant.
14174 * <script type="text/javascript">
14180 * @class Roo.util.ClickRepeater
14181 * @extends Roo.util.Observable
14183 * A wrapper class which can be applied to any element. Fires a "click" event while the
14184 * mouse is pressed. The interval between firings may be specified in the config but
14185 * defaults to 10 milliseconds.
14187 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14189 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14190 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14191 * Similar to an autorepeat key delay.
14192 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14193 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14194 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14195 * "interval" and "delay" are ignored. "immediate" is honored.
14196 * @cfg {Boolean} preventDefault True to prevent the default click event
14197 * @cfg {Boolean} stopDefault True to stop the default click event
14200 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14201 * 2007-02-02 jvs Renamed to ClickRepeater
14202 * 2007-02-03 jvs Modifications for FF Mac and Safari
14205 * @param {String/HTMLElement/Element} el The element to listen on
14206 * @param {Object} config
14208 Roo.util.ClickRepeater = function(el, config)
14210 this.el = Roo.get(el);
14211 this.el.unselectable();
14213 Roo.apply(this, config);
14218 * Fires when the mouse button is depressed.
14219 * @param {Roo.util.ClickRepeater} this
14221 "mousedown" : true,
14224 * Fires on a specified interval during the time the element is pressed.
14225 * @param {Roo.util.ClickRepeater} this
14230 * Fires when the mouse key is released.
14231 * @param {Roo.util.ClickRepeater} this
14236 this.el.on("mousedown", this.handleMouseDown, this);
14237 if(this.preventDefault || this.stopDefault){
14238 this.el.on("click", function(e){
14239 if(this.preventDefault){
14240 e.preventDefault();
14242 if(this.stopDefault){
14248 // allow inline handler
14250 this.on("click", this.handler, this.scope || this);
14253 Roo.util.ClickRepeater.superclass.constructor.call(this);
14256 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14259 preventDefault : true,
14260 stopDefault : false,
14264 handleMouseDown : function(){
14265 clearTimeout(this.timer);
14267 if(this.pressClass){
14268 this.el.addClass(this.pressClass);
14270 this.mousedownTime = new Date();
14272 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14273 this.el.on("mouseout", this.handleMouseOut, this);
14275 this.fireEvent("mousedown", this);
14276 this.fireEvent("click", this);
14278 this.timer = this.click.defer(this.delay || this.interval, this);
14282 click : function(){
14283 this.fireEvent("click", this);
14284 this.timer = this.click.defer(this.getInterval(), this);
14288 getInterval: function(){
14289 if(!this.accelerate){
14290 return this.interval;
14292 var pressTime = this.mousedownTime.getElapsed();
14293 if(pressTime < 500){
14295 }else if(pressTime < 1700){
14297 }else if(pressTime < 2600){
14299 }else if(pressTime < 3500){
14301 }else if(pressTime < 4400){
14303 }else if(pressTime < 5300){
14305 }else if(pressTime < 6200){
14313 handleMouseOut : function(){
14314 clearTimeout(this.timer);
14315 if(this.pressClass){
14316 this.el.removeClass(this.pressClass);
14318 this.el.on("mouseover", this.handleMouseReturn, this);
14322 handleMouseReturn : function(){
14323 this.el.un("mouseover", this.handleMouseReturn);
14324 if(this.pressClass){
14325 this.el.addClass(this.pressClass);
14331 handleMouseUp : function(){
14332 clearTimeout(this.timer);
14333 this.el.un("mouseover", this.handleMouseReturn);
14334 this.el.un("mouseout", this.handleMouseOut);
14335 Roo.get(document).un("mouseup", this.handleMouseUp);
14336 this.el.removeClass(this.pressClass);
14337 this.fireEvent("mouseup", this);
14341 * Ext JS Library 1.1.1
14342 * Copyright(c) 2006-2007, Ext JS, LLC.
14344 * Originally Released Under LGPL - original licence link has changed is not relivant.
14347 * <script type="text/javascript">
14352 * @class Roo.KeyNav
14353 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14354 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14355 * way to implement custom navigation schemes for any UI component.</p>
14356 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14357 * pageUp, pageDown, del, home, end. Usage:</p>
14359 var nav = new Roo.KeyNav("my-element", {
14360 "left" : function(e){
14361 this.moveLeft(e.ctrlKey);
14363 "right" : function(e){
14364 this.moveRight(e.ctrlKey);
14366 "enter" : function(e){
14373 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14374 * @param {Object} config The config
14376 Roo.KeyNav = function(el, config){
14377 this.el = Roo.get(el);
14378 Roo.apply(this, config);
14379 if(!this.disabled){
14380 this.disabled = true;
14385 Roo.KeyNav.prototype = {
14387 * @cfg {Boolean} disabled
14388 * True to disable this KeyNav instance (defaults to false)
14392 * @cfg {String} defaultEventAction
14393 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14394 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14395 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14397 defaultEventAction: "stopEvent",
14399 * @cfg {Boolean} forceKeyDown
14400 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14401 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14402 * handle keydown instead of keypress.
14404 forceKeyDown : false,
14407 prepareEvent : function(e){
14408 var k = e.getKey();
14409 var h = this.keyToHandler[k];
14410 //if(h && this[h]){
14411 // e.stopPropagation();
14413 if(Roo.isSafari && h && k >= 37 && k <= 40){
14419 relay : function(e){
14420 var k = e.getKey();
14421 var h = this.keyToHandler[k];
14423 if(this.doRelay(e, this[h], h) !== true){
14424 e[this.defaultEventAction]();
14430 doRelay : function(e, h, hname){
14431 return h.call(this.scope || this, e);
14434 // possible handlers
14448 // quick lookup hash
14465 * Enable this KeyNav
14467 enable: function(){
14469 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14470 // the EventObject will normalize Safari automatically
14471 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14472 this.el.on("keydown", this.relay, this);
14474 this.el.on("keydown", this.prepareEvent, this);
14475 this.el.on("keypress", this.relay, this);
14477 this.disabled = false;
14482 * Disable this KeyNav
14484 disable: function(){
14485 if(!this.disabled){
14486 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14487 this.el.un("keydown", this.relay);
14489 this.el.un("keydown", this.prepareEvent);
14490 this.el.un("keypress", this.relay);
14492 this.disabled = true;
14497 * Ext JS Library 1.1.1
14498 * Copyright(c) 2006-2007, Ext JS, LLC.
14500 * Originally Released Under LGPL - original licence link has changed is not relivant.
14503 * <script type="text/javascript">
14508 * @class Roo.KeyMap
14509 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14510 * The constructor accepts the same config object as defined by {@link #addBinding}.
14511 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14512 * combination it will call the function with this signature (if the match is a multi-key
14513 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14514 * A KeyMap can also handle a string representation of keys.<br />
14517 // map one key by key code
14518 var map = new Roo.KeyMap("my-element", {
14519 key: 13, // or Roo.EventObject.ENTER
14524 // map multiple keys to one action by string
14525 var map = new Roo.KeyMap("my-element", {
14531 // map multiple keys to multiple actions by strings and array of codes
14532 var map = new Roo.KeyMap("my-element", [
14535 fn: function(){ alert("Return was pressed"); }
14538 fn: function(){ alert('a, b or c was pressed'); }
14543 fn: function(){ alert('Control + shift + tab was pressed.'); }
14547 * <b>Note: A KeyMap starts enabled</b>
14549 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14550 * @param {Object} config The config (see {@link #addBinding})
14551 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14553 Roo.KeyMap = function(el, config, eventName){
14554 this.el = Roo.get(el);
14555 this.eventName = eventName || "keydown";
14556 this.bindings = [];
14558 this.addBinding(config);
14563 Roo.KeyMap.prototype = {
14565 * True to stop the event from bubbling and prevent the default browser action if the
14566 * key was handled by the KeyMap (defaults to false)
14572 * Add a new binding to this KeyMap. The following config object properties are supported:
14574 Property Type Description
14575 ---------- --------------- ----------------------------------------------------------------------
14576 key String/Array A single keycode or an array of keycodes to handle
14577 shift Boolean True to handle key only when shift is pressed (defaults to false)
14578 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14579 alt Boolean True to handle key only when alt is pressed (defaults to false)
14580 fn Function The function to call when KeyMap finds the expected key combination
14581 scope Object The scope of the callback function
14587 var map = new Roo.KeyMap(document, {
14588 key: Roo.EventObject.ENTER,
14593 //Add a new binding to the existing KeyMap later
14601 * @param {Object/Array} config A single KeyMap config or an array of configs
14603 addBinding : function(config){
14604 if(config instanceof Array){
14605 for(var i = 0, len = config.length; i < len; i++){
14606 this.addBinding(config[i]);
14610 var keyCode = config.key,
14611 shift = config.shift,
14612 ctrl = config.ctrl,
14615 scope = config.scope;
14616 if(typeof keyCode == "string"){
14618 var keyString = keyCode.toUpperCase();
14619 for(var j = 0, len = keyString.length; j < len; j++){
14620 ks.push(keyString.charCodeAt(j));
14624 var keyArray = keyCode instanceof Array;
14625 var handler = function(e){
14626 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14627 var k = e.getKey();
14629 for(var i = 0, len = keyCode.length; i < len; i++){
14630 if(keyCode[i] == k){
14631 if(this.stopEvent){
14634 fn.call(scope || window, k, e);
14640 if(this.stopEvent){
14643 fn.call(scope || window, k, e);
14648 this.bindings.push(handler);
14652 * Shorthand for adding a single key listener
14653 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14654 * following options:
14655 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14656 * @param {Function} fn The function to call
14657 * @param {Object} scope (optional) The scope of the function
14659 on : function(key, fn, scope){
14660 var keyCode, shift, ctrl, alt;
14661 if(typeof key == "object" && !(key instanceof Array)){
14680 handleKeyDown : function(e){
14681 if(this.enabled){ //just in case
14682 var b = this.bindings;
14683 for(var i = 0, len = b.length; i < len; i++){
14684 b[i].call(this, e);
14690 * Returns true if this KeyMap is enabled
14691 * @return {Boolean}
14693 isEnabled : function(){
14694 return this.enabled;
14698 * Enables this KeyMap
14700 enable: function(){
14702 this.el.on(this.eventName, this.handleKeyDown, this);
14703 this.enabled = true;
14708 * Disable this KeyMap
14710 disable: function(){
14712 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14713 this.enabled = false;
14718 * Ext JS Library 1.1.1
14719 * Copyright(c) 2006-2007, Ext JS, LLC.
14721 * Originally Released Under LGPL - original licence link has changed is not relivant.
14724 * <script type="text/javascript">
14729 * @class Roo.util.TextMetrics
14730 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14731 * wide, in pixels, a given block of text will be.
14734 Roo.util.TextMetrics = function(){
14738 * Measures the size of the specified text
14739 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14740 * that can affect the size of the rendered text
14741 * @param {String} text The text to measure
14742 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14743 * in order to accurately measure the text height
14744 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14746 measure : function(el, text, fixedWidth){
14748 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14751 shared.setFixedWidth(fixedWidth || 'auto');
14752 return shared.getSize(text);
14756 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14757 * the overhead of multiple calls to initialize the style properties on each measurement.
14758 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14759 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14760 * in order to accurately measure the text height
14761 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14763 createInstance : function(el, fixedWidth){
14764 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14771 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14772 var ml = new Roo.Element(document.createElement('div'));
14773 document.body.appendChild(ml.dom);
14774 ml.position('absolute');
14775 ml.setLeftTop(-1000, -1000);
14779 ml.setWidth(fixedWidth);
14784 * Returns the size of the specified text based on the internal element's style and width properties
14785 * @memberOf Roo.util.TextMetrics.Instance#
14786 * @param {String} text The text to measure
14787 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14789 getSize : function(text){
14791 var s = ml.getSize();
14797 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14798 * that can affect the size of the rendered text
14799 * @memberOf Roo.util.TextMetrics.Instance#
14800 * @param {String/HTMLElement} el The element, dom node or id
14802 bind : function(el){
14804 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14809 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14810 * to set a fixed width in order to accurately measure the text height.
14811 * @memberOf Roo.util.TextMetrics.Instance#
14812 * @param {Number} width The width to set on the element
14814 setFixedWidth : function(width){
14815 ml.setWidth(width);
14819 * Returns the measured width of the specified text
14820 * @memberOf Roo.util.TextMetrics.Instance#
14821 * @param {String} text The text to measure
14822 * @return {Number} width The width in pixels
14824 getWidth : function(text){
14825 ml.dom.style.width = 'auto';
14826 return this.getSize(text).width;
14830 * Returns the measured height of the specified text. For multiline text, be sure to call
14831 * {@link #setFixedWidth} if necessary.
14832 * @memberOf Roo.util.TextMetrics.Instance#
14833 * @param {String} text The text to measure
14834 * @return {Number} height The height in pixels
14836 getHeight : function(text){
14837 return this.getSize(text).height;
14841 instance.bind(bindTo);
14846 // backwards compat
14847 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14849 * Ext JS Library 1.1.1
14850 * Copyright(c) 2006-2007, Ext JS, LLC.
14852 * Originally Released Under LGPL - original licence link has changed is not relivant.
14855 * <script type="text/javascript">
14859 * @class Roo.state.Provider
14860 * Abstract base class for state provider implementations. This class provides methods
14861 * for encoding and decoding <b>typed</b> variables including dates and defines the
14862 * Provider interface.
14864 Roo.state.Provider = function(){
14866 * @event statechange
14867 * Fires when a state change occurs.
14868 * @param {Provider} this This state provider
14869 * @param {String} key The state key which was changed
14870 * @param {String} value The encoded value for the state
14873 "statechange": true
14876 Roo.state.Provider.superclass.constructor.call(this);
14878 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14880 * Returns the current value for a key
14881 * @param {String} name The key name
14882 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14883 * @return {Mixed} The state data
14885 get : function(name, defaultValue){
14886 return typeof this.state[name] == "undefined" ?
14887 defaultValue : this.state[name];
14891 * Clears a value from the state
14892 * @param {String} name The key name
14894 clear : function(name){
14895 delete this.state[name];
14896 this.fireEvent("statechange", this, name, null);
14900 * Sets the value for a key
14901 * @param {String} name The key name
14902 * @param {Mixed} value The value to set
14904 set : function(name, value){
14905 this.state[name] = value;
14906 this.fireEvent("statechange", this, name, value);
14910 * Decodes a string previously encoded with {@link #encodeValue}.
14911 * @param {String} value The value to decode
14912 * @return {Mixed} The decoded value
14914 decodeValue : function(cookie){
14915 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14916 var matches = re.exec(unescape(cookie));
14917 if(!matches || !matches[1]) {
14918 return; // non state cookie
14920 var type = matches[1];
14921 var v = matches[2];
14924 return parseFloat(v);
14926 return new Date(Date.parse(v));
14931 var values = v.split("^");
14932 for(var i = 0, len = values.length; i < len; i++){
14933 all.push(this.decodeValue(values[i]));
14938 var values = v.split("^");
14939 for(var i = 0, len = values.length; i < len; i++){
14940 var kv = values[i].split("=");
14941 all[kv[0]] = this.decodeValue(kv[1]);
14950 * Encodes a value including type information. Decode with {@link #decodeValue}.
14951 * @param {Mixed} value The value to encode
14952 * @return {String} The encoded value
14954 encodeValue : function(v){
14956 if(typeof v == "number"){
14958 }else if(typeof v == "boolean"){
14959 enc = "b:" + (v ? "1" : "0");
14960 }else if(v instanceof Date){
14961 enc = "d:" + v.toGMTString();
14962 }else if(v instanceof Array){
14964 for(var i = 0, len = v.length; i < len; i++){
14965 flat += this.encodeValue(v[i]);
14971 }else if(typeof v == "object"){
14974 if(typeof v[key] != "function"){
14975 flat += key + "=" + this.encodeValue(v[key]) + "^";
14978 enc = "o:" + flat.substring(0, flat.length-1);
14982 return escape(enc);
14988 * Ext JS Library 1.1.1
14989 * Copyright(c) 2006-2007, Ext JS, LLC.
14991 * Originally Released Under LGPL - original licence link has changed is not relivant.
14994 * <script type="text/javascript">
14997 * @class Roo.state.Manager
14998 * This is the global state manager. By default all components that are "state aware" check this class
14999 * for state information if you don't pass them a custom state provider. In order for this class
15000 * to be useful, it must be initialized with a provider when your application initializes.
15002 // in your initialization function
15004 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15006 // supposed you have a {@link Roo.BorderLayout}
15007 var layout = new Roo.BorderLayout(...);
15008 layout.restoreState();
15009 // or a {Roo.BasicDialog}
15010 var dialog = new Roo.BasicDialog(...);
15011 dialog.restoreState();
15015 Roo.state.Manager = function(){
15016 var provider = new Roo.state.Provider();
15020 * Configures the default state provider for your application
15021 * @param {Provider} stateProvider The state provider to set
15023 setProvider : function(stateProvider){
15024 provider = stateProvider;
15028 * Returns the current value for a key
15029 * @param {String} name The key name
15030 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15031 * @return {Mixed} The state data
15033 get : function(key, defaultValue){
15034 return provider.get(key, defaultValue);
15038 * Sets the value for a key
15039 * @param {String} name The key name
15040 * @param {Mixed} value The state data
15042 set : function(key, value){
15043 provider.set(key, value);
15047 * Clears a value from the state
15048 * @param {String} name The key name
15050 clear : function(key){
15051 provider.clear(key);
15055 * Gets the currently configured state provider
15056 * @return {Provider} The state provider
15058 getProvider : function(){
15065 * Ext JS Library 1.1.1
15066 * Copyright(c) 2006-2007, Ext JS, LLC.
15068 * Originally Released Under LGPL - original licence link has changed is not relivant.
15071 * <script type="text/javascript">
15074 * @class Roo.state.CookieProvider
15075 * @extends Roo.state.Provider
15076 * The default Provider implementation which saves state via cookies.
15079 var cp = new Roo.state.CookieProvider({
15081 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15082 domain: "roojs.com"
15084 Roo.state.Manager.setProvider(cp);
15086 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15087 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15088 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15089 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15090 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15091 * domain the page is running on including the 'www' like 'www.roojs.com')
15092 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15094 * Create a new CookieProvider
15095 * @param {Object} config The configuration object
15097 Roo.state.CookieProvider = function(config){
15098 Roo.state.CookieProvider.superclass.constructor.call(this);
15100 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15101 this.domain = null;
15102 this.secure = false;
15103 Roo.apply(this, config);
15104 this.state = this.readCookies();
15107 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15109 set : function(name, value){
15110 if(typeof value == "undefined" || value === null){
15114 this.setCookie(name, value);
15115 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15119 clear : function(name){
15120 this.clearCookie(name);
15121 Roo.state.CookieProvider.superclass.clear.call(this, name);
15125 readCookies : function(){
15127 var c = document.cookie + ";";
15128 var re = /\s?(.*?)=(.*?);/g;
15130 while((matches = re.exec(c)) != null){
15131 var name = matches[1];
15132 var value = matches[2];
15133 if(name && name.substring(0,3) == "ys-"){
15134 cookies[name.substr(3)] = this.decodeValue(value);
15141 setCookie : function(name, value){
15142 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15143 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15144 ((this.path == null) ? "" : ("; path=" + this.path)) +
15145 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15146 ((this.secure == true) ? "; secure" : "");
15150 clearCookie : function(name){
15151 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15152 ((this.path == null) ? "" : ("; path=" + this.path)) +
15153 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15154 ((this.secure == true) ? "; secure" : "");
15158 * Ext JS Library 1.1.1
15159 * Copyright(c) 2006-2007, Ext JS, LLC.
15161 * Originally Released Under LGPL - original licence link has changed is not relivant.
15164 * <script type="text/javascript">
15169 * @class Roo.ComponentMgr
15170 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15173 Roo.ComponentMgr = function(){
15174 var all = new Roo.util.MixedCollection();
15178 * Registers a component.
15179 * @param {Roo.Component} c The component
15181 register : function(c){
15186 * Unregisters a component.
15187 * @param {Roo.Component} c The component
15189 unregister : function(c){
15194 * Returns a component by id
15195 * @param {String} id The component id
15197 get : function(id){
15198 return all.get(id);
15202 * Registers a function that will be called when a specified component is added to ComponentMgr
15203 * @param {String} id The component id
15204 * @param {Funtction} fn The callback function
15205 * @param {Object} scope The scope of the callback
15207 onAvailable : function(id, fn, scope){
15208 all.on("add", function(index, o){
15210 fn.call(scope || o, o);
15211 all.un("add", fn, scope);
15218 * Ext JS Library 1.1.1
15219 * Copyright(c) 2006-2007, Ext JS, LLC.
15221 * Originally Released Under LGPL - original licence link has changed is not relivant.
15224 * <script type="text/javascript">
15228 * @class Roo.Component
15229 * @extends Roo.util.Observable
15230 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15231 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15232 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15233 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15234 * All visual components (widgets) that require rendering into a layout should subclass Component.
15236 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15237 * 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
15238 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15240 Roo.Component = function(config){
15241 config = config || {};
15242 if(config.tagName || config.dom || typeof config == "string"){ // element object
15243 config = {el: config, id: config.id || config};
15245 this.initialConfig = config;
15247 Roo.apply(this, config);
15251 * Fires after the component is disabled.
15252 * @param {Roo.Component} this
15257 * Fires after the component is enabled.
15258 * @param {Roo.Component} this
15262 * @event beforeshow
15263 * Fires before the component is shown. Return false to stop the show.
15264 * @param {Roo.Component} this
15269 * Fires after the component is shown.
15270 * @param {Roo.Component} this
15274 * @event beforehide
15275 * Fires before the component is hidden. Return false to stop the hide.
15276 * @param {Roo.Component} this
15281 * Fires after the component is hidden.
15282 * @param {Roo.Component} this
15286 * @event beforerender
15287 * Fires before the component is rendered. Return false to stop the render.
15288 * @param {Roo.Component} this
15290 beforerender : true,
15293 * Fires after the component is rendered.
15294 * @param {Roo.Component} this
15298 * @event beforedestroy
15299 * Fires before the component is destroyed. Return false to stop the destroy.
15300 * @param {Roo.Component} this
15302 beforedestroy : true,
15305 * Fires after the component is destroyed.
15306 * @param {Roo.Component} this
15311 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15313 Roo.ComponentMgr.register(this);
15314 Roo.Component.superclass.constructor.call(this);
15315 this.initComponent();
15316 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15317 this.render(this.renderTo);
15318 delete this.renderTo;
15323 Roo.Component.AUTO_ID = 1000;
15325 Roo.extend(Roo.Component, Roo.util.Observable, {
15327 * @scope Roo.Component.prototype
15329 * true if this component is hidden. Read-only.
15334 * true if this component is disabled. Read-only.
15339 * true if this component has been rendered. Read-only.
15343 /** @cfg {String} disableClass
15344 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15346 disabledClass : "x-item-disabled",
15347 /** @cfg {Boolean} allowDomMove
15348 * Whether the component can move the Dom node when rendering (defaults to true).
15350 allowDomMove : true,
15351 /** @cfg {String} hideMode (display|visibility)
15352 * How this component should hidden. Supported values are
15353 * "visibility" (css visibility), "offsets" (negative offset position) and
15354 * "display" (css display) - defaults to "display".
15356 hideMode: 'display',
15359 ctype : "Roo.Component",
15362 * @cfg {String} actionMode
15363 * which property holds the element that used for hide() / show() / disable() / enable()
15369 getActionEl : function(){
15370 return this[this.actionMode];
15373 initComponent : Roo.emptyFn,
15375 * If this is a lazy rendering component, render it to its container element.
15376 * @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.
15378 render : function(container, position){
15379 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15380 if(!container && this.el){
15381 this.el = Roo.get(this.el);
15382 container = this.el.dom.parentNode;
15383 this.allowDomMove = false;
15385 this.container = Roo.get(container);
15386 this.rendered = true;
15387 if(position !== undefined){
15388 if(typeof position == 'number'){
15389 position = this.container.dom.childNodes[position];
15391 position = Roo.getDom(position);
15394 this.onRender(this.container, position || null);
15396 this.el.addClass(this.cls);
15400 this.el.applyStyles(this.style);
15403 this.fireEvent("render", this);
15404 this.afterRender(this.container);
15416 // default function is not really useful
15417 onRender : function(ct, position){
15419 this.el = Roo.get(this.el);
15420 if(this.allowDomMove !== false){
15421 ct.dom.insertBefore(this.el.dom, position);
15427 getAutoCreate : function(){
15428 var cfg = typeof this.autoCreate == "object" ?
15429 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15430 if(this.id && !cfg.id){
15437 afterRender : Roo.emptyFn,
15440 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15441 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15443 destroy : function(){
15444 if(this.fireEvent("beforedestroy", this) !== false){
15445 this.purgeListeners();
15446 this.beforeDestroy();
15448 this.el.removeAllListeners();
15450 if(this.actionMode == "container"){
15451 this.container.remove();
15455 Roo.ComponentMgr.unregister(this);
15456 this.fireEvent("destroy", this);
15461 beforeDestroy : function(){
15466 onDestroy : function(){
15471 * Returns the underlying {@link Roo.Element}.
15472 * @return {Roo.Element} The element
15474 getEl : function(){
15479 * Returns the id of this component.
15482 getId : function(){
15487 * Try to focus this component.
15488 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15489 * @return {Roo.Component} this
15491 focus : function(selectText){
15494 if(selectText === true){
15495 this.el.dom.select();
15510 * Disable this component.
15511 * @return {Roo.Component} this
15513 disable : function(){
15517 this.disabled = true;
15518 this.fireEvent("disable", this);
15523 onDisable : function(){
15524 this.getActionEl().addClass(this.disabledClass);
15525 this.el.dom.disabled = true;
15529 * Enable this component.
15530 * @return {Roo.Component} this
15532 enable : function(){
15536 this.disabled = false;
15537 this.fireEvent("enable", this);
15542 onEnable : function(){
15543 this.getActionEl().removeClass(this.disabledClass);
15544 this.el.dom.disabled = false;
15548 * Convenience function for setting disabled/enabled by boolean.
15549 * @param {Boolean} disabled
15551 setDisabled : function(disabled){
15552 this[disabled ? "disable" : "enable"]();
15556 * Show this component.
15557 * @return {Roo.Component} this
15560 if(this.fireEvent("beforeshow", this) !== false){
15561 this.hidden = false;
15565 this.fireEvent("show", this);
15571 onShow : function(){
15572 var ae = this.getActionEl();
15573 if(this.hideMode == 'visibility'){
15574 ae.dom.style.visibility = "visible";
15575 }else if(this.hideMode == 'offsets'){
15576 ae.removeClass('x-hidden');
15578 ae.dom.style.display = "";
15583 * Hide this component.
15584 * @return {Roo.Component} this
15587 if(this.fireEvent("beforehide", this) !== false){
15588 this.hidden = true;
15592 this.fireEvent("hide", this);
15598 onHide : function(){
15599 var ae = this.getActionEl();
15600 if(this.hideMode == 'visibility'){
15601 ae.dom.style.visibility = "hidden";
15602 }else if(this.hideMode == 'offsets'){
15603 ae.addClass('x-hidden');
15605 ae.dom.style.display = "none";
15610 * Convenience function to hide or show this component by boolean.
15611 * @param {Boolean} visible True to show, false to hide
15612 * @return {Roo.Component} this
15614 setVisible: function(visible){
15624 * Returns true if this component is visible.
15626 isVisible : function(){
15627 return this.getActionEl().isVisible();
15630 cloneConfig : function(overrides){
15631 overrides = overrides || {};
15632 var id = overrides.id || Roo.id();
15633 var cfg = Roo.applyIf(overrides, this.initialConfig);
15634 cfg.id = id; // prevent dup id
15635 return new this.constructor(cfg);
15639 * Ext JS Library 1.1.1
15640 * Copyright(c) 2006-2007, Ext JS, LLC.
15642 * Originally Released Under LGPL - original licence link has changed is not relivant.
15645 * <script type="text/javascript">
15649 * @class Roo.BoxComponent
15650 * @extends Roo.Component
15651 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15652 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15653 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15654 * layout containers.
15656 * @param {Roo.Element/String/Object} config The configuration options.
15658 Roo.BoxComponent = function(config){
15659 Roo.Component.call(this, config);
15663 * Fires after the component is resized.
15664 * @param {Roo.Component} this
15665 * @param {Number} adjWidth The box-adjusted width that was set
15666 * @param {Number} adjHeight The box-adjusted height that was set
15667 * @param {Number} rawWidth The width that was originally specified
15668 * @param {Number} rawHeight The height that was originally specified
15673 * Fires after the component is moved.
15674 * @param {Roo.Component} this
15675 * @param {Number} x The new x position
15676 * @param {Number} y The new y position
15682 Roo.extend(Roo.BoxComponent, Roo.Component, {
15683 // private, set in afterRender to signify that the component has been rendered
15685 // private, used to defer height settings to subclasses
15686 deferHeight: false,
15687 /** @cfg {Number} width
15688 * width (optional) size of component
15690 /** @cfg {Number} height
15691 * height (optional) size of component
15695 * Sets the width and height of the component. This method fires the resize event. This method can accept
15696 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15697 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15698 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15699 * @return {Roo.BoxComponent} this
15701 setSize : function(w, h){
15702 // support for standard size objects
15703 if(typeof w == 'object'){
15708 if(!this.boxReady){
15714 // prevent recalcs when not needed
15715 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15718 this.lastSize = {width: w, height: h};
15720 var adj = this.adjustSize(w, h);
15721 var aw = adj.width, ah = adj.height;
15722 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15723 var rz = this.getResizeEl();
15724 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15725 rz.setSize(aw, ah);
15726 }else if(!this.deferHeight && ah !== undefined){
15728 }else if(aw !== undefined){
15731 this.onResize(aw, ah, w, h);
15732 this.fireEvent('resize', this, aw, ah, w, h);
15738 * Gets the current size of the component's underlying element.
15739 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15741 getSize : function(){
15742 return this.el.getSize();
15746 * Gets the current XY position of the component's underlying element.
15747 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15748 * @return {Array} The XY position of the element (e.g., [100, 200])
15750 getPosition : function(local){
15751 if(local === true){
15752 return [this.el.getLeft(true), this.el.getTop(true)];
15754 return this.xy || this.el.getXY();
15758 * Gets the current box measurements of the component's underlying element.
15759 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15760 * @returns {Object} box An object in the format {x, y, width, height}
15762 getBox : function(local){
15763 var s = this.el.getSize();
15765 s.x = this.el.getLeft(true);
15766 s.y = this.el.getTop(true);
15768 var xy = this.xy || this.el.getXY();
15776 * Sets the current box measurements of the component's underlying element.
15777 * @param {Object} box An object in the format {x, y, width, height}
15778 * @returns {Roo.BoxComponent} this
15780 updateBox : function(box){
15781 this.setSize(box.width, box.height);
15782 this.setPagePosition(box.x, box.y);
15787 getResizeEl : function(){
15788 return this.resizeEl || this.el;
15792 getPositionEl : function(){
15793 return this.positionEl || this.el;
15797 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15798 * This method fires the move event.
15799 * @param {Number} left The new left
15800 * @param {Number} top The new top
15801 * @returns {Roo.BoxComponent} this
15803 setPosition : function(x, y){
15806 if(!this.boxReady){
15809 var adj = this.adjustPosition(x, y);
15810 var ax = adj.x, ay = adj.y;
15812 var el = this.getPositionEl();
15813 if(ax !== undefined || ay !== undefined){
15814 if(ax !== undefined && ay !== undefined){
15815 el.setLeftTop(ax, ay);
15816 }else if(ax !== undefined){
15818 }else if(ay !== undefined){
15821 this.onPosition(ax, ay);
15822 this.fireEvent('move', this, ax, ay);
15828 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15829 * This method fires the move event.
15830 * @param {Number} x The new x position
15831 * @param {Number} y The new y position
15832 * @returns {Roo.BoxComponent} this
15834 setPagePosition : function(x, y){
15837 if(!this.boxReady){
15840 if(x === undefined || y === undefined){ // cannot translate undefined points
15843 var p = this.el.translatePoints(x, y);
15844 this.setPosition(p.left, p.top);
15849 onRender : function(ct, position){
15850 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15852 this.resizeEl = Roo.get(this.resizeEl);
15854 if(this.positionEl){
15855 this.positionEl = Roo.get(this.positionEl);
15860 afterRender : function(){
15861 Roo.BoxComponent.superclass.afterRender.call(this);
15862 this.boxReady = true;
15863 this.setSize(this.width, this.height);
15864 if(this.x || this.y){
15865 this.setPosition(this.x, this.y);
15867 if(this.pageX || this.pageY){
15868 this.setPagePosition(this.pageX, this.pageY);
15873 * Force the component's size to recalculate based on the underlying element's current height and width.
15874 * @returns {Roo.BoxComponent} this
15876 syncSize : function(){
15877 delete this.lastSize;
15878 this.setSize(this.el.getWidth(), this.el.getHeight());
15883 * Called after the component is resized, this method is empty by default but can be implemented by any
15884 * subclass that needs to perform custom logic after a resize occurs.
15885 * @param {Number} adjWidth The box-adjusted width that was set
15886 * @param {Number} adjHeight The box-adjusted height that was set
15887 * @param {Number} rawWidth The width that was originally specified
15888 * @param {Number} rawHeight The height that was originally specified
15890 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15895 * Called after the component is moved, this method is empty by default but can be implemented by any
15896 * subclass that needs to perform custom logic after a move occurs.
15897 * @param {Number} x The new x position
15898 * @param {Number} y The new y position
15900 onPosition : function(x, y){
15905 adjustSize : function(w, h){
15906 if(this.autoWidth){
15909 if(this.autoHeight){
15912 return {width : w, height: h};
15916 adjustPosition : function(x, y){
15917 return {x : x, y: y};
15920 * Original code for Roojs - LGPL
15921 * <script type="text/javascript">
15925 * @class Roo.XComponent
15926 * A delayed Element creator...
15927 * Or a way to group chunks of interface together.
15928 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15929 * used in conjunction with XComponent.build() it will create an instance of each element,
15930 * then call addxtype() to build the User interface.
15932 * Mypart.xyx = new Roo.XComponent({
15934 parent : 'Mypart.xyz', // empty == document.element.!!
15938 disabled : function() {}
15940 tree : function() { // return an tree of xtype declared components
15944 xtype : 'NestedLayoutPanel',
15951 * It can be used to build a big heiracy, with parent etc.
15952 * or you can just use this to render a single compoent to a dom element
15953 * MYPART.render(Roo.Element | String(id) | dom_element )
15960 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15961 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15963 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15965 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15966 * - if mulitple topModules exist, the last one is defined as the top module.
15970 * When the top level or multiple modules are to embedded into a existing HTML page,
15971 * the parent element can container '#id' of the element where the module will be drawn.
15975 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15976 * it relies more on a include mechanism, where sub modules are included into an outer page.
15977 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15979 * Bootstrap Roo Included elements
15981 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15982 * hence confusing the component builder as it thinks there are multiple top level elements.
15986 * @extends Roo.util.Observable
15988 * @param cfg {Object} configuration of component
15991 Roo.XComponent = function(cfg) {
15992 Roo.apply(this, cfg);
15996 * Fires when this the componnt is built
15997 * @param {Roo.XComponent} c the component
16002 this.region = this.region || 'center'; // default..
16003 Roo.XComponent.register(this);
16004 this.modules = false;
16005 this.el = false; // where the layout goes..
16009 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16012 * The created element (with Roo.factory())
16013 * @type {Roo.Layout}
16019 * for BC - use el in new code
16020 * @type {Roo.Layout}
16026 * for BC - use el in new code
16027 * @type {Roo.Layout}
16032 * @cfg {Function|boolean} disabled
16033 * If this module is disabled by some rule, return true from the funtion
16038 * @cfg {String} parent
16039 * Name of parent element which it get xtype added to..
16044 * @cfg {String} order
16045 * Used to set the order in which elements are created (usefull for multiple tabs)
16050 * @cfg {String} name
16051 * String to display while loading.
16055 * @cfg {String} region
16056 * Region to render component to (defaults to center)
16061 * @cfg {Array} items
16062 * A single item array - the first element is the root of the tree..
16063 * It's done this way to stay compatible with the Xtype system...
16069 * The method that retuns the tree of parts that make up this compoennt
16076 * render element to dom or tree
16077 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16080 render : function(el)
16084 var hp = this.parent ? 1 : 0;
16085 Roo.debug && Roo.log(this);
16087 var tree = this._tree ? this._tree() : this.tree();
16090 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16091 // if parent is a '#.....' string, then let's use that..
16092 var ename = this.parent.substr(1);
16093 this.parent = false;
16094 Roo.debug && Roo.log(ename);
16096 case 'bootstrap-body':
16097 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16098 // this is the BorderLayout standard?
16099 this.parent = { el : true };
16102 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16103 // need to insert stuff...
16105 el : new Roo.bootstrap.layout.Border({
16106 el : document.body,
16112 tabPosition: 'top',
16113 //resizeTabs: true,
16114 alwaysShowTabs: true,
16124 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16125 this.parent = { el : new Roo.bootstrap.Body() };
16126 Roo.debug && Roo.log("setting el to doc body");
16129 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16133 this.parent = { el : true};
16136 el = Roo.get(ename);
16137 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16138 this.parent = { el : true};
16145 if (!el && !this.parent) {
16146 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16151 Roo.debug && Roo.log("EL:");
16152 Roo.debug && Roo.log(el);
16153 Roo.debug && Roo.log("this.parent.el:");
16154 Roo.debug && Roo.log(this.parent.el);
16157 // altertive root elements ??? - we need a better way to indicate these.
16158 var is_alt = Roo.XComponent.is_alt ||
16159 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16160 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16161 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16165 if (!this.parent && is_alt) {
16166 //el = Roo.get(document.body);
16167 this.parent = { el : true };
16172 if (!this.parent) {
16174 Roo.debug && Roo.log("no parent - creating one");
16176 el = el ? Roo.get(el) : false;
16178 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16181 el : new Roo.bootstrap.layout.Border({
16182 el: el || document.body,
16188 tabPosition: 'top',
16189 //resizeTabs: true,
16190 alwaysShowTabs: false,
16193 overflow: 'visible'
16199 // it's a top level one..
16201 el : new Roo.BorderLayout(el || document.body, {
16206 tabPosition: 'top',
16207 //resizeTabs: true,
16208 alwaysShowTabs: el && hp? false : true,
16209 hideTabs: el || !hp ? true : false,
16217 if (!this.parent.el) {
16218 // probably an old style ctor, which has been disabled.
16222 // The 'tree' method is '_tree now'
16224 tree.region = tree.region || this.region;
16225 var is_body = false;
16226 if (this.parent.el === true) {
16227 // bootstrap... - body..
16231 this.parent.el = Roo.factory(tree);
16235 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16236 this.fireEvent('built', this);
16238 this.panel = this.el;
16239 this.layout = this.panel.layout;
16240 this.parentLayout = this.parent.layout || false;
16246 Roo.apply(Roo.XComponent, {
16248 * @property hideProgress
16249 * true to disable the building progress bar.. usefull on single page renders.
16252 hideProgress : false,
16254 * @property buildCompleted
16255 * True when the builder has completed building the interface.
16258 buildCompleted : false,
16261 * @property topModule
16262 * the upper most module - uses document.element as it's constructor.
16269 * @property modules
16270 * array of modules to be created by registration system.
16271 * @type {Array} of Roo.XComponent
16276 * @property elmodules
16277 * array of modules to be created by which use #ID
16278 * @type {Array} of Roo.XComponent
16285 * Is an alternative Root - normally used by bootstrap or other systems,
16286 * where the top element in the tree can wrap 'body'
16287 * @type {boolean} (default false)
16292 * @property build_from_html
16293 * Build elements from html - used by bootstrap HTML stuff
16294 * - this is cleared after build is completed
16295 * @type {boolean} (default false)
16298 build_from_html : false,
16300 * Register components to be built later.
16302 * This solves the following issues
16303 * - Building is not done on page load, but after an authentication process has occured.
16304 * - Interface elements are registered on page load
16305 * - Parent Interface elements may not be loaded before child, so this handles that..
16312 module : 'Pman.Tab.projectMgr',
16314 parent : 'Pman.layout',
16315 disabled : false, // or use a function..
16318 * * @param {Object} details about module
16320 register : function(obj) {
16322 Roo.XComponent.event.fireEvent('register', obj);
16323 switch(typeof(obj.disabled) ) {
16329 if ( obj.disabled() ) {
16335 if (obj.disabled) {
16341 this.modules.push(obj);
16345 * convert a string to an object..
16346 * eg. 'AAA.BBB' -> finds AAA.BBB
16350 toObject : function(str)
16352 if (!str || typeof(str) == 'object') {
16355 if (str.substring(0,1) == '#') {
16359 var ar = str.split('.');
16364 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16366 throw "Module not found : " + str;
16370 throw "Module not found : " + str;
16372 Roo.each(ar, function(e) {
16373 if (typeof(o[e]) == 'undefined') {
16374 throw "Module not found : " + str;
16385 * move modules into their correct place in the tree..
16388 preBuild : function ()
16391 Roo.each(this.modules , function (obj)
16393 Roo.XComponent.event.fireEvent('beforebuild', obj);
16395 var opar = obj.parent;
16397 obj.parent = this.toObject(opar);
16399 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16404 Roo.debug && Roo.log("GOT top level module");
16405 Roo.debug && Roo.log(obj);
16406 obj.modules = new Roo.util.MixedCollection(false,
16407 function(o) { return o.order + '' }
16409 this.topModule = obj;
16412 // parent is a string (usually a dom element name..)
16413 if (typeof(obj.parent) == 'string') {
16414 this.elmodules.push(obj);
16417 if (obj.parent.constructor != Roo.XComponent) {
16418 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16420 if (!obj.parent.modules) {
16421 obj.parent.modules = new Roo.util.MixedCollection(false,
16422 function(o) { return o.order + '' }
16425 if (obj.parent.disabled) {
16426 obj.disabled = true;
16428 obj.parent.modules.add(obj);
16433 * make a list of modules to build.
16434 * @return {Array} list of modules.
16437 buildOrder : function()
16440 var cmp = function(a,b) {
16441 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16443 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16444 throw "No top level modules to build";
16447 // make a flat list in order of modules to build.
16448 var mods = this.topModule ? [ this.topModule ] : [];
16451 // elmodules (is a list of DOM based modules )
16452 Roo.each(this.elmodules, function(e) {
16454 if (!this.topModule &&
16455 typeof(e.parent) == 'string' &&
16456 e.parent.substring(0,1) == '#' &&
16457 Roo.get(e.parent.substr(1))
16460 _this.topModule = e;
16466 // add modules to their parents..
16467 var addMod = function(m) {
16468 Roo.debug && Roo.log("build Order: add: " + m.name);
16471 if (m.modules && !m.disabled) {
16472 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16473 m.modules.keySort('ASC', cmp );
16474 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16476 m.modules.each(addMod);
16478 Roo.debug && Roo.log("build Order: no child modules");
16480 // not sure if this is used any more..
16482 m.finalize.name = m.name + " (clean up) ";
16483 mods.push(m.finalize);
16487 if (this.topModule && this.topModule.modules) {
16488 this.topModule.modules.keySort('ASC', cmp );
16489 this.topModule.modules.each(addMod);
16495 * Build the registered modules.
16496 * @param {Object} parent element.
16497 * @param {Function} optional method to call after module has been added.
16501 build : function(opts)
16504 if (typeof(opts) != 'undefined') {
16505 Roo.apply(this,opts);
16509 var mods = this.buildOrder();
16511 //this.allmods = mods;
16512 //Roo.debug && Roo.log(mods);
16514 if (!mods.length) { // should not happen
16515 throw "NO modules!!!";
16519 var msg = "Building Interface...";
16520 // flash it up as modal - so we store the mask!?
16521 if (!this.hideProgress && Roo.MessageBox) {
16522 Roo.MessageBox.show({ title: 'loading' });
16523 Roo.MessageBox.show({
16524 title: "Please wait...",
16533 var total = mods.length;
16536 var progressRun = function() {
16537 if (!mods.length) {
16538 Roo.debug && Roo.log('hide?');
16539 if (!this.hideProgress && Roo.MessageBox) {
16540 Roo.MessageBox.hide();
16542 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16544 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16550 var m = mods.shift();
16553 Roo.debug && Roo.log(m);
16554 // not sure if this is supported any more.. - modules that are are just function
16555 if (typeof(m) == 'function') {
16557 return progressRun.defer(10, _this);
16561 msg = "Building Interface " + (total - mods.length) +
16563 (m.name ? (' - ' + m.name) : '');
16564 Roo.debug && Roo.log(msg);
16565 if (!_this.hideProgress && Roo.MessageBox) {
16566 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16570 // is the module disabled?
16571 var disabled = (typeof(m.disabled) == 'function') ?
16572 m.disabled.call(m.module.disabled) : m.disabled;
16576 return progressRun(); // we do not update the display!
16584 // it's 10 on top level, and 1 on others??? why...
16585 return progressRun.defer(10, _this);
16588 progressRun.defer(1, _this);
16602 * wrapper for event.on - aliased later..
16603 * Typically use to register a event handler for register:
16605 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16614 Roo.XComponent.event = new Roo.util.Observable({
16618 * Fires when an Component is registered,
16619 * set the disable property on the Component to stop registration.
16620 * @param {Roo.XComponent} c the component being registerd.
16625 * @event beforebuild
16626 * Fires before each Component is built
16627 * can be used to apply permissions.
16628 * @param {Roo.XComponent} c the component being registerd.
16631 'beforebuild' : true,
16633 * @event buildcomplete
16634 * Fires on the top level element when all elements have been built
16635 * @param {Roo.XComponent} the top level component.
16637 'buildcomplete' : true
16642 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16645 * marked - a markdown parser
16646 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16647 * https://github.com/chjj/marked
16653 * Roo.Markdown - is a very crude wrapper around marked..
16657 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16659 * Note: move the sample code to the bottom of this
16660 * file before uncommenting it.
16665 Roo.Markdown.toHtml = function(text) {
16667 var c = new Roo.Markdown.marked.setOptions({
16668 renderer: new Roo.Markdown.marked.Renderer(),
16679 text = text.replace(/\\\n/g,' ');
16680 return Roo.Markdown.marked(text);
16685 // Wraps all "globals" so that the only thing
16686 // exposed is makeHtml().
16691 * Block-Level Grammar
16696 code: /^( {4}[^\n]+\n*)+/,
16698 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16699 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16701 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16702 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16703 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16704 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16705 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16707 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16711 block.bullet = /(?:[*+-]|\d+\.)/;
16712 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16713 block.item = replace(block.item, 'gm')
16714 (/bull/g, block.bullet)
16717 block.list = replace(block.list)
16718 (/bull/g, block.bullet)
16719 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16720 ('def', '\\n+(?=' + block.def.source + ')')
16723 block.blockquote = replace(block.blockquote)
16727 block._tag = '(?!(?:'
16728 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16729 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16730 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16732 block.html = replace(block.html)
16733 ('comment', /<!--[\s\S]*?-->/)
16734 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16735 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16736 (/tag/g, block._tag)
16739 block.paragraph = replace(block.paragraph)
16741 ('heading', block.heading)
16742 ('lheading', block.lheading)
16743 ('blockquote', block.blockquote)
16744 ('tag', '<' + block._tag)
16749 * Normal Block Grammar
16752 block.normal = merge({}, block);
16755 * GFM Block Grammar
16758 block.gfm = merge({}, block.normal, {
16759 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16761 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16764 block.gfm.paragraph = replace(block.paragraph)
16766 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16767 + block.list.source.replace('\\1', '\\3') + '|')
16771 * GFM + Tables Block Grammar
16774 block.tables = merge({}, block.gfm, {
16775 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16776 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16783 function Lexer(options) {
16785 this.tokens.links = {};
16786 this.options = options || marked.defaults;
16787 this.rules = block.normal;
16789 if (this.options.gfm) {
16790 if (this.options.tables) {
16791 this.rules = block.tables;
16793 this.rules = block.gfm;
16799 * Expose Block Rules
16802 Lexer.rules = block;
16805 * Static Lex Method
16808 Lexer.lex = function(src, options) {
16809 var lexer = new Lexer(options);
16810 return lexer.lex(src);
16817 Lexer.prototype.lex = function(src) {
16819 .replace(/\r\n|\r/g, '\n')
16820 .replace(/\t/g, ' ')
16821 .replace(/\u00a0/g, ' ')
16822 .replace(/\u2424/g, '\n');
16824 return this.token(src, true);
16831 Lexer.prototype.token = function(src, top, bq) {
16832 var src = src.replace(/^ +$/gm, '')
16845 if (cap = this.rules.newline.exec(src)) {
16846 src = src.substring(cap[0].length);
16847 if (cap[0].length > 1) {
16855 if (cap = this.rules.code.exec(src)) {
16856 src = src.substring(cap[0].length);
16857 cap = cap[0].replace(/^ {4}/gm, '');
16860 text: !this.options.pedantic
16861 ? cap.replace(/\n+$/, '')
16868 if (cap = this.rules.fences.exec(src)) {
16869 src = src.substring(cap[0].length);
16879 if (cap = this.rules.heading.exec(src)) {
16880 src = src.substring(cap[0].length);
16883 depth: cap[1].length,
16889 // table no leading pipe (gfm)
16890 if (top && (cap = this.rules.nptable.exec(src))) {
16891 src = src.substring(cap[0].length);
16895 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16896 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16897 cells: cap[3].replace(/\n$/, '').split('\n')
16900 for (i = 0; i < item.align.length; i++) {
16901 if (/^ *-+: *$/.test(item.align[i])) {
16902 item.align[i] = 'right';
16903 } else if (/^ *:-+: *$/.test(item.align[i])) {
16904 item.align[i] = 'center';
16905 } else if (/^ *:-+ *$/.test(item.align[i])) {
16906 item.align[i] = 'left';
16908 item.align[i] = null;
16912 for (i = 0; i < item.cells.length; i++) {
16913 item.cells[i] = item.cells[i].split(/ *\| */);
16916 this.tokens.push(item);
16922 if (cap = this.rules.lheading.exec(src)) {
16923 src = src.substring(cap[0].length);
16926 depth: cap[2] === '=' ? 1 : 2,
16933 if (cap = this.rules.hr.exec(src)) {
16934 src = src.substring(cap[0].length);
16942 if (cap = this.rules.blockquote.exec(src)) {
16943 src = src.substring(cap[0].length);
16946 type: 'blockquote_start'
16949 cap = cap[0].replace(/^ *> ?/gm, '');
16951 // Pass `top` to keep the current
16952 // "toplevel" state. This is exactly
16953 // how markdown.pl works.
16954 this.token(cap, top, true);
16957 type: 'blockquote_end'
16964 if (cap = this.rules.list.exec(src)) {
16965 src = src.substring(cap[0].length);
16969 type: 'list_start',
16970 ordered: bull.length > 1
16973 // Get each top-level item.
16974 cap = cap[0].match(this.rules.item);
16980 for (; i < l; i++) {
16983 // Remove the list item's bullet
16984 // so it is seen as the next token.
16985 space = item.length;
16986 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16988 // Outdent whatever the
16989 // list item contains. Hacky.
16990 if (~item.indexOf('\n ')) {
16991 space -= item.length;
16992 item = !this.options.pedantic
16993 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16994 : item.replace(/^ {1,4}/gm, '');
16997 // Determine whether the next list item belongs here.
16998 // Backpedal if it does not belong in this list.
16999 if (this.options.smartLists && i !== l - 1) {
17000 b = block.bullet.exec(cap[i + 1])[0];
17001 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17002 src = cap.slice(i + 1).join('\n') + src;
17007 // Determine whether item is loose or not.
17008 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17009 // for discount behavior.
17010 loose = next || /\n\n(?!\s*$)/.test(item);
17012 next = item.charAt(item.length - 1) === '\n';
17013 if (!loose) { loose = next; }
17018 ? 'loose_item_start'
17019 : 'list_item_start'
17023 this.token(item, false, bq);
17026 type: 'list_item_end'
17038 if (cap = this.rules.html.exec(src)) {
17039 src = src.substring(cap[0].length);
17041 type: this.options.sanitize
17044 pre: !this.options.sanitizer
17045 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17052 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17053 src = src.substring(cap[0].length);
17054 this.tokens.links[cap[1].toLowerCase()] = {
17062 if (top && (cap = this.rules.table.exec(src))) {
17063 src = src.substring(cap[0].length);
17067 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17068 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17069 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17072 for (i = 0; i < item.align.length; i++) {
17073 if (/^ *-+: *$/.test(item.align[i])) {
17074 item.align[i] = 'right';
17075 } else if (/^ *:-+: *$/.test(item.align[i])) {
17076 item.align[i] = 'center';
17077 } else if (/^ *:-+ *$/.test(item.align[i])) {
17078 item.align[i] = 'left';
17080 item.align[i] = null;
17084 for (i = 0; i < item.cells.length; i++) {
17085 item.cells[i] = item.cells[i]
17086 .replace(/^ *\| *| *\| *$/g, '')
17090 this.tokens.push(item);
17095 // top-level paragraph
17096 if (top && (cap = this.rules.paragraph.exec(src))) {
17097 src = src.substring(cap[0].length);
17100 text: cap[1].charAt(cap[1].length - 1) === '\n'
17101 ? cap[1].slice(0, -1)
17108 if (cap = this.rules.text.exec(src)) {
17109 // Top-level should never reach here.
17110 src = src.substring(cap[0].length);
17120 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17124 return this.tokens;
17128 * Inline-Level Grammar
17132 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17133 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17135 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17136 link: /^!?\[(inside)\]\(href\)/,
17137 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17138 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17139 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17140 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17141 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17142 br: /^ {2,}\n(?!\s*$)/,
17144 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17147 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17148 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17150 inline.link = replace(inline.link)
17151 ('inside', inline._inside)
17152 ('href', inline._href)
17155 inline.reflink = replace(inline.reflink)
17156 ('inside', inline._inside)
17160 * Normal Inline Grammar
17163 inline.normal = merge({}, inline);
17166 * Pedantic Inline Grammar
17169 inline.pedantic = merge({}, inline.normal, {
17170 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17171 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17175 * GFM Inline Grammar
17178 inline.gfm = merge({}, inline.normal, {
17179 escape: replace(inline.escape)('])', '~|])')(),
17180 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17181 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17182 text: replace(inline.text)
17184 ('|', '|https?://|')
17189 * GFM + Line Breaks Inline Grammar
17192 inline.breaks = merge({}, inline.gfm, {
17193 br: replace(inline.br)('{2,}', '*')(),
17194 text: replace(inline.gfm.text)('{2,}', '*')()
17198 * Inline Lexer & Compiler
17201 function InlineLexer(links, options) {
17202 this.options = options || marked.defaults;
17203 this.links = links;
17204 this.rules = inline.normal;
17205 this.renderer = this.options.renderer || new Renderer;
17206 this.renderer.options = this.options;
17210 Error('Tokens array requires a `links` property.');
17213 if (this.options.gfm) {
17214 if (this.options.breaks) {
17215 this.rules = inline.breaks;
17217 this.rules = inline.gfm;
17219 } else if (this.options.pedantic) {
17220 this.rules = inline.pedantic;
17225 * Expose Inline Rules
17228 InlineLexer.rules = inline;
17231 * Static Lexing/Compiling Method
17234 InlineLexer.output = function(src, links, options) {
17235 var inline = new InlineLexer(links, options);
17236 return inline.output(src);
17243 InlineLexer.prototype.output = function(src) {
17252 if (cap = this.rules.escape.exec(src)) {
17253 src = src.substring(cap[0].length);
17259 if (cap = this.rules.autolink.exec(src)) {
17260 src = src.substring(cap[0].length);
17261 if (cap[2] === '@') {
17262 text = cap[1].charAt(6) === ':'
17263 ? this.mangle(cap[1].substring(7))
17264 : this.mangle(cap[1]);
17265 href = this.mangle('mailto:') + text;
17267 text = escape(cap[1]);
17270 out += this.renderer.link(href, null, text);
17275 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17276 src = src.substring(cap[0].length);
17277 text = escape(cap[1]);
17279 out += this.renderer.link(href, null, text);
17284 if (cap = this.rules.tag.exec(src)) {
17285 if (!this.inLink && /^<a /i.test(cap[0])) {
17286 this.inLink = true;
17287 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17288 this.inLink = false;
17290 src = src.substring(cap[0].length);
17291 out += this.options.sanitize
17292 ? this.options.sanitizer
17293 ? this.options.sanitizer(cap[0])
17300 if (cap = this.rules.link.exec(src)) {
17301 src = src.substring(cap[0].length);
17302 this.inLink = true;
17303 out += this.outputLink(cap, {
17307 this.inLink = false;
17312 if ((cap = this.rules.reflink.exec(src))
17313 || (cap = this.rules.nolink.exec(src))) {
17314 src = src.substring(cap[0].length);
17315 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17316 link = this.links[link.toLowerCase()];
17317 if (!link || !link.href) {
17318 out += cap[0].charAt(0);
17319 src = cap[0].substring(1) + src;
17322 this.inLink = true;
17323 out += this.outputLink(cap, link);
17324 this.inLink = false;
17329 if (cap = this.rules.strong.exec(src)) {
17330 src = src.substring(cap[0].length);
17331 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17336 if (cap = this.rules.em.exec(src)) {
17337 src = src.substring(cap[0].length);
17338 out += this.renderer.em(this.output(cap[2] || cap[1]));
17343 if (cap = this.rules.code.exec(src)) {
17344 src = src.substring(cap[0].length);
17345 out += this.renderer.codespan(escape(cap[2], true));
17350 if (cap = this.rules.br.exec(src)) {
17351 src = src.substring(cap[0].length);
17352 out += this.renderer.br();
17357 if (cap = this.rules.del.exec(src)) {
17358 src = src.substring(cap[0].length);
17359 out += this.renderer.del(this.output(cap[1]));
17364 if (cap = this.rules.text.exec(src)) {
17365 src = src.substring(cap[0].length);
17366 out += this.renderer.text(escape(this.smartypants(cap[0])));
17372 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17383 InlineLexer.prototype.outputLink = function(cap, link) {
17384 var href = escape(link.href)
17385 , title = link.title ? escape(link.title) : null;
17387 return cap[0].charAt(0) !== '!'
17388 ? this.renderer.link(href, title, this.output(cap[1]))
17389 : this.renderer.image(href, title, escape(cap[1]));
17393 * Smartypants Transformations
17396 InlineLexer.prototype.smartypants = function(text) {
17397 if (!this.options.smartypants) { return text; }
17400 .replace(/---/g, '\u2014')
17402 .replace(/--/g, '\u2013')
17404 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17405 // closing singles & apostrophes
17406 .replace(/'/g, '\u2019')
17408 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17410 .replace(/"/g, '\u201d')
17412 .replace(/\.{3}/g, '\u2026');
17419 InlineLexer.prototype.mangle = function(text) {
17420 if (!this.options.mangle) { return text; }
17426 for (; i < l; i++) {
17427 ch = text.charCodeAt(i);
17428 if (Math.random() > 0.5) {
17429 ch = 'x' + ch.toString(16);
17431 out += '&#' + ch + ';';
17441 function Renderer(options) {
17442 this.options = options || {};
17445 Renderer.prototype.code = function(code, lang, escaped) {
17446 if (this.options.highlight) {
17447 var out = this.options.highlight(code, lang);
17448 if (out != null && out !== code) {
17453 // hack!!! - it's already escapeD?
17458 return '<pre><code>'
17459 + (escaped ? code : escape(code, true))
17460 + '\n</code></pre>';
17463 return '<pre><code class="'
17464 + this.options.langPrefix
17465 + escape(lang, true)
17467 + (escaped ? code : escape(code, true))
17468 + '\n</code></pre>\n';
17471 Renderer.prototype.blockquote = function(quote) {
17472 return '<blockquote>\n' + quote + '</blockquote>\n';
17475 Renderer.prototype.html = function(html) {
17479 Renderer.prototype.heading = function(text, level, raw) {
17483 + this.options.headerPrefix
17484 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17492 Renderer.prototype.hr = function() {
17493 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17496 Renderer.prototype.list = function(body, ordered) {
17497 var type = ordered ? 'ol' : 'ul';
17498 return '<' + type + '>\n' + body + '</' + type + '>\n';
17501 Renderer.prototype.listitem = function(text) {
17502 return '<li>' + text + '</li>\n';
17505 Renderer.prototype.paragraph = function(text) {
17506 return '<p>' + text + '</p>\n';
17509 Renderer.prototype.table = function(header, body) {
17510 return '<table class="table table-striped">\n'
17520 Renderer.prototype.tablerow = function(content) {
17521 return '<tr>\n' + content + '</tr>\n';
17524 Renderer.prototype.tablecell = function(content, flags) {
17525 var type = flags.header ? 'th' : 'td';
17526 var tag = flags.align
17527 ? '<' + type + ' style="text-align:' + flags.align + '">'
17528 : '<' + type + '>';
17529 return tag + content + '</' + type + '>\n';
17532 // span level renderer
17533 Renderer.prototype.strong = function(text) {
17534 return '<strong>' + text + '</strong>';
17537 Renderer.prototype.em = function(text) {
17538 return '<em>' + text + '</em>';
17541 Renderer.prototype.codespan = function(text) {
17542 return '<code>' + text + '</code>';
17545 Renderer.prototype.br = function() {
17546 return this.options.xhtml ? '<br/>' : '<br>';
17549 Renderer.prototype.del = function(text) {
17550 return '<del>' + text + '</del>';
17553 Renderer.prototype.link = function(href, title, text) {
17554 if (this.options.sanitize) {
17556 var prot = decodeURIComponent(unescape(href))
17557 .replace(/[^\w:]/g, '')
17562 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17566 var out = '<a href="' + href + '"';
17568 out += ' title="' + title + '"';
17570 out += '>' + text + '</a>';
17574 Renderer.prototype.image = function(href, title, text) {
17575 var out = '<img src="' + href + '" alt="' + text + '"';
17577 out += ' title="' + title + '"';
17579 out += this.options.xhtml ? '/>' : '>';
17583 Renderer.prototype.text = function(text) {
17588 * Parsing & Compiling
17591 function Parser(options) {
17594 this.options = options || marked.defaults;
17595 this.options.renderer = this.options.renderer || new Renderer;
17596 this.renderer = this.options.renderer;
17597 this.renderer.options = this.options;
17601 * Static Parse Method
17604 Parser.parse = function(src, options, renderer) {
17605 var parser = new Parser(options, renderer);
17606 return parser.parse(src);
17613 Parser.prototype.parse = function(src) {
17614 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17615 this.tokens = src.reverse();
17618 while (this.next()) {
17629 Parser.prototype.next = function() {
17630 return this.token = this.tokens.pop();
17634 * Preview Next Token
17637 Parser.prototype.peek = function() {
17638 return this.tokens[this.tokens.length - 1] || 0;
17642 * Parse Text Tokens
17645 Parser.prototype.parseText = function() {
17646 var body = this.token.text;
17648 while (this.peek().type === 'text') {
17649 body += '\n' + this.next().text;
17652 return this.inline.output(body);
17656 * Parse Current Token
17659 Parser.prototype.tok = function() {
17660 switch (this.token.type) {
17665 return this.renderer.hr();
17668 return this.renderer.heading(
17669 this.inline.output(this.token.text),
17674 return this.renderer.code(this.token.text,
17676 this.token.escaped);
17689 for (i = 0; i < this.token.header.length; i++) {
17690 flags = { header: true, align: this.token.align[i] };
17691 cell += this.renderer.tablecell(
17692 this.inline.output(this.token.header[i]),
17693 { header: true, align: this.token.align[i] }
17696 header += this.renderer.tablerow(cell);
17698 for (i = 0; i < this.token.cells.length; i++) {
17699 row = this.token.cells[i];
17702 for (j = 0; j < row.length; j++) {
17703 cell += this.renderer.tablecell(
17704 this.inline.output(row[j]),
17705 { header: false, align: this.token.align[j] }
17709 body += this.renderer.tablerow(cell);
17711 return this.renderer.table(header, body);
17713 case 'blockquote_start': {
17716 while (this.next().type !== 'blockquote_end') {
17717 body += this.tok();
17720 return this.renderer.blockquote(body);
17722 case 'list_start': {
17724 , ordered = this.token.ordered;
17726 while (this.next().type !== 'list_end') {
17727 body += this.tok();
17730 return this.renderer.list(body, ordered);
17732 case 'list_item_start': {
17735 while (this.next().type !== 'list_item_end') {
17736 body += this.token.type === 'text'
17741 return this.renderer.listitem(body);
17743 case 'loose_item_start': {
17746 while (this.next().type !== 'list_item_end') {
17747 body += this.tok();
17750 return this.renderer.listitem(body);
17753 var html = !this.token.pre && !this.options.pedantic
17754 ? this.inline.output(this.token.text)
17756 return this.renderer.html(html);
17758 case 'paragraph': {
17759 return this.renderer.paragraph(this.inline.output(this.token.text));
17762 return this.renderer.paragraph(this.parseText());
17771 function escape(html, encode) {
17773 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17774 .replace(/</g, '<')
17775 .replace(/>/g, '>')
17776 .replace(/"/g, '"')
17777 .replace(/'/g, ''');
17780 function unescape(html) {
17781 // explicitly match decimal, hex, and named HTML entities
17782 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17783 n = n.toLowerCase();
17784 if (n === 'colon') { return ':'; }
17785 if (n.charAt(0) === '#') {
17786 return n.charAt(1) === 'x'
17787 ? String.fromCharCode(parseInt(n.substring(2), 16))
17788 : String.fromCharCode(+n.substring(1));
17794 function replace(regex, opt) {
17795 regex = regex.source;
17797 return function self(name, val) {
17798 if (!name) { return new RegExp(regex, opt); }
17799 val = val.source || val;
17800 val = val.replace(/(^|[^\[])\^/g, '$1');
17801 regex = regex.replace(name, val);
17809 function merge(obj) {
17814 for (; i < arguments.length; i++) {
17815 target = arguments[i];
17816 for (key in target) {
17817 if (Object.prototype.hasOwnProperty.call(target, key)) {
17818 obj[key] = target[key];
17831 function marked(src, opt, callback) {
17832 if (callback || typeof opt === 'function') {
17838 opt = merge({}, marked.defaults, opt || {});
17840 var highlight = opt.highlight
17846 tokens = Lexer.lex(src, opt)
17848 return callback(e);
17851 pending = tokens.length;
17853 var done = function(err) {
17855 opt.highlight = highlight;
17856 return callback(err);
17862 out = Parser.parse(tokens, opt);
17867 opt.highlight = highlight;
17871 : callback(null, out);
17874 if (!highlight || highlight.length < 3) {
17878 delete opt.highlight;
17880 if (!pending) { return done(); }
17882 for (; i < tokens.length; i++) {
17884 if (token.type !== 'code') {
17885 return --pending || done();
17887 return highlight(token.text, token.lang, function(err, code) {
17888 if (err) { return done(err); }
17889 if (code == null || code === token.text) {
17890 return --pending || done();
17893 token.escaped = true;
17894 --pending || done();
17902 if (opt) { opt = merge({}, marked.defaults, opt); }
17903 return Parser.parse(Lexer.lex(src, opt), opt);
17905 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17906 if ((opt || marked.defaults).silent) {
17907 return '<p>An error occured:</p><pre>'
17908 + escape(e.message + '', true)
17920 marked.setOptions = function(opt) {
17921 merge(marked.defaults, opt);
17925 marked.defaults = {
17936 langPrefix: 'lang-',
17937 smartypants: false,
17939 renderer: new Renderer,
17947 marked.Parser = Parser;
17948 marked.parser = Parser.parse;
17950 marked.Renderer = Renderer;
17952 marked.Lexer = Lexer;
17953 marked.lexer = Lexer.lex;
17955 marked.InlineLexer = InlineLexer;
17956 marked.inlineLexer = InlineLexer.output;
17958 marked.parse = marked;
17960 Roo.Markdown.marked = marked;
17964 * Ext JS Library 1.1.1
17965 * Copyright(c) 2006-2007, Ext JS, LLC.
17967 * Originally Released Under LGPL - original licence link has changed is not relivant.
17970 * <script type="text/javascript">
17976 * These classes are derivatives of the similarly named classes in the YUI Library.
17977 * The original license:
17978 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17979 * Code licensed under the BSD License:
17980 * http://developer.yahoo.net/yui/license.txt
17985 var Event=Roo.EventManager;
17986 var Dom=Roo.lib.Dom;
17989 * @class Roo.dd.DragDrop
17990 * @extends Roo.util.Observable
17991 * Defines the interface and base operation of items that that can be
17992 * dragged or can be drop targets. It was designed to be extended, overriding
17993 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17994 * Up to three html elements can be associated with a DragDrop instance:
17996 * <li>linked element: the element that is passed into the constructor.
17997 * This is the element which defines the boundaries for interaction with
17998 * other DragDrop objects.</li>
17999 * <li>handle element(s): The drag operation only occurs if the element that
18000 * was clicked matches a handle element. By default this is the linked
18001 * element, but there are times that you will want only a portion of the
18002 * linked element to initiate the drag operation, and the setHandleElId()
18003 * method provides a way to define this.</li>
18004 * <li>drag element: this represents the element that would be moved along
18005 * with the cursor during a drag operation. By default, this is the linked
18006 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18007 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18010 * This class should not be instantiated until the onload event to ensure that
18011 * the associated elements are available.
18012 * The following would define a DragDrop obj that would interact with any
18013 * other DragDrop obj in the "group1" group:
18015 * dd = new Roo.dd.DragDrop("div1", "group1");
18017 * Since none of the event handlers have been implemented, nothing would
18018 * actually happen if you were to run the code above. Normally you would
18019 * override this class or one of the default implementations, but you can
18020 * also override the methods you want on an instance of the class...
18022 * dd.onDragDrop = function(e, id) {
18023 * alert("dd was dropped on " + id);
18027 * @param {String} id of the element that is linked to this instance
18028 * @param {String} sGroup the group of related DragDrop objects
18029 * @param {object} config an object containing configurable attributes
18030 * Valid properties for DragDrop:
18031 * padding, isTarget, maintainOffset, primaryButtonOnly
18033 Roo.dd.DragDrop = function(id, sGroup, config) {
18035 this.init(id, sGroup, config);
18040 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18043 * The id of the element associated with this object. This is what we
18044 * refer to as the "linked element" because the size and position of
18045 * this element is used to determine when the drag and drop objects have
18053 * Configuration attributes passed into the constructor
18060 * The id of the element that will be dragged. By default this is same
18061 * as the linked element , but could be changed to another element. Ex:
18063 * @property dragElId
18070 * the id of the element that initiates the drag operation. By default
18071 * this is the linked element, but could be changed to be a child of this
18072 * element. This lets us do things like only starting the drag when the
18073 * header element within the linked html element is clicked.
18074 * @property handleElId
18081 * An associative array of HTML tags that will be ignored if clicked.
18082 * @property invalidHandleTypes
18083 * @type {string: string}
18085 invalidHandleTypes: null,
18088 * An associative array of ids for elements that will be ignored if clicked
18089 * @property invalidHandleIds
18090 * @type {string: string}
18092 invalidHandleIds: null,
18095 * An indexted array of css class names for elements that will be ignored
18097 * @property invalidHandleClasses
18100 invalidHandleClasses: null,
18103 * The linked element's absolute X position at the time the drag was
18105 * @property startPageX
18112 * The linked element's absolute X position at the time the drag was
18114 * @property startPageY
18121 * The group defines a logical collection of DragDrop objects that are
18122 * related. Instances only get events when interacting with other
18123 * DragDrop object in the same group. This lets us define multiple
18124 * groups using a single DragDrop subclass if we want.
18126 * @type {string: string}
18131 * Individual drag/drop instances can be locked. This will prevent
18132 * onmousedown start drag.
18140 * Lock this instance
18143 lock: function() { this.locked = true; },
18146 * Unlock this instace
18149 unlock: function() { this.locked = false; },
18152 * By default, all insances can be a drop target. This can be disabled by
18153 * setting isTarget to false.
18160 * The padding configured for this drag and drop object for calculating
18161 * the drop zone intersection with this object.
18168 * Cached reference to the linked element
18169 * @property _domRef
18175 * Internal typeof flag
18176 * @property __ygDragDrop
18179 __ygDragDrop: true,
18182 * Set to true when horizontal contraints are applied
18183 * @property constrainX
18190 * Set to true when vertical contraints are applied
18191 * @property constrainY
18198 * The left constraint
18206 * The right constraint
18214 * The up constraint
18223 * The down constraint
18231 * Maintain offsets when we resetconstraints. Set to true when you want
18232 * the position of the element relative to its parent to stay the same
18233 * when the page changes
18235 * @property maintainOffset
18238 maintainOffset: false,
18241 * Array of pixel locations the element will snap to if we specified a
18242 * horizontal graduation/interval. This array is generated automatically
18243 * when you define a tick interval.
18250 * Array of pixel locations the element will snap to if we specified a
18251 * vertical graduation/interval. This array is generated automatically
18252 * when you define a tick interval.
18259 * By default the drag and drop instance will only respond to the primary
18260 * button click (left button for a right-handed mouse). Set to true to
18261 * allow drag and drop to start with any mouse click that is propogated
18263 * @property primaryButtonOnly
18266 primaryButtonOnly: true,
18269 * The availabe property is false until the linked dom element is accessible.
18270 * @property available
18276 * By default, drags can only be initiated if the mousedown occurs in the
18277 * region the linked element is. This is done in part to work around a
18278 * bug in some browsers that mis-report the mousedown if the previous
18279 * mouseup happened outside of the window. This property is set to true
18280 * if outer handles are defined.
18282 * @property hasOuterHandles
18286 hasOuterHandles: false,
18289 * Code that executes immediately before the startDrag event
18290 * @method b4StartDrag
18293 b4StartDrag: function(x, y) { },
18296 * Abstract method called after a drag/drop object is clicked
18297 * and the drag or mousedown time thresholds have beeen met.
18298 * @method startDrag
18299 * @param {int} X click location
18300 * @param {int} Y click location
18302 startDrag: function(x, y) { /* override this */ },
18305 * Code that executes immediately before the onDrag event
18309 b4Drag: function(e) { },
18312 * Abstract method called during the onMouseMove event while dragging an
18315 * @param {Event} e the mousemove event
18317 onDrag: function(e) { /* override this */ },
18320 * Abstract method called when this element fist begins hovering over
18321 * another DragDrop obj
18322 * @method onDragEnter
18323 * @param {Event} e the mousemove event
18324 * @param {String|DragDrop[]} id In POINT mode, the element
18325 * id this is hovering over. In INTERSECT mode, an array of one or more
18326 * dragdrop items being hovered over.
18328 onDragEnter: function(e, id) { /* override this */ },
18331 * Code that executes immediately before the onDragOver event
18332 * @method b4DragOver
18335 b4DragOver: function(e) { },
18338 * Abstract method called when this element is hovering over another
18340 * @method onDragOver
18341 * @param {Event} e the mousemove event
18342 * @param {String|DragDrop[]} id In POINT mode, the element
18343 * id this is hovering over. In INTERSECT mode, an array of dd items
18344 * being hovered over.
18346 onDragOver: function(e, id) { /* override this */ },
18349 * Code that executes immediately before the onDragOut event
18350 * @method b4DragOut
18353 b4DragOut: function(e) { },
18356 * Abstract method called when we are no longer hovering over an element
18357 * @method onDragOut
18358 * @param {Event} e the mousemove event
18359 * @param {String|DragDrop[]} id In POINT mode, the element
18360 * id this was hovering over. In INTERSECT mode, an array of dd items
18361 * that the mouse is no longer over.
18363 onDragOut: function(e, id) { /* override this */ },
18366 * Code that executes immediately before the onDragDrop event
18367 * @method b4DragDrop
18370 b4DragDrop: function(e) { },
18373 * Abstract method called when this item is dropped on another DragDrop
18375 * @method onDragDrop
18376 * @param {Event} e the mouseup event
18377 * @param {String|DragDrop[]} id In POINT mode, the element
18378 * id this was dropped on. In INTERSECT mode, an array of dd items this
18381 onDragDrop: function(e, id) { /* override this */ },
18384 * Abstract method called when this item is dropped on an area with no
18386 * @method onInvalidDrop
18387 * @param {Event} e the mouseup event
18389 onInvalidDrop: function(e) { /* override this */ },
18392 * Code that executes immediately before the endDrag event
18393 * @method b4EndDrag
18396 b4EndDrag: function(e) { },
18399 * Fired when we are done dragging the object
18401 * @param {Event} e the mouseup event
18403 endDrag: function(e) { /* override this */ },
18406 * Code executed immediately before the onMouseDown event
18407 * @method b4MouseDown
18408 * @param {Event} e the mousedown event
18411 b4MouseDown: function(e) { },
18414 * Event handler that fires when a drag/drop obj gets a mousedown
18415 * @method onMouseDown
18416 * @param {Event} e the mousedown event
18418 onMouseDown: function(e) { /* override this */ },
18421 * Event handler that fires when a drag/drop obj gets a mouseup
18422 * @method onMouseUp
18423 * @param {Event} e the mouseup event
18425 onMouseUp: function(e) { /* override this */ },
18428 * Override the onAvailable method to do what is needed after the initial
18429 * position was determined.
18430 * @method onAvailable
18432 onAvailable: function () {
18436 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18439 defaultPadding : {left:0, right:0, top:0, bottom:0},
18442 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18446 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18447 { dragElId: "existingProxyDiv" });
18448 dd.startDrag = function(){
18449 this.constrainTo("parent-id");
18452 * Or you can initalize it using the {@link Roo.Element} object:
18454 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18455 startDrag : function(){
18456 this.constrainTo("parent-id");
18460 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18461 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18462 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18463 * an object containing the sides to pad. For example: {right:10, bottom:10}
18464 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18466 constrainTo : function(constrainTo, pad, inContent){
18467 if(typeof pad == "number"){
18468 pad = {left: pad, right:pad, top:pad, bottom:pad};
18470 pad = pad || this.defaultPadding;
18471 var b = Roo.get(this.getEl()).getBox();
18472 var ce = Roo.get(constrainTo);
18473 var s = ce.getScroll();
18474 var c, cd = ce.dom;
18475 if(cd == document.body){
18476 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18479 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18483 var topSpace = b.y - c.y;
18484 var leftSpace = b.x - c.x;
18486 this.resetConstraints();
18487 this.setXConstraint(leftSpace - (pad.left||0), // left
18488 c.width - leftSpace - b.width - (pad.right||0) //right
18490 this.setYConstraint(topSpace - (pad.top||0), //top
18491 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18496 * Returns a reference to the linked element
18498 * @return {HTMLElement} the html element
18500 getEl: function() {
18501 if (!this._domRef) {
18502 this._domRef = Roo.getDom(this.id);
18505 return this._domRef;
18509 * Returns a reference to the actual element to drag. By default this is
18510 * the same as the html element, but it can be assigned to another
18511 * element. An example of this can be found in Roo.dd.DDProxy
18512 * @method getDragEl
18513 * @return {HTMLElement} the html element
18515 getDragEl: function() {
18516 return Roo.getDom(this.dragElId);
18520 * Sets up the DragDrop object. Must be called in the constructor of any
18521 * Roo.dd.DragDrop subclass
18523 * @param id the id of the linked element
18524 * @param {String} sGroup the group of related items
18525 * @param {object} config configuration attributes
18527 init: function(id, sGroup, config) {
18528 this.initTarget(id, sGroup, config);
18529 if (!Roo.isTouch) {
18530 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18532 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18533 // Event.on(this.id, "selectstart", Event.preventDefault);
18537 * Initializes Targeting functionality only... the object does not
18538 * get a mousedown handler.
18539 * @method initTarget
18540 * @param id the id of the linked element
18541 * @param {String} sGroup the group of related items
18542 * @param {object} config configuration attributes
18544 initTarget: function(id, sGroup, config) {
18546 // configuration attributes
18547 this.config = config || {};
18549 // create a local reference to the drag and drop manager
18550 this.DDM = Roo.dd.DDM;
18551 // initialize the groups array
18554 // assume that we have an element reference instead of an id if the
18555 // parameter is not a string
18556 if (typeof id !== "string") {
18563 // add to an interaction group
18564 this.addToGroup((sGroup) ? sGroup : "default");
18566 // We don't want to register this as the handle with the manager
18567 // so we just set the id rather than calling the setter.
18568 this.handleElId = id;
18570 // the linked element is the element that gets dragged by default
18571 this.setDragElId(id);
18573 // by default, clicked anchors will not start drag operations.
18574 this.invalidHandleTypes = { A: "A" };
18575 this.invalidHandleIds = {};
18576 this.invalidHandleClasses = [];
18578 this.applyConfig();
18580 this.handleOnAvailable();
18584 * Applies the configuration parameters that were passed into the constructor.
18585 * This is supposed to happen at each level through the inheritance chain. So
18586 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18587 * DragDrop in order to get all of the parameters that are available in
18589 * @method applyConfig
18591 applyConfig: function() {
18593 // configurable properties:
18594 // padding, isTarget, maintainOffset, primaryButtonOnly
18595 this.padding = this.config.padding || [0, 0, 0, 0];
18596 this.isTarget = (this.config.isTarget !== false);
18597 this.maintainOffset = (this.config.maintainOffset);
18598 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18603 * Executed when the linked element is available
18604 * @method handleOnAvailable
18607 handleOnAvailable: function() {
18608 this.available = true;
18609 this.resetConstraints();
18610 this.onAvailable();
18614 * Configures the padding for the target zone in px. Effectively expands
18615 * (or reduces) the virtual object size for targeting calculations.
18616 * Supports css-style shorthand; if only one parameter is passed, all sides
18617 * will have that padding, and if only two are passed, the top and bottom
18618 * will have the first param, the left and right the second.
18619 * @method setPadding
18620 * @param {int} iTop Top pad
18621 * @param {int} iRight Right pad
18622 * @param {int} iBot Bot pad
18623 * @param {int} iLeft Left pad
18625 setPadding: function(iTop, iRight, iBot, iLeft) {
18626 // this.padding = [iLeft, iRight, iTop, iBot];
18627 if (!iRight && 0 !== iRight) {
18628 this.padding = [iTop, iTop, iTop, iTop];
18629 } else if (!iBot && 0 !== iBot) {
18630 this.padding = [iTop, iRight, iTop, iRight];
18632 this.padding = [iTop, iRight, iBot, iLeft];
18637 * Stores the initial placement of the linked element.
18638 * @method setInitialPosition
18639 * @param {int} diffX the X offset, default 0
18640 * @param {int} diffY the Y offset, default 0
18642 setInitPosition: function(diffX, diffY) {
18643 var el = this.getEl();
18645 if (!this.DDM.verifyEl(el)) {
18649 var dx = diffX || 0;
18650 var dy = diffY || 0;
18652 var p = Dom.getXY( el );
18654 this.initPageX = p[0] - dx;
18655 this.initPageY = p[1] - dy;
18657 this.lastPageX = p[0];
18658 this.lastPageY = p[1];
18661 this.setStartPosition(p);
18665 * Sets the start position of the element. This is set when the obj
18666 * is initialized, the reset when a drag is started.
18667 * @method setStartPosition
18668 * @param pos current position (from previous lookup)
18671 setStartPosition: function(pos) {
18672 var p = pos || Dom.getXY( this.getEl() );
18673 this.deltaSetXY = null;
18675 this.startPageX = p[0];
18676 this.startPageY = p[1];
18680 * Add this instance to a group of related drag/drop objects. All
18681 * instances belong to at least one group, and can belong to as many
18682 * groups as needed.
18683 * @method addToGroup
18684 * @param sGroup {string} the name of the group
18686 addToGroup: function(sGroup) {
18687 this.groups[sGroup] = true;
18688 this.DDM.regDragDrop(this, sGroup);
18692 * Remove's this instance from the supplied interaction group
18693 * @method removeFromGroup
18694 * @param {string} sGroup The group to drop
18696 removeFromGroup: function(sGroup) {
18697 if (this.groups[sGroup]) {
18698 delete this.groups[sGroup];
18701 this.DDM.removeDDFromGroup(this, sGroup);
18705 * Allows you to specify that an element other than the linked element
18706 * will be moved with the cursor during a drag
18707 * @method setDragElId
18708 * @param id {string} the id of the element that will be used to initiate the drag
18710 setDragElId: function(id) {
18711 this.dragElId = id;
18715 * Allows you to specify a child of the linked element that should be
18716 * used to initiate the drag operation. An example of this would be if
18717 * you have a content div with text and links. Clicking anywhere in the
18718 * content area would normally start the drag operation. Use this method
18719 * to specify that an element inside of the content div is the element
18720 * that starts the drag operation.
18721 * @method setHandleElId
18722 * @param id {string} the id of the element that will be used to
18723 * initiate the drag.
18725 setHandleElId: function(id) {
18726 if (typeof id !== "string") {
18729 this.handleElId = id;
18730 this.DDM.regHandle(this.id, id);
18734 * Allows you to set an element outside of the linked element as a drag
18736 * @method setOuterHandleElId
18737 * @param id the id of the element that will be used to initiate the drag
18739 setOuterHandleElId: function(id) {
18740 if (typeof id !== "string") {
18743 Event.on(id, "mousedown",
18744 this.handleMouseDown, this);
18745 this.setHandleElId(id);
18747 this.hasOuterHandles = true;
18751 * Remove all drag and drop hooks for this element
18754 unreg: function() {
18755 Event.un(this.id, "mousedown",
18756 this.handleMouseDown);
18757 Event.un(this.id, "touchstart",
18758 this.handleMouseDown);
18759 this._domRef = null;
18760 this.DDM._remove(this);
18763 destroy : function(){
18768 * Returns true if this instance is locked, or the drag drop mgr is locked
18769 * (meaning that all drag/drop is disabled on the page.)
18771 * @return {boolean} true if this obj or all drag/drop is locked, else
18774 isLocked: function() {
18775 return (this.DDM.isLocked() || this.locked);
18779 * Fired when this object is clicked
18780 * @method handleMouseDown
18782 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18785 handleMouseDown: function(e, oDD){
18787 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18788 //Roo.log('not touch/ button !=0');
18791 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18792 return; // double touch..
18796 if (this.isLocked()) {
18797 //Roo.log('locked');
18801 this.DDM.refreshCache(this.groups);
18802 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18803 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18804 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18805 //Roo.log('no outer handes or not over target');
18808 // Roo.log('check validator');
18809 if (this.clickValidator(e)) {
18810 // Roo.log('validate success');
18811 // set the initial element position
18812 this.setStartPosition();
18815 this.b4MouseDown(e);
18816 this.onMouseDown(e);
18818 this.DDM.handleMouseDown(e, this);
18820 this.DDM.stopEvent(e);
18828 clickValidator: function(e) {
18829 var target = e.getTarget();
18830 return ( this.isValidHandleChild(target) &&
18831 (this.id == this.handleElId ||
18832 this.DDM.handleWasClicked(target, this.id)) );
18836 * Allows you to specify a tag name that should not start a drag operation
18837 * when clicked. This is designed to facilitate embedding links within a
18838 * drag handle that do something other than start the drag.
18839 * @method addInvalidHandleType
18840 * @param {string} tagName the type of element to exclude
18842 addInvalidHandleType: function(tagName) {
18843 var type = tagName.toUpperCase();
18844 this.invalidHandleTypes[type] = type;
18848 * Lets you to specify an element id for a child of a drag handle
18849 * that should not initiate a drag
18850 * @method addInvalidHandleId
18851 * @param {string} id the element id of the element you wish to ignore
18853 addInvalidHandleId: function(id) {
18854 if (typeof id !== "string") {
18857 this.invalidHandleIds[id] = id;
18861 * Lets you specify a css class of elements that will not initiate a drag
18862 * @method addInvalidHandleClass
18863 * @param {string} cssClass the class of the elements you wish to ignore
18865 addInvalidHandleClass: function(cssClass) {
18866 this.invalidHandleClasses.push(cssClass);
18870 * Unsets an excluded tag name set by addInvalidHandleType
18871 * @method removeInvalidHandleType
18872 * @param {string} tagName the type of element to unexclude
18874 removeInvalidHandleType: function(tagName) {
18875 var type = tagName.toUpperCase();
18876 // this.invalidHandleTypes[type] = null;
18877 delete this.invalidHandleTypes[type];
18881 * Unsets an invalid handle id
18882 * @method removeInvalidHandleId
18883 * @param {string} id the id of the element to re-enable
18885 removeInvalidHandleId: function(id) {
18886 if (typeof id !== "string") {
18889 delete this.invalidHandleIds[id];
18893 * Unsets an invalid css class
18894 * @method removeInvalidHandleClass
18895 * @param {string} cssClass the class of the element(s) you wish to
18898 removeInvalidHandleClass: function(cssClass) {
18899 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18900 if (this.invalidHandleClasses[i] == cssClass) {
18901 delete this.invalidHandleClasses[i];
18907 * Checks the tag exclusion list to see if this click should be ignored
18908 * @method isValidHandleChild
18909 * @param {HTMLElement} node the HTMLElement to evaluate
18910 * @return {boolean} true if this is a valid tag type, false if not
18912 isValidHandleChild: function(node) {
18915 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18918 nodeName = node.nodeName.toUpperCase();
18920 nodeName = node.nodeName;
18922 valid = valid && !this.invalidHandleTypes[nodeName];
18923 valid = valid && !this.invalidHandleIds[node.id];
18925 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18926 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18935 * Create the array of horizontal tick marks if an interval was specified
18936 * in setXConstraint().
18937 * @method setXTicks
18940 setXTicks: function(iStartX, iTickSize) {
18942 this.xTickSize = iTickSize;
18946 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18948 this.xTicks[this.xTicks.length] = i;
18953 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18955 this.xTicks[this.xTicks.length] = i;
18960 this.xTicks.sort(this.DDM.numericSort) ;
18964 * Create the array of vertical tick marks if an interval was specified in
18965 * setYConstraint().
18966 * @method setYTicks
18969 setYTicks: function(iStartY, iTickSize) {
18971 this.yTickSize = iTickSize;
18975 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18977 this.yTicks[this.yTicks.length] = i;
18982 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18984 this.yTicks[this.yTicks.length] = i;
18989 this.yTicks.sort(this.DDM.numericSort) ;
18993 * By default, the element can be dragged any place on the screen. Use
18994 * this method to limit the horizontal travel of the element. Pass in
18995 * 0,0 for the parameters if you want to lock the drag to the y axis.
18996 * @method setXConstraint
18997 * @param {int} iLeft the number of pixels the element can move to the left
18998 * @param {int} iRight the number of pixels the element can move to the
19000 * @param {int} iTickSize optional parameter for specifying that the
19002 * should move iTickSize pixels at a time.
19004 setXConstraint: function(iLeft, iRight, iTickSize) {
19005 this.leftConstraint = iLeft;
19006 this.rightConstraint = iRight;
19008 this.minX = this.initPageX - iLeft;
19009 this.maxX = this.initPageX + iRight;
19010 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19012 this.constrainX = true;
19016 * Clears any constraints applied to this instance. Also clears ticks
19017 * since they can't exist independent of a constraint at this time.
19018 * @method clearConstraints
19020 clearConstraints: function() {
19021 this.constrainX = false;
19022 this.constrainY = false;
19027 * Clears any tick interval defined for this instance
19028 * @method clearTicks
19030 clearTicks: function() {
19031 this.xTicks = null;
19032 this.yTicks = null;
19033 this.xTickSize = 0;
19034 this.yTickSize = 0;
19038 * By default, the element can be dragged any place on the screen. Set
19039 * this to limit the vertical travel of the element. Pass in 0,0 for the
19040 * parameters if you want to lock the drag to the x axis.
19041 * @method setYConstraint
19042 * @param {int} iUp the number of pixels the element can move up
19043 * @param {int} iDown the number of pixels the element can move down
19044 * @param {int} iTickSize optional parameter for specifying that the
19045 * element should move iTickSize pixels at a time.
19047 setYConstraint: function(iUp, iDown, iTickSize) {
19048 this.topConstraint = iUp;
19049 this.bottomConstraint = iDown;
19051 this.minY = this.initPageY - iUp;
19052 this.maxY = this.initPageY + iDown;
19053 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19055 this.constrainY = true;
19060 * resetConstraints must be called if you manually reposition a dd element.
19061 * @method resetConstraints
19062 * @param {boolean} maintainOffset
19064 resetConstraints: function() {
19067 // Maintain offsets if necessary
19068 if (this.initPageX || this.initPageX === 0) {
19069 // figure out how much this thing has moved
19070 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19071 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19073 this.setInitPosition(dx, dy);
19075 // This is the first time we have detected the element's position
19077 this.setInitPosition();
19080 if (this.constrainX) {
19081 this.setXConstraint( this.leftConstraint,
19082 this.rightConstraint,
19086 if (this.constrainY) {
19087 this.setYConstraint( this.topConstraint,
19088 this.bottomConstraint,
19094 * Normally the drag element is moved pixel by pixel, but we can specify
19095 * that it move a number of pixels at a time. This method resolves the
19096 * location when we have it set up like this.
19098 * @param {int} val where we want to place the object
19099 * @param {int[]} tickArray sorted array of valid points
19100 * @return {int} the closest tick
19103 getTick: function(val, tickArray) {
19106 // If tick interval is not defined, it is effectively 1 pixel,
19107 // so we return the value passed to us.
19109 } else if (tickArray[0] >= val) {
19110 // The value is lower than the first tick, so we return the first
19112 return tickArray[0];
19114 for (var i=0, len=tickArray.length; i<len; ++i) {
19116 if (tickArray[next] && tickArray[next] >= val) {
19117 var diff1 = val - tickArray[i];
19118 var diff2 = tickArray[next] - val;
19119 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19123 // The value is larger than the last tick, so we return the last
19125 return tickArray[tickArray.length - 1];
19132 * @return {string} string representation of the dd obj
19134 toString: function() {
19135 return ("DragDrop " + this.id);
19143 * Ext JS Library 1.1.1
19144 * Copyright(c) 2006-2007, Ext JS, LLC.
19146 * Originally Released Under LGPL - original licence link has changed is not relivant.
19149 * <script type="text/javascript">
19154 * The drag and drop utility provides a framework for building drag and drop
19155 * applications. In addition to enabling drag and drop for specific elements,
19156 * the drag and drop elements are tracked by the manager class, and the
19157 * interactions between the various elements are tracked during the drag and
19158 * the implementing code is notified about these important moments.
19161 // Only load the library once. Rewriting the manager class would orphan
19162 // existing drag and drop instances.
19163 if (!Roo.dd.DragDropMgr) {
19166 * @class Roo.dd.DragDropMgr
19167 * DragDropMgr is a singleton that tracks the element interaction for
19168 * all DragDrop items in the window. Generally, you will not call
19169 * this class directly, but it does have helper methods that could
19170 * be useful in your DragDrop implementations.
19173 Roo.dd.DragDropMgr = function() {
19175 var Event = Roo.EventManager;
19180 * Two dimensional Array of registered DragDrop objects. The first
19181 * dimension is the DragDrop item group, the second the DragDrop
19184 * @type {string: string}
19191 * Array of element ids defined as drag handles. Used to determine
19192 * if the element that generated the mousedown event is actually the
19193 * handle and not the html element itself.
19194 * @property handleIds
19195 * @type {string: string}
19202 * the DragDrop object that is currently being dragged
19203 * @property dragCurrent
19211 * the DragDrop object(s) that are being hovered over
19212 * @property dragOvers
19220 * the X distance between the cursor and the object being dragged
19229 * the Y distance between the cursor and the object being dragged
19238 * Flag to determine if we should prevent the default behavior of the
19239 * events we define. By default this is true, but this can be set to
19240 * false if you need the default behavior (not recommended)
19241 * @property preventDefault
19245 preventDefault: true,
19248 * Flag to determine if we should stop the propagation of the events
19249 * we generate. This is true by default but you may want to set it to
19250 * false if the html element contains other features that require the
19252 * @property stopPropagation
19256 stopPropagation: true,
19259 * Internal flag that is set to true when drag and drop has been
19261 * @property initialized
19268 * All drag and drop can be disabled.
19276 * Called the first time an element is registered.
19282 this.initialized = true;
19286 * In point mode, drag and drop interaction is defined by the
19287 * location of the cursor during the drag/drop
19295 * In intersect mode, drag and drop interactio nis defined by the
19296 * overlap of two or more drag and drop objects.
19297 * @property INTERSECT
19304 * The current drag and drop mode. Default: POINT
19312 * Runs method on all drag and drop objects
19313 * @method _execOnAll
19317 _execOnAll: function(sMethod, args) {
19318 for (var i in this.ids) {
19319 for (var j in this.ids[i]) {
19320 var oDD = this.ids[i][j];
19321 if (! this.isTypeOfDD(oDD)) {
19324 oDD[sMethod].apply(oDD, args);
19330 * Drag and drop initialization. Sets up the global event handlers
19335 _onLoad: function() {
19339 if (!Roo.isTouch) {
19340 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19341 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19343 Event.on(document, "touchend", this.handleMouseUp, this, true);
19344 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19346 Event.on(window, "unload", this._onUnload, this, true);
19347 Event.on(window, "resize", this._onResize, this, true);
19348 // Event.on(window, "mouseout", this._test);
19353 * Reset constraints on all drag and drop objs
19354 * @method _onResize
19358 _onResize: function(e) {
19359 this._execOnAll("resetConstraints", []);
19363 * Lock all drag and drop functionality
19367 lock: function() { this.locked = true; },
19370 * Unlock all drag and drop functionality
19374 unlock: function() { this.locked = false; },
19377 * Is drag and drop locked?
19379 * @return {boolean} True if drag and drop is locked, false otherwise.
19382 isLocked: function() { return this.locked; },
19385 * Location cache that is set for all drag drop objects when a drag is
19386 * initiated, cleared when the drag is finished.
19387 * @property locationCache
19394 * Set useCache to false if you want to force object the lookup of each
19395 * drag and drop linked element constantly during a drag.
19396 * @property useCache
19403 * The number of pixels that the mouse needs to move after the
19404 * mousedown before the drag is initiated. Default=3;
19405 * @property clickPixelThresh
19409 clickPixelThresh: 3,
19412 * The number of milliseconds after the mousedown event to initiate the
19413 * drag if we don't get a mouseup event. Default=1000
19414 * @property clickTimeThresh
19418 clickTimeThresh: 350,
19421 * Flag that indicates that either the drag pixel threshold or the
19422 * mousdown time threshold has been met
19423 * @property dragThreshMet
19428 dragThreshMet: false,
19431 * Timeout used for the click time threshold
19432 * @property clickTimeout
19437 clickTimeout: null,
19440 * The X position of the mousedown event stored for later use when a
19441 * drag threshold is met.
19450 * The Y position of the mousedown event stored for later use when a
19451 * drag threshold is met.
19460 * Each DragDrop instance must be registered with the DragDropMgr.
19461 * This is executed in DragDrop.init()
19462 * @method regDragDrop
19463 * @param {DragDrop} oDD the DragDrop object to register
19464 * @param {String} sGroup the name of the group this element belongs to
19467 regDragDrop: function(oDD, sGroup) {
19468 if (!this.initialized) { this.init(); }
19470 if (!this.ids[sGroup]) {
19471 this.ids[sGroup] = {};
19473 this.ids[sGroup][oDD.id] = oDD;
19477 * Removes the supplied dd instance from the supplied group. Executed
19478 * by DragDrop.removeFromGroup, so don't call this function directly.
19479 * @method removeDDFromGroup
19483 removeDDFromGroup: function(oDD, sGroup) {
19484 if (!this.ids[sGroup]) {
19485 this.ids[sGroup] = {};
19488 var obj = this.ids[sGroup];
19489 if (obj && obj[oDD.id]) {
19490 delete obj[oDD.id];
19495 * Unregisters a drag and drop item. This is executed in
19496 * DragDrop.unreg, use that method instead of calling this directly.
19501 _remove: function(oDD) {
19502 for (var g in oDD.groups) {
19503 if (g && this.ids[g][oDD.id]) {
19504 delete this.ids[g][oDD.id];
19507 delete this.handleIds[oDD.id];
19511 * Each DragDrop handle element must be registered. This is done
19512 * automatically when executing DragDrop.setHandleElId()
19513 * @method regHandle
19514 * @param {String} sDDId the DragDrop id this element is a handle for
19515 * @param {String} sHandleId the id of the element that is the drag
19519 regHandle: function(sDDId, sHandleId) {
19520 if (!this.handleIds[sDDId]) {
19521 this.handleIds[sDDId] = {};
19523 this.handleIds[sDDId][sHandleId] = sHandleId;
19527 * Utility function to determine if a given element has been
19528 * registered as a drag drop item.
19529 * @method isDragDrop
19530 * @param {String} id the element id to check
19531 * @return {boolean} true if this element is a DragDrop item,
19535 isDragDrop: function(id) {
19536 return ( this.getDDById(id) ) ? true : false;
19540 * Returns the drag and drop instances that are in all groups the
19541 * passed in instance belongs to.
19542 * @method getRelated
19543 * @param {DragDrop} p_oDD the obj to get related data for
19544 * @param {boolean} bTargetsOnly if true, only return targetable objs
19545 * @return {DragDrop[]} the related instances
19548 getRelated: function(p_oDD, bTargetsOnly) {
19550 for (var i in p_oDD.groups) {
19551 for (j in this.ids[i]) {
19552 var dd = this.ids[i][j];
19553 if (! this.isTypeOfDD(dd)) {
19556 if (!bTargetsOnly || dd.isTarget) {
19557 oDDs[oDDs.length] = dd;
19566 * Returns true if the specified dd target is a legal target for
19567 * the specifice drag obj
19568 * @method isLegalTarget
19569 * @param {DragDrop} the drag obj
19570 * @param {DragDrop} the target
19571 * @return {boolean} true if the target is a legal target for the
19575 isLegalTarget: function (oDD, oTargetDD) {
19576 var targets = this.getRelated(oDD, true);
19577 for (var i=0, len=targets.length;i<len;++i) {
19578 if (targets[i].id == oTargetDD.id) {
19587 * My goal is to be able to transparently determine if an object is
19588 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19589 * returns "object", oDD.constructor.toString() always returns
19590 * "DragDrop" and not the name of the subclass. So for now it just
19591 * evaluates a well-known variable in DragDrop.
19592 * @method isTypeOfDD
19593 * @param {Object} the object to evaluate
19594 * @return {boolean} true if typeof oDD = DragDrop
19597 isTypeOfDD: function (oDD) {
19598 return (oDD && oDD.__ygDragDrop);
19602 * Utility function to determine if a given element has been
19603 * registered as a drag drop handle for the given Drag Drop object.
19605 * @param {String} id the element id to check
19606 * @return {boolean} true if this element is a DragDrop handle, false
19610 isHandle: function(sDDId, sHandleId) {
19611 return ( this.handleIds[sDDId] &&
19612 this.handleIds[sDDId][sHandleId] );
19616 * Returns the DragDrop instance for a given id
19617 * @method getDDById
19618 * @param {String} id the id of the DragDrop object
19619 * @return {DragDrop} the drag drop object, null if it is not found
19622 getDDById: function(id) {
19623 for (var i in this.ids) {
19624 if (this.ids[i][id]) {
19625 return this.ids[i][id];
19632 * Fired after a registered DragDrop object gets the mousedown event.
19633 * Sets up the events required to track the object being dragged
19634 * @method handleMouseDown
19635 * @param {Event} e the event
19636 * @param oDD the DragDrop object being dragged
19640 handleMouseDown: function(e, oDD) {
19642 Roo.QuickTips.disable();
19644 this.currentTarget = e.getTarget();
19646 this.dragCurrent = oDD;
19648 var el = oDD.getEl();
19650 // track start position
19651 this.startX = e.getPageX();
19652 this.startY = e.getPageY();
19654 this.deltaX = this.startX - el.offsetLeft;
19655 this.deltaY = this.startY - el.offsetTop;
19657 this.dragThreshMet = false;
19659 this.clickTimeout = setTimeout(
19661 var DDM = Roo.dd.DDM;
19662 DDM.startDrag(DDM.startX, DDM.startY);
19664 this.clickTimeThresh );
19668 * Fired when either the drag pixel threshol or the mousedown hold
19669 * time threshold has been met.
19670 * @method startDrag
19671 * @param x {int} the X position of the original mousedown
19672 * @param y {int} the Y position of the original mousedown
19675 startDrag: function(x, y) {
19676 clearTimeout(this.clickTimeout);
19677 if (this.dragCurrent) {
19678 this.dragCurrent.b4StartDrag(x, y);
19679 this.dragCurrent.startDrag(x, y);
19681 this.dragThreshMet = true;
19685 * Internal function to handle the mouseup event. Will be invoked
19686 * from the context of the document.
19687 * @method handleMouseUp
19688 * @param {Event} e the event
19692 handleMouseUp: function(e) {
19695 Roo.QuickTips.enable();
19697 if (! this.dragCurrent) {
19701 clearTimeout(this.clickTimeout);
19703 if (this.dragThreshMet) {
19704 this.fireEvents(e, true);
19714 * Utility to stop event propagation and event default, if these
19715 * features are turned on.
19716 * @method stopEvent
19717 * @param {Event} e the event as returned by this.getEvent()
19720 stopEvent: function(e){
19721 if(this.stopPropagation) {
19722 e.stopPropagation();
19725 if (this.preventDefault) {
19726 e.preventDefault();
19731 * Internal function to clean up event handlers after the drag
19732 * operation is complete
19734 * @param {Event} e the event
19738 stopDrag: function(e) {
19739 // Fire the drag end event for the item that was dragged
19740 if (this.dragCurrent) {
19741 if (this.dragThreshMet) {
19742 this.dragCurrent.b4EndDrag(e);
19743 this.dragCurrent.endDrag(e);
19746 this.dragCurrent.onMouseUp(e);
19749 this.dragCurrent = null;
19750 this.dragOvers = {};
19754 * Internal function to handle the mousemove event. Will be invoked
19755 * from the context of the html element.
19757 * @TODO figure out what we can do about mouse events lost when the
19758 * user drags objects beyond the window boundary. Currently we can
19759 * detect this in internet explorer by verifying that the mouse is
19760 * down during the mousemove event. Firefox doesn't give us the
19761 * button state on the mousemove event.
19762 * @method handleMouseMove
19763 * @param {Event} e the event
19767 handleMouseMove: function(e) {
19768 if (! this.dragCurrent) {
19772 // var button = e.which || e.button;
19774 // check for IE mouseup outside of page boundary
19775 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19777 return this.handleMouseUp(e);
19780 if (!this.dragThreshMet) {
19781 var diffX = Math.abs(this.startX - e.getPageX());
19782 var diffY = Math.abs(this.startY - e.getPageY());
19783 if (diffX > this.clickPixelThresh ||
19784 diffY > this.clickPixelThresh) {
19785 this.startDrag(this.startX, this.startY);
19789 if (this.dragThreshMet) {
19790 this.dragCurrent.b4Drag(e);
19791 this.dragCurrent.onDrag(e);
19792 if(!this.dragCurrent.moveOnly){
19793 this.fireEvents(e, false);
19803 * Iterates over all of the DragDrop elements to find ones we are
19804 * hovering over or dropping on
19805 * @method fireEvents
19806 * @param {Event} e the event
19807 * @param {boolean} isDrop is this a drop op or a mouseover op?
19811 fireEvents: function(e, isDrop) {
19812 var dc = this.dragCurrent;
19814 // If the user did the mouse up outside of the window, we could
19815 // get here even though we have ended the drag.
19816 if (!dc || dc.isLocked()) {
19820 var pt = e.getPoint();
19822 // cache the previous dragOver array
19828 var enterEvts = [];
19830 // Check to see if the object(s) we were hovering over is no longer
19831 // being hovered over so we can fire the onDragOut event
19832 for (var i in this.dragOvers) {
19834 var ddo = this.dragOvers[i];
19836 if (! this.isTypeOfDD(ddo)) {
19840 if (! this.isOverTarget(pt, ddo, this.mode)) {
19841 outEvts.push( ddo );
19844 oldOvers[i] = true;
19845 delete this.dragOvers[i];
19848 for (var sGroup in dc.groups) {
19850 if ("string" != typeof sGroup) {
19854 for (i in this.ids[sGroup]) {
19855 var oDD = this.ids[sGroup][i];
19856 if (! this.isTypeOfDD(oDD)) {
19860 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19861 if (this.isOverTarget(pt, oDD, this.mode)) {
19862 // look for drop interactions
19864 dropEvts.push( oDD );
19865 // look for drag enter and drag over interactions
19868 // initial drag over: dragEnter fires
19869 if (!oldOvers[oDD.id]) {
19870 enterEvts.push( oDD );
19871 // subsequent drag overs: dragOver fires
19873 overEvts.push( oDD );
19876 this.dragOvers[oDD.id] = oDD;
19884 if (outEvts.length) {
19885 dc.b4DragOut(e, outEvts);
19886 dc.onDragOut(e, outEvts);
19889 if (enterEvts.length) {
19890 dc.onDragEnter(e, enterEvts);
19893 if (overEvts.length) {
19894 dc.b4DragOver(e, overEvts);
19895 dc.onDragOver(e, overEvts);
19898 if (dropEvts.length) {
19899 dc.b4DragDrop(e, dropEvts);
19900 dc.onDragDrop(e, dropEvts);
19904 // fire dragout events
19906 for (i=0, len=outEvts.length; i<len; ++i) {
19907 dc.b4DragOut(e, outEvts[i].id);
19908 dc.onDragOut(e, outEvts[i].id);
19911 // fire enter events
19912 for (i=0,len=enterEvts.length; i<len; ++i) {
19913 // dc.b4DragEnter(e, oDD.id);
19914 dc.onDragEnter(e, enterEvts[i].id);
19917 // fire over events
19918 for (i=0,len=overEvts.length; i<len; ++i) {
19919 dc.b4DragOver(e, overEvts[i].id);
19920 dc.onDragOver(e, overEvts[i].id);
19923 // fire drop events
19924 for (i=0, len=dropEvts.length; i<len; ++i) {
19925 dc.b4DragDrop(e, dropEvts[i].id);
19926 dc.onDragDrop(e, dropEvts[i].id);
19931 // notify about a drop that did not find a target
19932 if (isDrop && !dropEvts.length) {
19933 dc.onInvalidDrop(e);
19939 * Helper function for getting the best match from the list of drag
19940 * and drop objects returned by the drag and drop events when we are
19941 * in INTERSECT mode. It returns either the first object that the
19942 * cursor is over, or the object that has the greatest overlap with
19943 * the dragged element.
19944 * @method getBestMatch
19945 * @param {DragDrop[]} dds The array of drag and drop objects
19947 * @return {DragDrop} The best single match
19950 getBestMatch: function(dds) {
19952 // Return null if the input is not what we expect
19953 //if (!dds || !dds.length || dds.length == 0) {
19955 // If there is only one item, it wins
19956 //} else if (dds.length == 1) {
19958 var len = dds.length;
19963 // Loop through the targeted items
19964 for (var i=0; i<len; ++i) {
19966 // If the cursor is over the object, it wins. If the
19967 // cursor is over multiple matches, the first one we come
19969 if (dd.cursorIsOver) {
19972 // Otherwise the object with the most overlap wins
19975 winner.overlap.getArea() < dd.overlap.getArea()) {
19986 * Refreshes the cache of the top-left and bottom-right points of the
19987 * drag and drop objects in the specified group(s). This is in the
19988 * format that is stored in the drag and drop instance, so typical
19991 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19995 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19997 * @TODO this really should be an indexed array. Alternatively this
19998 * method could accept both.
19999 * @method refreshCache
20000 * @param {Object} groups an associative array of groups to refresh
20003 refreshCache: function(groups) {
20004 for (var sGroup in groups) {
20005 if ("string" != typeof sGroup) {
20008 for (var i in this.ids[sGroup]) {
20009 var oDD = this.ids[sGroup][i];
20011 if (this.isTypeOfDD(oDD)) {
20012 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20013 var loc = this.getLocation(oDD);
20015 this.locationCache[oDD.id] = loc;
20017 delete this.locationCache[oDD.id];
20018 // this will unregister the drag and drop object if
20019 // the element is not in a usable state
20028 * This checks to make sure an element exists and is in the DOM. The
20029 * main purpose is to handle cases where innerHTML is used to remove
20030 * drag and drop objects from the DOM. IE provides an 'unspecified
20031 * error' when trying to access the offsetParent of such an element
20033 * @param {HTMLElement} el the element to check
20034 * @return {boolean} true if the element looks usable
20037 verifyEl: function(el) {
20042 parent = el.offsetParent;
20045 parent = el.offsetParent;
20056 * Returns a Region object containing the drag and drop element's position
20057 * and size, including the padding configured for it
20058 * @method getLocation
20059 * @param {DragDrop} oDD the drag and drop object to get the
20061 * @return {Roo.lib.Region} a Region object representing the total area
20062 * the element occupies, including any padding
20063 * the instance is configured for.
20066 getLocation: function(oDD) {
20067 if (! this.isTypeOfDD(oDD)) {
20071 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20074 pos= Roo.lib.Dom.getXY(el);
20082 x2 = x1 + el.offsetWidth;
20084 y2 = y1 + el.offsetHeight;
20086 t = y1 - oDD.padding[0];
20087 r = x2 + oDD.padding[1];
20088 b = y2 + oDD.padding[2];
20089 l = x1 - oDD.padding[3];
20091 return new Roo.lib.Region( t, r, b, l );
20095 * Checks the cursor location to see if it over the target
20096 * @method isOverTarget
20097 * @param {Roo.lib.Point} pt The point to evaluate
20098 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20099 * @return {boolean} true if the mouse is over the target
20103 isOverTarget: function(pt, oTarget, intersect) {
20104 // use cache if available
20105 var loc = this.locationCache[oTarget.id];
20106 if (!loc || !this.useCache) {
20107 loc = this.getLocation(oTarget);
20108 this.locationCache[oTarget.id] = loc;
20116 oTarget.cursorIsOver = loc.contains( pt );
20118 // DragDrop is using this as a sanity check for the initial mousedown
20119 // in this case we are done. In POINT mode, if the drag obj has no
20120 // contraints, we are also done. Otherwise we need to evaluate the
20121 // location of the target as related to the actual location of the
20122 // dragged element.
20123 var dc = this.dragCurrent;
20124 if (!dc || !dc.getTargetCoord ||
20125 (!intersect && !dc.constrainX && !dc.constrainY)) {
20126 return oTarget.cursorIsOver;
20129 oTarget.overlap = null;
20131 // Get the current location of the drag element, this is the
20132 // location of the mouse event less the delta that represents
20133 // where the original mousedown happened on the element. We
20134 // need to consider constraints and ticks as well.
20135 var pos = dc.getTargetCoord(pt.x, pt.y);
20137 var el = dc.getDragEl();
20138 var curRegion = new Roo.lib.Region( pos.y,
20139 pos.x + el.offsetWidth,
20140 pos.y + el.offsetHeight,
20143 var overlap = curRegion.intersect(loc);
20146 oTarget.overlap = overlap;
20147 return (intersect) ? true : oTarget.cursorIsOver;
20154 * unload event handler
20155 * @method _onUnload
20159 _onUnload: function(e, me) {
20160 Roo.dd.DragDropMgr.unregAll();
20164 * Cleans up the drag and drop events and objects.
20169 unregAll: function() {
20171 if (this.dragCurrent) {
20173 this.dragCurrent = null;
20176 this._execOnAll("unreg", []);
20178 for (i in this.elementCache) {
20179 delete this.elementCache[i];
20182 this.elementCache = {};
20187 * A cache of DOM elements
20188 * @property elementCache
20195 * Get the wrapper for the DOM element specified
20196 * @method getElWrapper
20197 * @param {String} id the id of the element to get
20198 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20200 * @deprecated This wrapper isn't that useful
20203 getElWrapper: function(id) {
20204 var oWrapper = this.elementCache[id];
20205 if (!oWrapper || !oWrapper.el) {
20206 oWrapper = this.elementCache[id] =
20207 new this.ElementWrapper(Roo.getDom(id));
20213 * Returns the actual DOM element
20214 * @method getElement
20215 * @param {String} id the id of the elment to get
20216 * @return {Object} The element
20217 * @deprecated use Roo.getDom instead
20220 getElement: function(id) {
20221 return Roo.getDom(id);
20225 * Returns the style property for the DOM element (i.e.,
20226 * document.getElById(id).style)
20228 * @param {String} id the id of the elment to get
20229 * @return {Object} The style property of the element
20230 * @deprecated use Roo.getDom instead
20233 getCss: function(id) {
20234 var el = Roo.getDom(id);
20235 return (el) ? el.style : null;
20239 * Inner class for cached elements
20240 * @class DragDropMgr.ElementWrapper
20245 ElementWrapper: function(el) {
20250 this.el = el || null;
20255 this.id = this.el && el.id;
20257 * A reference to the style property
20260 this.css = this.el && el.style;
20264 * Returns the X position of an html element
20266 * @param el the element for which to get the position
20267 * @return {int} the X coordinate
20269 * @deprecated use Roo.lib.Dom.getX instead
20272 getPosX: function(el) {
20273 return Roo.lib.Dom.getX(el);
20277 * Returns the Y position of an html element
20279 * @param el the element for which to get the position
20280 * @return {int} the Y coordinate
20281 * @deprecated use Roo.lib.Dom.getY instead
20284 getPosY: function(el) {
20285 return Roo.lib.Dom.getY(el);
20289 * Swap two nodes. In IE, we use the native method, for others we
20290 * emulate the IE behavior
20292 * @param n1 the first node to swap
20293 * @param n2 the other node to swap
20296 swapNode: function(n1, n2) {
20300 var p = n2.parentNode;
20301 var s = n2.nextSibling;
20304 p.insertBefore(n1, n2);
20305 } else if (n2 == n1.nextSibling) {
20306 p.insertBefore(n2, n1);
20308 n1.parentNode.replaceChild(n2, n1);
20309 p.insertBefore(n1, s);
20315 * Returns the current scroll position
20316 * @method getScroll
20320 getScroll: function () {
20321 var t, l, dde=document.documentElement, db=document.body;
20322 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20324 l = dde.scrollLeft;
20331 return { top: t, left: l };
20335 * Returns the specified element style property
20337 * @param {HTMLElement} el the element
20338 * @param {string} styleProp the style property
20339 * @return {string} The value of the style property
20340 * @deprecated use Roo.lib.Dom.getStyle
20343 getStyle: function(el, styleProp) {
20344 return Roo.fly(el).getStyle(styleProp);
20348 * Gets the scrollTop
20349 * @method getScrollTop
20350 * @return {int} the document's scrollTop
20353 getScrollTop: function () { return this.getScroll().top; },
20356 * Gets the scrollLeft
20357 * @method getScrollLeft
20358 * @return {int} the document's scrollTop
20361 getScrollLeft: function () { return this.getScroll().left; },
20364 * Sets the x/y position of an element to the location of the
20367 * @param {HTMLElement} moveEl The element to move
20368 * @param {HTMLElement} targetEl The position reference element
20371 moveToEl: function (moveEl, targetEl) {
20372 var aCoord = Roo.lib.Dom.getXY(targetEl);
20373 Roo.lib.Dom.setXY(moveEl, aCoord);
20377 * Numeric array sort function
20378 * @method numericSort
20381 numericSort: function(a, b) { return (a - b); },
20385 * @property _timeoutCount
20392 * Trying to make the load order less important. Without this we get
20393 * an error if this file is loaded before the Event Utility.
20394 * @method _addListeners
20398 _addListeners: function() {
20399 var DDM = Roo.dd.DDM;
20400 if ( Roo.lib.Event && document ) {
20403 if (DDM._timeoutCount > 2000) {
20405 setTimeout(DDM._addListeners, 10);
20406 if (document && document.body) {
20407 DDM._timeoutCount += 1;
20414 * Recursively searches the immediate parent and all child nodes for
20415 * the handle element in order to determine wheter or not it was
20417 * @method handleWasClicked
20418 * @param node the html element to inspect
20421 handleWasClicked: function(node, id) {
20422 if (this.isHandle(id, node.id)) {
20425 // check to see if this is a text node child of the one we want
20426 var p = node.parentNode;
20429 if (this.isHandle(id, p.id)) {
20444 // shorter alias, save a few bytes
20445 Roo.dd.DDM = Roo.dd.DragDropMgr;
20446 Roo.dd.DDM._addListeners();
20450 * Ext JS Library 1.1.1
20451 * Copyright(c) 2006-2007, Ext JS, LLC.
20453 * Originally Released Under LGPL - original licence link has changed is not relivant.
20456 * <script type="text/javascript">
20461 * A DragDrop implementation where the linked element follows the
20462 * mouse cursor during a drag.
20463 * @extends Roo.dd.DragDrop
20465 * @param {String} id the id of the linked element
20466 * @param {String} sGroup the group of related DragDrop items
20467 * @param {object} config an object containing configurable attributes
20468 * Valid properties for DD:
20471 Roo.dd.DD = function(id, sGroup, config) {
20473 this.init(id, sGroup, config);
20477 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20480 * When set to true, the utility automatically tries to scroll the browser
20481 * window wehn a drag and drop element is dragged near the viewport boundary.
20482 * Defaults to true.
20489 * Sets the pointer offset to the distance between the linked element's top
20490 * left corner and the location the element was clicked
20491 * @method autoOffset
20492 * @param {int} iPageX the X coordinate of the click
20493 * @param {int} iPageY the Y coordinate of the click
20495 autoOffset: function(iPageX, iPageY) {
20496 var x = iPageX - this.startPageX;
20497 var y = iPageY - this.startPageY;
20498 this.setDelta(x, y);
20502 * Sets the pointer offset. You can call this directly to force the
20503 * offset to be in a particular location (e.g., pass in 0,0 to set it
20504 * to the center of the object)
20506 * @param {int} iDeltaX the distance from the left
20507 * @param {int} iDeltaY the distance from the top
20509 setDelta: function(iDeltaX, iDeltaY) {
20510 this.deltaX = iDeltaX;
20511 this.deltaY = iDeltaY;
20515 * Sets the drag element to the location of the mousedown or click event,
20516 * maintaining the cursor location relative to the location on the element
20517 * that was clicked. Override this if you want to place the element in a
20518 * location other than where the cursor is.
20519 * @method setDragElPos
20520 * @param {int} iPageX the X coordinate of the mousedown or drag event
20521 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20523 setDragElPos: function(iPageX, iPageY) {
20524 // the first time we do this, we are going to check to make sure
20525 // the element has css positioning
20527 var el = this.getDragEl();
20528 this.alignElWithMouse(el, iPageX, iPageY);
20532 * Sets the element to the location of the mousedown or click event,
20533 * maintaining the cursor location relative to the location on the element
20534 * that was clicked. Override this if you want to place the element in a
20535 * location other than where the cursor is.
20536 * @method alignElWithMouse
20537 * @param {HTMLElement} el the element to move
20538 * @param {int} iPageX the X coordinate of the mousedown or drag event
20539 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20541 alignElWithMouse: function(el, iPageX, iPageY) {
20542 var oCoord = this.getTargetCoord(iPageX, iPageY);
20543 var fly = el.dom ? el : Roo.fly(el);
20544 if (!this.deltaSetXY) {
20545 var aCoord = [oCoord.x, oCoord.y];
20547 var newLeft = fly.getLeft(true);
20548 var newTop = fly.getTop(true);
20549 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20551 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20554 this.cachePosition(oCoord.x, oCoord.y);
20555 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20560 * Saves the most recent position so that we can reset the constraints and
20561 * tick marks on-demand. We need to know this so that we can calculate the
20562 * number of pixels the element is offset from its original position.
20563 * @method cachePosition
20564 * @param iPageX the current x position (optional, this just makes it so we
20565 * don't have to look it up again)
20566 * @param iPageY the current y position (optional, this just makes it so we
20567 * don't have to look it up again)
20569 cachePosition: function(iPageX, iPageY) {
20571 this.lastPageX = iPageX;
20572 this.lastPageY = iPageY;
20574 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20575 this.lastPageX = aCoord[0];
20576 this.lastPageY = aCoord[1];
20581 * Auto-scroll the window if the dragged object has been moved beyond the
20582 * visible window boundary.
20583 * @method autoScroll
20584 * @param {int} x the drag element's x position
20585 * @param {int} y the drag element's y position
20586 * @param {int} h the height of the drag element
20587 * @param {int} w the width of the drag element
20590 autoScroll: function(x, y, h, w) {
20593 // The client height
20594 var clientH = Roo.lib.Dom.getViewWidth();
20596 // The client width
20597 var clientW = Roo.lib.Dom.getViewHeight();
20599 // The amt scrolled down
20600 var st = this.DDM.getScrollTop();
20602 // The amt scrolled right
20603 var sl = this.DDM.getScrollLeft();
20605 // Location of the bottom of the element
20608 // Location of the right of the element
20611 // The distance from the cursor to the bottom of the visible area,
20612 // adjusted so that we don't scroll if the cursor is beyond the
20613 // element drag constraints
20614 var toBot = (clientH + st - y - this.deltaY);
20616 // The distance from the cursor to the right of the visible area
20617 var toRight = (clientW + sl - x - this.deltaX);
20620 // How close to the edge the cursor must be before we scroll
20621 // var thresh = (document.all) ? 100 : 40;
20624 // How many pixels to scroll per autoscroll op. This helps to reduce
20625 // clunky scrolling. IE is more sensitive about this ... it needs this
20626 // value to be higher.
20627 var scrAmt = (document.all) ? 80 : 30;
20629 // Scroll down if we are near the bottom of the visible page and the
20630 // obj extends below the crease
20631 if ( bot > clientH && toBot < thresh ) {
20632 window.scrollTo(sl, st + scrAmt);
20635 // Scroll up if the window is scrolled down and the top of the object
20636 // goes above the top border
20637 if ( y < st && st > 0 && y - st < thresh ) {
20638 window.scrollTo(sl, st - scrAmt);
20641 // Scroll right if the obj is beyond the right border and the cursor is
20642 // near the border.
20643 if ( right > clientW && toRight < thresh ) {
20644 window.scrollTo(sl + scrAmt, st);
20647 // Scroll left if the window has been scrolled to the right and the obj
20648 // extends past the left border
20649 if ( x < sl && sl > 0 && x - sl < thresh ) {
20650 window.scrollTo(sl - scrAmt, st);
20656 * Finds the location the element should be placed if we want to move
20657 * it to where the mouse location less the click offset would place us.
20658 * @method getTargetCoord
20659 * @param {int} iPageX the X coordinate of the click
20660 * @param {int} iPageY the Y coordinate of the click
20661 * @return an object that contains the coordinates (Object.x and Object.y)
20664 getTargetCoord: function(iPageX, iPageY) {
20667 var x = iPageX - this.deltaX;
20668 var y = iPageY - this.deltaY;
20670 if (this.constrainX) {
20671 if (x < this.minX) { x = this.minX; }
20672 if (x > this.maxX) { x = this.maxX; }
20675 if (this.constrainY) {
20676 if (y < this.minY) { y = this.minY; }
20677 if (y > this.maxY) { y = this.maxY; }
20680 x = this.getTick(x, this.xTicks);
20681 y = this.getTick(y, this.yTicks);
20688 * Sets up config options specific to this class. Overrides
20689 * Roo.dd.DragDrop, but all versions of this method through the
20690 * inheritance chain are called
20692 applyConfig: function() {
20693 Roo.dd.DD.superclass.applyConfig.call(this);
20694 this.scroll = (this.config.scroll !== false);
20698 * Event that fires prior to the onMouseDown event. Overrides
20701 b4MouseDown: function(e) {
20702 // this.resetConstraints();
20703 this.autoOffset(e.getPageX(),
20708 * Event that fires prior to the onDrag event. Overrides
20711 b4Drag: function(e) {
20712 this.setDragElPos(e.getPageX(),
20716 toString: function() {
20717 return ("DD " + this.id);
20720 //////////////////////////////////////////////////////////////////////////
20721 // Debugging ygDragDrop events that can be overridden
20722 //////////////////////////////////////////////////////////////////////////
20724 startDrag: function(x, y) {
20727 onDrag: function(e) {
20730 onDragEnter: function(e, id) {
20733 onDragOver: function(e, id) {
20736 onDragOut: function(e, id) {
20739 onDragDrop: function(e, id) {
20742 endDrag: function(e) {
20749 * Ext JS Library 1.1.1
20750 * Copyright(c) 2006-2007, Ext JS, LLC.
20752 * Originally Released Under LGPL - original licence link has changed is not relivant.
20755 * <script type="text/javascript">
20759 * @class Roo.dd.DDProxy
20760 * A DragDrop implementation that inserts an empty, bordered div into
20761 * the document that follows the cursor during drag operations. At the time of
20762 * the click, the frame div is resized to the dimensions of the linked html
20763 * element, and moved to the exact location of the linked element.
20765 * References to the "frame" element refer to the single proxy element that
20766 * was created to be dragged in place of all DDProxy elements on the
20769 * @extends Roo.dd.DD
20771 * @param {String} id the id of the linked html element
20772 * @param {String} sGroup the group of related DragDrop objects
20773 * @param {object} config an object containing configurable attributes
20774 * Valid properties for DDProxy in addition to those in DragDrop:
20775 * resizeFrame, centerFrame, dragElId
20777 Roo.dd.DDProxy = function(id, sGroup, config) {
20779 this.init(id, sGroup, config);
20785 * The default drag frame div id
20786 * @property Roo.dd.DDProxy.dragElId
20790 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20792 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20795 * By default we resize the drag frame to be the same size as the element
20796 * we want to drag (this is to get the frame effect). We can turn it off
20797 * if we want a different behavior.
20798 * @property resizeFrame
20804 * By default the frame is positioned exactly where the drag element is, so
20805 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20806 * you do not have constraints on the obj is to have the drag frame centered
20807 * around the cursor. Set centerFrame to true for this effect.
20808 * @property centerFrame
20811 centerFrame: false,
20814 * Creates the proxy element if it does not yet exist
20815 * @method createFrame
20817 createFrame: function() {
20819 var body = document.body;
20821 if (!body || !body.firstChild) {
20822 setTimeout( function() { self.createFrame(); }, 50 );
20826 var div = this.getDragEl();
20829 div = document.createElement("div");
20830 div.id = this.dragElId;
20833 s.position = "absolute";
20834 s.visibility = "hidden";
20836 s.border = "2px solid #aaa";
20839 // appendChild can blow up IE if invoked prior to the window load event
20840 // while rendering a table. It is possible there are other scenarios
20841 // that would cause this to happen as well.
20842 body.insertBefore(div, body.firstChild);
20847 * Initialization for the drag frame element. Must be called in the
20848 * constructor of all subclasses
20849 * @method initFrame
20851 initFrame: function() {
20852 this.createFrame();
20855 applyConfig: function() {
20856 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20858 this.resizeFrame = (this.config.resizeFrame !== false);
20859 this.centerFrame = (this.config.centerFrame);
20860 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20864 * Resizes the drag frame to the dimensions of the clicked object, positions
20865 * it over the object, and finally displays it
20866 * @method showFrame
20867 * @param {int} iPageX X click position
20868 * @param {int} iPageY Y click position
20871 showFrame: function(iPageX, iPageY) {
20872 var el = this.getEl();
20873 var dragEl = this.getDragEl();
20874 var s = dragEl.style;
20876 this._resizeProxy();
20878 if (this.centerFrame) {
20879 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20880 Math.round(parseInt(s.height, 10)/2) );
20883 this.setDragElPos(iPageX, iPageY);
20885 Roo.fly(dragEl).show();
20889 * The proxy is automatically resized to the dimensions of the linked
20890 * element when a drag is initiated, unless resizeFrame is set to false
20891 * @method _resizeProxy
20894 _resizeProxy: function() {
20895 if (this.resizeFrame) {
20896 var el = this.getEl();
20897 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20901 // overrides Roo.dd.DragDrop
20902 b4MouseDown: function(e) {
20903 var x = e.getPageX();
20904 var y = e.getPageY();
20905 this.autoOffset(x, y);
20906 this.setDragElPos(x, y);
20909 // overrides Roo.dd.DragDrop
20910 b4StartDrag: function(x, y) {
20911 // show the drag frame
20912 this.showFrame(x, y);
20915 // overrides Roo.dd.DragDrop
20916 b4EndDrag: function(e) {
20917 Roo.fly(this.getDragEl()).hide();
20920 // overrides Roo.dd.DragDrop
20921 // By default we try to move the element to the last location of the frame.
20922 // This is so that the default behavior mirrors that of Roo.dd.DD.
20923 endDrag: function(e) {
20925 var lel = this.getEl();
20926 var del = this.getDragEl();
20928 // Show the drag frame briefly so we can get its position
20929 del.style.visibility = "";
20932 // Hide the linked element before the move to get around a Safari
20934 lel.style.visibility = "hidden";
20935 Roo.dd.DDM.moveToEl(lel, del);
20936 del.style.visibility = "hidden";
20937 lel.style.visibility = "";
20942 beforeMove : function(){
20946 afterDrag : function(){
20950 toString: function() {
20951 return ("DDProxy " + this.id);
20957 * Ext JS Library 1.1.1
20958 * Copyright(c) 2006-2007, Ext JS, LLC.
20960 * Originally Released Under LGPL - original licence link has changed is not relivant.
20963 * <script type="text/javascript">
20967 * @class Roo.dd.DDTarget
20968 * A DragDrop implementation that does not move, but can be a drop
20969 * target. You would get the same result by simply omitting implementation
20970 * for the event callbacks, but this way we reduce the processing cost of the
20971 * event listener and the callbacks.
20972 * @extends Roo.dd.DragDrop
20974 * @param {String} id the id of the element that is a drop target
20975 * @param {String} sGroup the group of related DragDrop objects
20976 * @param {object} config an object containing configurable attributes
20977 * Valid properties for DDTarget in addition to those in
20981 Roo.dd.DDTarget = function(id, sGroup, config) {
20983 this.initTarget(id, sGroup, config);
20985 if (config.listeners || config.events) {
20986 Roo.dd.DragDrop.superclass.constructor.call(this, {
20987 listeners : config.listeners || {},
20988 events : config.events || {}
20993 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20994 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20995 toString: function() {
20996 return ("DDTarget " + this.id);
21001 * Ext JS Library 1.1.1
21002 * Copyright(c) 2006-2007, Ext JS, LLC.
21004 * Originally Released Under LGPL - original licence link has changed is not relivant.
21007 * <script type="text/javascript">
21012 * @class Roo.dd.ScrollManager
21013 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21014 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21017 Roo.dd.ScrollManager = function(){
21018 var ddm = Roo.dd.DragDropMgr;
21025 var onStop = function(e){
21030 var triggerRefresh = function(){
21031 if(ddm.dragCurrent){
21032 ddm.refreshCache(ddm.dragCurrent.groups);
21036 var doScroll = function(){
21037 if(ddm.dragCurrent){
21038 var dds = Roo.dd.ScrollManager;
21040 if(proc.el.scroll(proc.dir, dds.increment)){
21044 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21049 var clearProc = function(){
21051 clearInterval(proc.id);
21058 var startProc = function(el, dir){
21059 Roo.log('scroll startproc');
21063 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21066 var onFire = function(e, isDrop){
21068 if(isDrop || !ddm.dragCurrent){ return; }
21069 var dds = Roo.dd.ScrollManager;
21070 if(!dragEl || dragEl != ddm.dragCurrent){
21071 dragEl = ddm.dragCurrent;
21072 // refresh regions on drag start
21073 dds.refreshCache();
21076 var xy = Roo.lib.Event.getXY(e);
21077 var pt = new Roo.lib.Point(xy[0], xy[1]);
21078 for(var id in els){
21079 var el = els[id], r = el._region;
21080 if(r && r.contains(pt) && el.isScrollable()){
21081 if(r.bottom - pt.y <= dds.thresh){
21083 startProc(el, "down");
21086 }else if(r.right - pt.x <= dds.thresh){
21088 startProc(el, "left");
21091 }else if(pt.y - r.top <= dds.thresh){
21093 startProc(el, "up");
21096 }else if(pt.x - r.left <= dds.thresh){
21098 startProc(el, "right");
21107 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21108 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21112 * Registers new overflow element(s) to auto scroll
21113 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21115 register : function(el){
21116 if(el instanceof Array){
21117 for(var i = 0, len = el.length; i < len; i++) {
21118 this.register(el[i]);
21124 Roo.dd.ScrollManager.els = els;
21128 * Unregisters overflow element(s) so they are no longer scrolled
21129 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21131 unregister : function(el){
21132 if(el instanceof Array){
21133 for(var i = 0, len = el.length; i < len; i++) {
21134 this.unregister(el[i]);
21143 * The number of pixels from the edge of a container the pointer needs to be to
21144 * trigger scrolling (defaults to 25)
21150 * The number of pixels to scroll in each scroll increment (defaults to 50)
21156 * The frequency of scrolls in milliseconds (defaults to 500)
21162 * True to animate the scroll (defaults to true)
21168 * The animation duration in seconds -
21169 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21175 * Manually trigger a cache refresh.
21177 refreshCache : function(){
21178 for(var id in els){
21179 if(typeof els[id] == 'object'){ // for people extending the object prototype
21180 els[id]._region = els[id].getRegion();
21187 * Ext JS Library 1.1.1
21188 * Copyright(c) 2006-2007, Ext JS, LLC.
21190 * Originally Released Under LGPL - original licence link has changed is not relivant.
21193 * <script type="text/javascript">
21198 * @class Roo.dd.Registry
21199 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21200 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21203 Roo.dd.Registry = function(){
21206 var autoIdSeed = 0;
21208 var getId = function(el, autogen){
21209 if(typeof el == "string"){
21213 if(!id && autogen !== false){
21214 id = "roodd-" + (++autoIdSeed);
21222 * Register a drag drop element
21223 * @param {String|HTMLElement} element The id or DOM node to register
21224 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21225 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21226 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21227 * populated in the data object (if applicable):
21229 Value Description<br />
21230 --------- ------------------------------------------<br />
21231 handles Array of DOM nodes that trigger dragging<br />
21232 for the element being registered<br />
21233 isHandle True if the element passed in triggers<br />
21234 dragging itself, else false
21237 register : function(el, data){
21239 if(typeof el == "string"){
21240 el = document.getElementById(el);
21243 elements[getId(el)] = data;
21244 if(data.isHandle !== false){
21245 handles[data.ddel.id] = data;
21248 var hs = data.handles;
21249 for(var i = 0, len = hs.length; i < len; i++){
21250 handles[getId(hs[i])] = data;
21256 * Unregister a drag drop element
21257 * @param {String|HTMLElement} element The id or DOM node to unregister
21259 unregister : function(el){
21260 var id = getId(el, false);
21261 var data = elements[id];
21263 delete elements[id];
21265 var hs = data.handles;
21266 for(var i = 0, len = hs.length; i < len; i++){
21267 delete handles[getId(hs[i], false)];
21274 * Returns the handle registered for a DOM Node by id
21275 * @param {String|HTMLElement} id The DOM node or id to look up
21276 * @return {Object} handle The custom handle data
21278 getHandle : function(id){
21279 if(typeof id != "string"){ // must be element?
21282 return handles[id];
21286 * Returns the handle that is registered for the DOM node that is the target of the event
21287 * @param {Event} e The event
21288 * @return {Object} handle The custom handle data
21290 getHandleFromEvent : function(e){
21291 var t = Roo.lib.Event.getTarget(e);
21292 return t ? handles[t.id] : null;
21296 * Returns a custom data object that is registered for a DOM node by id
21297 * @param {String|HTMLElement} id The DOM node or id to look up
21298 * @return {Object} data The custom data
21300 getTarget : function(id){
21301 if(typeof id != "string"){ // must be element?
21304 return elements[id];
21308 * Returns a custom data object that is registered for the DOM node that is the target of the event
21309 * @param {Event} e The event
21310 * @return {Object} data The custom data
21312 getTargetFromEvent : function(e){
21313 var t = Roo.lib.Event.getTarget(e);
21314 return t ? elements[t.id] || handles[t.id] : null;
21319 * Ext JS Library 1.1.1
21320 * Copyright(c) 2006-2007, Ext JS, LLC.
21322 * Originally Released Under LGPL - original licence link has changed is not relivant.
21325 * <script type="text/javascript">
21330 * @class Roo.dd.StatusProxy
21331 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21332 * default drag proxy used by all Roo.dd components.
21334 * @param {Object} config
21336 Roo.dd.StatusProxy = function(config){
21337 Roo.apply(this, config);
21338 this.id = this.id || Roo.id();
21339 this.el = new Roo.Layer({
21341 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21342 {tag: "div", cls: "x-dd-drop-icon"},
21343 {tag: "div", cls: "x-dd-drag-ghost"}
21346 shadow: !config || config.shadow !== false
21348 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21349 this.dropStatus = this.dropNotAllowed;
21352 Roo.dd.StatusProxy.prototype = {
21354 * @cfg {String} dropAllowed
21355 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21357 dropAllowed : "x-dd-drop-ok",
21359 * @cfg {String} dropNotAllowed
21360 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21362 dropNotAllowed : "x-dd-drop-nodrop",
21365 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21366 * over the current target element.
21367 * @param {String} cssClass The css class for the new drop status indicator image
21369 setStatus : function(cssClass){
21370 cssClass = cssClass || this.dropNotAllowed;
21371 if(this.dropStatus != cssClass){
21372 this.el.replaceClass(this.dropStatus, cssClass);
21373 this.dropStatus = cssClass;
21378 * Resets the status indicator to the default dropNotAllowed value
21379 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21381 reset : function(clearGhost){
21382 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21383 this.dropStatus = this.dropNotAllowed;
21385 this.ghost.update("");
21390 * Updates the contents of the ghost element
21391 * @param {String} html The html that will replace the current innerHTML of the ghost element
21393 update : function(html){
21394 if(typeof html == "string"){
21395 this.ghost.update(html);
21397 this.ghost.update("");
21398 html.style.margin = "0";
21399 this.ghost.dom.appendChild(html);
21401 // ensure float = none set?? cant remember why though.
21402 var el = this.ghost.dom.firstChild;
21404 Roo.fly(el).setStyle('float', 'none');
21409 * Returns the underlying proxy {@link Roo.Layer}
21410 * @return {Roo.Layer} el
21412 getEl : function(){
21417 * Returns the ghost element
21418 * @return {Roo.Element} el
21420 getGhost : function(){
21426 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21428 hide : function(clear){
21436 * Stops the repair animation if it's currently running
21439 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21445 * Displays this proxy
21452 * Force the Layer to sync its shadow and shim positions to the element
21459 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21460 * invalid drop operation by the item being dragged.
21461 * @param {Array} xy The XY position of the element ([x, y])
21462 * @param {Function} callback The function to call after the repair is complete
21463 * @param {Object} scope The scope in which to execute the callback
21465 repair : function(xy, callback, scope){
21466 this.callback = callback;
21467 this.scope = scope;
21468 if(xy && this.animRepair !== false){
21469 this.el.addClass("x-dd-drag-repair");
21470 this.el.hideUnders(true);
21471 this.anim = this.el.shift({
21472 duration: this.repairDuration || .5,
21476 callback: this.afterRepair,
21480 this.afterRepair();
21485 afterRepair : function(){
21487 if(typeof this.callback == "function"){
21488 this.callback.call(this.scope || this);
21490 this.callback = null;
21495 * Ext JS Library 1.1.1
21496 * Copyright(c) 2006-2007, Ext JS, LLC.
21498 * Originally Released Under LGPL - original licence link has changed is not relivant.
21501 * <script type="text/javascript">
21505 * @class Roo.dd.DragSource
21506 * @extends Roo.dd.DDProxy
21507 * A simple class that provides the basic implementation needed to make any element draggable.
21509 * @param {String/HTMLElement/Element} el The container element
21510 * @param {Object} config
21512 Roo.dd.DragSource = function(el, config){
21513 this.el = Roo.get(el);
21514 this.dragData = {};
21516 Roo.apply(this, config);
21519 this.proxy = new Roo.dd.StatusProxy();
21522 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21523 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21525 this.dragging = false;
21528 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21530 * @cfg {String} dropAllowed
21531 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21533 dropAllowed : "x-dd-drop-ok",
21535 * @cfg {String} dropNotAllowed
21536 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21538 dropNotAllowed : "x-dd-drop-nodrop",
21541 * Returns the data object associated with this drag source
21542 * @return {Object} data An object containing arbitrary data
21544 getDragData : function(e){
21545 return this.dragData;
21549 onDragEnter : function(e, id){
21550 var target = Roo.dd.DragDropMgr.getDDById(id);
21551 this.cachedTarget = target;
21552 if(this.beforeDragEnter(target, e, id) !== false){
21553 if(target.isNotifyTarget){
21554 var status = target.notifyEnter(this, e, this.dragData);
21555 this.proxy.setStatus(status);
21557 this.proxy.setStatus(this.dropAllowed);
21560 if(this.afterDragEnter){
21562 * An empty function by default, but provided so that you can perform a custom action
21563 * when the dragged item enters the drop target by providing an implementation.
21564 * @param {Roo.dd.DragDrop} target The drop target
21565 * @param {Event} e The event object
21566 * @param {String} id The id of the dragged element
21567 * @method afterDragEnter
21569 this.afterDragEnter(target, e, id);
21575 * An empty function by default, but provided so that you can perform a custom action
21576 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21577 * @param {Roo.dd.DragDrop} target The drop target
21578 * @param {Event} e The event object
21579 * @param {String} id The id of the dragged element
21580 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21582 beforeDragEnter : function(target, e, id){
21587 alignElWithMouse: function() {
21588 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21593 onDragOver : function(e, id){
21594 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21595 if(this.beforeDragOver(target, e, id) !== false){
21596 if(target.isNotifyTarget){
21597 var status = target.notifyOver(this, e, this.dragData);
21598 this.proxy.setStatus(status);
21601 if(this.afterDragOver){
21603 * An empty function by default, but provided so that you can perform a custom action
21604 * while the dragged item is over the drop target by providing an implementation.
21605 * @param {Roo.dd.DragDrop} target The drop target
21606 * @param {Event} e The event object
21607 * @param {String} id The id of the dragged element
21608 * @method afterDragOver
21610 this.afterDragOver(target, e, id);
21616 * An empty function by default, but provided so that you can perform a custom action
21617 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21618 * @param {Roo.dd.DragDrop} target The drop target
21619 * @param {Event} e The event object
21620 * @param {String} id The id of the dragged element
21621 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21623 beforeDragOver : function(target, e, id){
21628 onDragOut : function(e, id){
21629 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21630 if(this.beforeDragOut(target, e, id) !== false){
21631 if(target.isNotifyTarget){
21632 target.notifyOut(this, e, this.dragData);
21634 this.proxy.reset();
21635 if(this.afterDragOut){
21637 * An empty function by default, but provided so that you can perform a custom action
21638 * after the dragged item is dragged out of the target without dropping.
21639 * @param {Roo.dd.DragDrop} target The drop target
21640 * @param {Event} e The event object
21641 * @param {String} id The id of the dragged element
21642 * @method afterDragOut
21644 this.afterDragOut(target, e, id);
21647 this.cachedTarget = null;
21651 * An empty function by default, but provided so that you can perform a custom action before the dragged
21652 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21653 * @param {Roo.dd.DragDrop} target The drop target
21654 * @param {Event} e The event object
21655 * @param {String} id The id of the dragged element
21656 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21658 beforeDragOut : function(target, e, id){
21663 onDragDrop : function(e, id){
21664 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21665 if(this.beforeDragDrop(target, e, id) !== false){
21666 if(target.isNotifyTarget){
21667 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21668 this.onValidDrop(target, e, id);
21670 this.onInvalidDrop(target, e, id);
21673 this.onValidDrop(target, e, id);
21676 if(this.afterDragDrop){
21678 * An empty function by default, but provided so that you can perform a custom action
21679 * after a valid drag drop has occurred by providing an implementation.
21680 * @param {Roo.dd.DragDrop} target The drop target
21681 * @param {Event} e The event object
21682 * @param {String} id The id of the dropped element
21683 * @method afterDragDrop
21685 this.afterDragDrop(target, e, id);
21688 delete this.cachedTarget;
21692 * An empty function by default, but provided so that you can perform a custom action before the dragged
21693 * item is dropped onto the target and optionally cancel the onDragDrop.
21694 * @param {Roo.dd.DragDrop} target The drop target
21695 * @param {Event} e The event object
21696 * @param {String} id The id of the dragged element
21697 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21699 beforeDragDrop : function(target, e, id){
21704 onValidDrop : function(target, e, id){
21706 if(this.afterValidDrop){
21708 * An empty function by default, but provided so that you can perform a custom action
21709 * after a valid drop has occurred by providing an implementation.
21710 * @param {Object} target The target DD
21711 * @param {Event} e The event object
21712 * @param {String} id The id of the dropped element
21713 * @method afterInvalidDrop
21715 this.afterValidDrop(target, e, id);
21720 getRepairXY : function(e, data){
21721 return this.el.getXY();
21725 onInvalidDrop : function(target, e, id){
21726 this.beforeInvalidDrop(target, e, id);
21727 if(this.cachedTarget){
21728 if(this.cachedTarget.isNotifyTarget){
21729 this.cachedTarget.notifyOut(this, e, this.dragData);
21731 this.cacheTarget = null;
21733 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21735 if(this.afterInvalidDrop){
21737 * An empty function by default, but provided so that you can perform a custom action
21738 * after an invalid drop has occurred by providing an implementation.
21739 * @param {Event} e The event object
21740 * @param {String} id The id of the dropped element
21741 * @method afterInvalidDrop
21743 this.afterInvalidDrop(e, id);
21748 afterRepair : function(){
21750 this.el.highlight(this.hlColor || "c3daf9");
21752 this.dragging = false;
21756 * An empty function by default, but provided so that you can perform a custom action after an invalid
21757 * drop has occurred.
21758 * @param {Roo.dd.DragDrop} target The drop target
21759 * @param {Event} e The event object
21760 * @param {String} id The id of the dragged element
21761 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21763 beforeInvalidDrop : function(target, e, id){
21768 handleMouseDown : function(e){
21769 if(this.dragging) {
21772 var data = this.getDragData(e);
21773 if(data && this.onBeforeDrag(data, e) !== false){
21774 this.dragData = data;
21776 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21781 * An empty function by default, but provided so that you can perform a custom action before the initial
21782 * drag event begins and optionally cancel it.
21783 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21784 * @param {Event} e The event object
21785 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21787 onBeforeDrag : function(data, e){
21792 * An empty function by default, but provided so that you can perform a custom action once the initial
21793 * drag event has begun. The drag cannot be canceled from this function.
21794 * @param {Number} x The x position of the click on the dragged object
21795 * @param {Number} y The y position of the click on the dragged object
21797 onStartDrag : Roo.emptyFn,
21799 // private - YUI override
21800 startDrag : function(x, y){
21801 this.proxy.reset();
21802 this.dragging = true;
21803 this.proxy.update("");
21804 this.onInitDrag(x, y);
21809 onInitDrag : function(x, y){
21810 var clone = this.el.dom.cloneNode(true);
21811 clone.id = Roo.id(); // prevent duplicate ids
21812 this.proxy.update(clone);
21813 this.onStartDrag(x, y);
21818 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21819 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21821 getProxy : function(){
21826 * Hides the drag source's {@link Roo.dd.StatusProxy}
21828 hideProxy : function(){
21830 this.proxy.reset(true);
21831 this.dragging = false;
21835 triggerCacheRefresh : function(){
21836 Roo.dd.DDM.refreshCache(this.groups);
21839 // private - override to prevent hiding
21840 b4EndDrag: function(e) {
21843 // private - override to prevent moving
21844 endDrag : function(e){
21845 this.onEndDrag(this.dragData, e);
21849 onEndDrag : function(data, e){
21852 // private - pin to cursor
21853 autoOffset : function(x, y) {
21854 this.setDelta(-12, -20);
21858 * Ext JS Library 1.1.1
21859 * Copyright(c) 2006-2007, Ext JS, LLC.
21861 * Originally Released Under LGPL - original licence link has changed is not relivant.
21864 * <script type="text/javascript">
21869 * @class Roo.dd.DropTarget
21870 * @extends Roo.dd.DDTarget
21871 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21872 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21874 * @param {String/HTMLElement/Element} el The container element
21875 * @param {Object} config
21877 Roo.dd.DropTarget = function(el, config){
21878 this.el = Roo.get(el);
21880 var listeners = false; ;
21881 if (config && config.listeners) {
21882 listeners= config.listeners;
21883 delete config.listeners;
21885 Roo.apply(this, config);
21887 if(this.containerScroll){
21888 Roo.dd.ScrollManager.register(this.el);
21892 * @scope Roo.dd.DropTarget
21897 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21898 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21899 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21901 * IMPORTANT : it should set this.overClass and this.dropAllowed
21903 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21904 * @param {Event} e The event
21905 * @param {Object} data An object containing arbitrary data supplied by the drag source
21911 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21912 * This method will be called on every mouse movement while the drag source is over the drop target.
21913 * This default implementation simply returns the dropAllowed config value.
21915 * IMPORTANT : it should set this.dropAllowed
21917 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21918 * @param {Event} e The event
21919 * @param {Object} data An object containing arbitrary data supplied by the drag source
21925 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21926 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21927 * overClass (if any) from the drop element.
21929 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21930 * @param {Event} e The event
21931 * @param {Object} data An object containing arbitrary data supplied by the drag source
21937 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21938 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21939 * implementation that does something to process the drop event and returns true so that the drag source's
21940 * repair action does not run.
21942 * IMPORTANT : it should set this.success
21944 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21945 * @param {Event} e The event
21946 * @param {Object} data An object containing arbitrary data supplied by the drag source
21952 Roo.dd.DropTarget.superclass.constructor.call( this,
21954 this.ddGroup || this.group,
21957 listeners : listeners || {}
21965 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21967 * @cfg {String} overClass
21968 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21971 * @cfg {String} ddGroup
21972 * The drag drop group to handle drop events for
21976 * @cfg {String} dropAllowed
21977 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21979 dropAllowed : "x-dd-drop-ok",
21981 * @cfg {String} dropNotAllowed
21982 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21984 dropNotAllowed : "x-dd-drop-nodrop",
21986 * @cfg {boolean} success
21987 * set this after drop listener..
21991 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21992 * if the drop point is valid for over/enter..
21999 isNotifyTarget : true,
22004 notifyEnter : function(dd, e, data)
22007 this.fireEvent('enter', dd, e, data);
22008 if(this.overClass){
22009 this.el.addClass(this.overClass);
22011 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22012 this.valid ? this.dropAllowed : this.dropNotAllowed
22019 notifyOver : function(dd, e, data)
22022 this.fireEvent('over', dd, e, data);
22023 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22024 this.valid ? this.dropAllowed : this.dropNotAllowed
22031 notifyOut : function(dd, e, data)
22033 this.fireEvent('out', dd, e, data);
22034 if(this.overClass){
22035 this.el.removeClass(this.overClass);
22042 notifyDrop : function(dd, e, data)
22044 this.success = false;
22045 this.fireEvent('drop', dd, e, data);
22046 return this.success;
22050 * Ext JS Library 1.1.1
22051 * Copyright(c) 2006-2007, Ext JS, LLC.
22053 * Originally Released Under LGPL - original licence link has changed is not relivant.
22056 * <script type="text/javascript">
22061 * @class Roo.dd.DragZone
22062 * @extends Roo.dd.DragSource
22063 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22064 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22066 * @param {String/HTMLElement/Element} el The container element
22067 * @param {Object} config
22069 Roo.dd.DragZone = function(el, config){
22070 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22071 if(this.containerScroll){
22072 Roo.dd.ScrollManager.register(this.el);
22076 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22078 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22079 * for auto scrolling during drag operations.
22082 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22083 * method after a failed drop (defaults to "c3daf9" - light blue)
22087 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22088 * for a valid target to drag based on the mouse down. Override this method
22089 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22090 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22091 * @param {EventObject} e The mouse down event
22092 * @return {Object} The dragData
22094 getDragData : function(e){
22095 return Roo.dd.Registry.getHandleFromEvent(e);
22099 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22100 * this.dragData.ddel
22101 * @param {Number} x The x position of the click on the dragged object
22102 * @param {Number} y The y position of the click on the dragged object
22103 * @return {Boolean} true to continue the drag, false to cancel
22105 onInitDrag : function(x, y){
22106 this.proxy.update(this.dragData.ddel.cloneNode(true));
22107 this.onStartDrag(x, y);
22112 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22114 afterRepair : function(){
22116 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22118 this.dragging = false;
22122 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22123 * the XY of this.dragData.ddel
22124 * @param {EventObject} e The mouse up event
22125 * @return {Array} The xy location (e.g. [100, 200])
22127 getRepairXY : function(e){
22128 return Roo.Element.fly(this.dragData.ddel).getXY();
22132 * Ext JS Library 1.1.1
22133 * Copyright(c) 2006-2007, Ext JS, LLC.
22135 * Originally Released Under LGPL - original licence link has changed is not relivant.
22138 * <script type="text/javascript">
22141 * @class Roo.dd.DropZone
22142 * @extends Roo.dd.DropTarget
22143 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22144 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22146 * @param {String/HTMLElement/Element} el The container element
22147 * @param {Object} config
22149 Roo.dd.DropZone = function(el, config){
22150 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22153 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22155 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22156 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22157 * provide your own custom lookup.
22158 * @param {Event} e The event
22159 * @return {Object} data The custom data
22161 getTargetFromEvent : function(e){
22162 return Roo.dd.Registry.getTargetFromEvent(e);
22166 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22167 * that it has registered. This method has no default implementation and should be overridden to provide
22168 * node-specific processing if necessary.
22169 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22170 * {@link #getTargetFromEvent} for this node)
22171 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22172 * @param {Event} e The event
22173 * @param {Object} data An object containing arbitrary data supplied by the drag source
22175 onNodeEnter : function(n, dd, e, data){
22180 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22181 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22182 * overridden to provide the proper feedback.
22183 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22184 * {@link #getTargetFromEvent} for this node)
22185 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22186 * @param {Event} e The event
22187 * @param {Object} data An object containing arbitrary data supplied by the drag source
22188 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22189 * underlying {@link Roo.dd.StatusProxy} can be updated
22191 onNodeOver : function(n, dd, e, data){
22192 return this.dropAllowed;
22196 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22197 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22198 * node-specific processing if necessary.
22199 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22200 * {@link #getTargetFromEvent} for this node)
22201 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22202 * @param {Event} e The event
22203 * @param {Object} data An object containing arbitrary data supplied by the drag source
22205 onNodeOut : function(n, dd, e, data){
22210 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22211 * the drop node. The default implementation returns false, so it should be overridden to provide the
22212 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22213 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22214 * {@link #getTargetFromEvent} for this node)
22215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22216 * @param {Event} e The event
22217 * @param {Object} data An object containing arbitrary data supplied by the drag source
22218 * @return {Boolean} True if the drop was valid, else false
22220 onNodeDrop : function(n, dd, e, data){
22225 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22226 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22227 * it should be overridden to provide the proper feedback if necessary.
22228 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22229 * @param {Event} e The event
22230 * @param {Object} data An object containing arbitrary data supplied by the drag source
22231 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22232 * underlying {@link Roo.dd.StatusProxy} can be updated
22234 onContainerOver : function(dd, e, data){
22235 return this.dropNotAllowed;
22239 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22240 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22241 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22242 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22243 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22244 * @param {Event} e The event
22245 * @param {Object} data An object containing arbitrary data supplied by the drag source
22246 * @return {Boolean} True if the drop was valid, else false
22248 onContainerDrop : function(dd, e, data){
22253 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22254 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22255 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22256 * you should override this method and provide a custom implementation.
22257 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22258 * @param {Event} e The event
22259 * @param {Object} data An object containing arbitrary data supplied by the drag source
22260 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22261 * underlying {@link Roo.dd.StatusProxy} can be updated
22263 notifyEnter : function(dd, e, data){
22264 return this.dropNotAllowed;
22268 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22269 * This method will be called on every mouse movement while the drag source is over the drop zone.
22270 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22271 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22272 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22273 * registered node, it will call {@link #onContainerOver}.
22274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22275 * @param {Event} e The event
22276 * @param {Object} data An object containing arbitrary data supplied by the drag source
22277 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22278 * underlying {@link Roo.dd.StatusProxy} can be updated
22280 notifyOver : function(dd, e, data){
22281 var n = this.getTargetFromEvent(e);
22282 if(!n){ // not over valid drop target
22283 if(this.lastOverNode){
22284 this.onNodeOut(this.lastOverNode, dd, e, data);
22285 this.lastOverNode = null;
22287 return this.onContainerOver(dd, e, data);
22289 if(this.lastOverNode != n){
22290 if(this.lastOverNode){
22291 this.onNodeOut(this.lastOverNode, dd, e, data);
22293 this.onNodeEnter(n, dd, e, data);
22294 this.lastOverNode = n;
22296 return this.onNodeOver(n, dd, e, data);
22300 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22301 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22302 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22303 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22304 * @param {Event} e The event
22305 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22307 notifyOut : function(dd, e, data){
22308 if(this.lastOverNode){
22309 this.onNodeOut(this.lastOverNode, dd, e, data);
22310 this.lastOverNode = null;
22315 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22316 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22317 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22318 * otherwise it will call {@link #onContainerDrop}.
22319 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22320 * @param {Event} e The event
22321 * @param {Object} data An object containing arbitrary data supplied by the drag source
22322 * @return {Boolean} True if the drop was valid, else false
22324 notifyDrop : function(dd, e, data){
22325 if(this.lastOverNode){
22326 this.onNodeOut(this.lastOverNode, dd, e, data);
22327 this.lastOverNode = null;
22329 var n = this.getTargetFromEvent(e);
22331 this.onNodeDrop(n, dd, e, data) :
22332 this.onContainerDrop(dd, e, data);
22336 triggerCacheRefresh : function(){
22337 Roo.dd.DDM.refreshCache(this.groups);
22341 * Ext JS Library 1.1.1
22342 * Copyright(c) 2006-2007, Ext JS, LLC.
22344 * Originally Released Under LGPL - original licence link has changed is not relivant.
22347 * <script type="text/javascript">
22352 * @class Roo.data.SortTypes
22354 * Defines the default sorting (casting?) comparison functions used when sorting data.
22356 Roo.data.SortTypes = {
22358 * Default sort that does nothing
22359 * @param {Mixed} s The value being converted
22360 * @return {Mixed} The comparison value
22362 none : function(s){
22367 * The regular expression used to strip tags
22371 stripTagsRE : /<\/?[^>]+>/gi,
22374 * Strips all HTML tags to sort on text only
22375 * @param {Mixed} s The value being converted
22376 * @return {String} The comparison value
22378 asText : function(s){
22379 return String(s).replace(this.stripTagsRE, "");
22383 * Strips all HTML tags to sort on text only - Case insensitive
22384 * @param {Mixed} s The value being converted
22385 * @return {String} The comparison value
22387 asUCText : function(s){
22388 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22392 * Case insensitive string
22393 * @param {Mixed} s The value being converted
22394 * @return {String} The comparison value
22396 asUCString : function(s) {
22397 return String(s).toUpperCase();
22402 * @param {Mixed} s The value being converted
22403 * @return {Number} The comparison value
22405 asDate : function(s) {
22409 if(s instanceof Date){
22410 return s.getTime();
22412 return Date.parse(String(s));
22417 * @param {Mixed} s The value being converted
22418 * @return {Float} The comparison value
22420 asFloat : function(s) {
22421 var val = parseFloat(String(s).replace(/,/g, ""));
22430 * @param {Mixed} s The value being converted
22431 * @return {Number} The comparison value
22433 asInt : function(s) {
22434 var val = parseInt(String(s).replace(/,/g, ""));
22442 * Ext JS Library 1.1.1
22443 * Copyright(c) 2006-2007, Ext JS, LLC.
22445 * Originally Released Under LGPL - original licence link has changed is not relivant.
22448 * <script type="text/javascript">
22452 * @class Roo.data.Record
22453 * Instances of this class encapsulate both record <em>definition</em> information, and record
22454 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22455 * to access Records cached in an {@link Roo.data.Store} object.<br>
22457 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22458 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22461 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22463 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22464 * {@link #create}. The parameters are the same.
22465 * @param {Array} data An associative Array of data values keyed by the field name.
22466 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22467 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22468 * not specified an integer id is generated.
22470 Roo.data.Record = function(data, id){
22471 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22476 * Generate a constructor for a specific record layout.
22477 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22478 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22479 * Each field definition object may contain the following properties: <ul>
22480 * <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,
22481 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22482 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22483 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22484 * is being used, then this is a string containing the javascript expression to reference the data relative to
22485 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22486 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22487 * this may be omitted.</p></li>
22488 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22489 * <ul><li>auto (Default, implies no conversion)</li>
22494 * <li>date</li></ul></p></li>
22495 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22496 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22497 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22498 * by the Reader into an object that will be stored in the Record. It is passed the
22499 * following parameters:<ul>
22500 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22502 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22504 * <br>usage:<br><pre><code>
22505 var TopicRecord = Roo.data.Record.create(
22506 {name: 'title', mapping: 'topic_title'},
22507 {name: 'author', mapping: 'username'},
22508 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22509 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22510 {name: 'lastPoster', mapping: 'user2'},
22511 {name: 'excerpt', mapping: 'post_text'}
22514 var myNewRecord = new TopicRecord({
22515 title: 'Do my job please',
22518 lastPost: new Date(),
22519 lastPoster: 'Animal',
22520 excerpt: 'No way dude!'
22522 myStore.add(myNewRecord);
22527 Roo.data.Record.create = function(o){
22528 var f = function(){
22529 f.superclass.constructor.apply(this, arguments);
22531 Roo.extend(f, Roo.data.Record);
22532 var p = f.prototype;
22533 p.fields = new Roo.util.MixedCollection(false, function(field){
22536 for(var i = 0, len = o.length; i < len; i++){
22537 p.fields.add(new Roo.data.Field(o[i]));
22539 f.getField = function(name){
22540 return p.fields.get(name);
22545 Roo.data.Record.AUTO_ID = 1000;
22546 Roo.data.Record.EDIT = 'edit';
22547 Roo.data.Record.REJECT = 'reject';
22548 Roo.data.Record.COMMIT = 'commit';
22550 Roo.data.Record.prototype = {
22552 * Readonly flag - true if this record has been modified.
22561 join : function(store){
22562 this.store = store;
22566 * Set the named field to the specified value.
22567 * @param {String} name The name of the field to set.
22568 * @param {Object} value The value to set the field to.
22570 set : function(name, value){
22571 if(this.data[name] == value){
22575 if(!this.modified){
22576 this.modified = {};
22578 if(typeof this.modified[name] == 'undefined'){
22579 this.modified[name] = this.data[name];
22581 this.data[name] = value;
22582 if(!this.editing && this.store){
22583 this.store.afterEdit(this);
22588 * Get the value of the named field.
22589 * @param {String} name The name of the field to get the value of.
22590 * @return {Object} The value of the field.
22592 get : function(name){
22593 return this.data[name];
22597 beginEdit : function(){
22598 this.editing = true;
22599 this.modified = {};
22603 cancelEdit : function(){
22604 this.editing = false;
22605 delete this.modified;
22609 endEdit : function(){
22610 this.editing = false;
22611 if(this.dirty && this.store){
22612 this.store.afterEdit(this);
22617 * Usually called by the {@link Roo.data.Store} which owns the Record.
22618 * Rejects all changes made to the Record since either creation, or the last commit operation.
22619 * Modified fields are reverted to their original values.
22621 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22622 * of reject operations.
22624 reject : function(){
22625 var m = this.modified;
22627 if(typeof m[n] != "function"){
22628 this.data[n] = m[n];
22631 this.dirty = false;
22632 delete this.modified;
22633 this.editing = false;
22635 this.store.afterReject(this);
22640 * Usually called by the {@link Roo.data.Store} which owns the Record.
22641 * Commits all changes made to the Record since either creation, or the last commit operation.
22643 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22644 * of commit operations.
22646 commit : function(){
22647 this.dirty = false;
22648 delete this.modified;
22649 this.editing = false;
22651 this.store.afterCommit(this);
22656 hasError : function(){
22657 return this.error != null;
22661 clearError : function(){
22666 * Creates a copy of this record.
22667 * @param {String} id (optional) A new record id if you don't want to use this record's id
22670 copy : function(newId) {
22671 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22675 * Ext JS Library 1.1.1
22676 * Copyright(c) 2006-2007, Ext JS, LLC.
22678 * Originally Released Under LGPL - original licence link has changed is not relivant.
22681 * <script type="text/javascript">
22687 * @class Roo.data.Store
22688 * @extends Roo.util.Observable
22689 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22690 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22692 * 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
22693 * has no knowledge of the format of the data returned by the Proxy.<br>
22695 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22696 * instances from the data object. These records are cached and made available through accessor functions.
22698 * Creates a new Store.
22699 * @param {Object} config A config object containing the objects needed for the Store to access data,
22700 * and read the data into Records.
22702 Roo.data.Store = function(config){
22703 this.data = new Roo.util.MixedCollection(false);
22704 this.data.getKey = function(o){
22707 this.baseParams = {};
22709 this.paramNames = {
22714 "multisort" : "_multisort"
22717 if(config && config.data){
22718 this.inlineData = config.data;
22719 delete config.data;
22722 Roo.apply(this, config);
22724 if(this.reader){ // reader passed
22725 this.reader = Roo.factory(this.reader, Roo.data);
22726 this.reader.xmodule = this.xmodule || false;
22727 if(!this.recordType){
22728 this.recordType = this.reader.recordType;
22730 if(this.reader.onMetaChange){
22731 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22735 if(this.recordType){
22736 this.fields = this.recordType.prototype.fields;
22738 this.modified = [];
22742 * @event datachanged
22743 * Fires when the data cache has changed, and a widget which is using this Store
22744 * as a Record cache should refresh its view.
22745 * @param {Store} this
22747 datachanged : true,
22749 * @event metachange
22750 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22751 * @param {Store} this
22752 * @param {Object} meta The JSON metadata
22757 * Fires when Records have been added to the Store
22758 * @param {Store} this
22759 * @param {Roo.data.Record[]} records The array of Records added
22760 * @param {Number} index The index at which the record(s) were added
22765 * Fires when a Record has been removed from the Store
22766 * @param {Store} this
22767 * @param {Roo.data.Record} record The Record that was removed
22768 * @param {Number} index The index at which the record was removed
22773 * Fires when a Record has been updated
22774 * @param {Store} this
22775 * @param {Roo.data.Record} record The Record that was updated
22776 * @param {String} operation The update operation being performed. Value may be one of:
22778 Roo.data.Record.EDIT
22779 Roo.data.Record.REJECT
22780 Roo.data.Record.COMMIT
22786 * Fires when the data cache has been cleared.
22787 * @param {Store} this
22791 * @event beforeload
22792 * Fires before a request is made for a new data object. If the beforeload handler returns false
22793 * the load action will be canceled.
22794 * @param {Store} this
22795 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22799 * @event beforeloadadd
22800 * Fires after a new set of Records has been loaded.
22801 * @param {Store} this
22802 * @param {Roo.data.Record[]} records The Records that were loaded
22803 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22805 beforeloadadd : true,
22808 * Fires after a new set of Records has been loaded, before they are added to the store.
22809 * @param {Store} this
22810 * @param {Roo.data.Record[]} records The Records that were loaded
22811 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22812 * @params {Object} return from reader
22816 * @event loadexception
22817 * Fires if an exception occurs in the Proxy during loading.
22818 * Called with the signature of the Proxy's "loadexception" event.
22819 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22822 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22823 * @param {Object} load options
22824 * @param {Object} jsonData from your request (normally this contains the Exception)
22826 loadexception : true
22830 this.proxy = Roo.factory(this.proxy, Roo.data);
22831 this.proxy.xmodule = this.xmodule || false;
22832 this.relayEvents(this.proxy, ["loadexception"]);
22834 this.sortToggle = {};
22835 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22837 Roo.data.Store.superclass.constructor.call(this);
22839 if(this.inlineData){
22840 this.loadData(this.inlineData);
22841 delete this.inlineData;
22845 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22847 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22848 * without a remote query - used by combo/forms at present.
22852 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22855 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22858 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22859 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22862 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22863 * on any HTTP request
22866 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22869 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22873 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22874 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22876 remoteSort : false,
22879 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22880 * loaded or when a record is removed. (defaults to false).
22882 pruneModifiedRecords : false,
22885 lastOptions : null,
22888 * Add Records to the Store and fires the add event.
22889 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22891 add : function(records){
22892 records = [].concat(records);
22893 for(var i = 0, len = records.length; i < len; i++){
22894 records[i].join(this);
22896 var index = this.data.length;
22897 this.data.addAll(records);
22898 this.fireEvent("add", this, records, index);
22902 * Remove a Record from the Store and fires the remove event.
22903 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22905 remove : function(record){
22906 var index = this.data.indexOf(record);
22907 this.data.removeAt(index);
22908 if(this.pruneModifiedRecords){
22909 this.modified.remove(record);
22911 this.fireEvent("remove", this, record, index);
22915 * Remove all Records from the Store and fires the clear event.
22917 removeAll : function(){
22919 if(this.pruneModifiedRecords){
22920 this.modified = [];
22922 this.fireEvent("clear", this);
22926 * Inserts Records to the Store at the given index and fires the add event.
22927 * @param {Number} index The start index at which to insert the passed Records.
22928 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22930 insert : function(index, records){
22931 records = [].concat(records);
22932 for(var i = 0, len = records.length; i < len; i++){
22933 this.data.insert(index, records[i]);
22934 records[i].join(this);
22936 this.fireEvent("add", this, records, index);
22940 * Get the index within the cache of the passed Record.
22941 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22942 * @return {Number} The index of the passed Record. Returns -1 if not found.
22944 indexOf : function(record){
22945 return this.data.indexOf(record);
22949 * Get the index within the cache of the Record with the passed id.
22950 * @param {String} id The id of the Record to find.
22951 * @return {Number} The index of the Record. Returns -1 if not found.
22953 indexOfId : function(id){
22954 return this.data.indexOfKey(id);
22958 * Get the Record with the specified id.
22959 * @param {String} id The id of the Record to find.
22960 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22962 getById : function(id){
22963 return this.data.key(id);
22967 * Get the Record at the specified index.
22968 * @param {Number} index The index of the Record to find.
22969 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22971 getAt : function(index){
22972 return this.data.itemAt(index);
22976 * Returns a range of Records between specified indices.
22977 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22978 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22979 * @return {Roo.data.Record[]} An array of Records
22981 getRange : function(start, end){
22982 return this.data.getRange(start, end);
22986 storeOptions : function(o){
22987 o = Roo.apply({}, o);
22990 this.lastOptions = o;
22994 * Loads the Record cache from the configured Proxy using the configured Reader.
22996 * If using remote paging, then the first load call must specify the <em>start</em>
22997 * and <em>limit</em> properties in the options.params property to establish the initial
22998 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23000 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23001 * and this call will return before the new data has been loaded. Perform any post-processing
23002 * in a callback function, or in a "load" event handler.</strong>
23004 * @param {Object} options An object containing properties which control loading options:<ul>
23005 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23006 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23007 * passed the following arguments:<ul>
23008 * <li>r : Roo.data.Record[]</li>
23009 * <li>options: Options object from the load call</li>
23010 * <li>success: Boolean success indicator</li></ul></li>
23011 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23012 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23015 load : function(options){
23016 options = options || {};
23017 if(this.fireEvent("beforeload", this, options) !== false){
23018 this.storeOptions(options);
23019 var p = Roo.apply(options.params || {}, this.baseParams);
23020 // if meta was not loaded from remote source.. try requesting it.
23021 if (!this.reader.metaFromRemote) {
23022 p._requestMeta = 1;
23024 if(this.sortInfo && this.remoteSort){
23025 var pn = this.paramNames;
23026 p[pn["sort"]] = this.sortInfo.field;
23027 p[pn["dir"]] = this.sortInfo.direction;
23029 if (this.multiSort) {
23030 var pn = this.paramNames;
23031 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23034 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23039 * Reloads the Record cache from the configured Proxy using the configured Reader and
23040 * the options from the last load operation performed.
23041 * @param {Object} options (optional) An object containing properties which may override the options
23042 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23043 * the most recently used options are reused).
23045 reload : function(options){
23046 this.load(Roo.applyIf(options||{}, this.lastOptions));
23050 // Called as a callback by the Reader during a load operation.
23051 loadRecords : function(o, options, success){
23052 if(!o || success === false){
23053 if(success !== false){
23054 this.fireEvent("load", this, [], options, o);
23056 if(options.callback){
23057 options.callback.call(options.scope || this, [], options, false);
23061 // if data returned failure - throw an exception.
23062 if (o.success === false) {
23063 // show a message if no listener is registered.
23064 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23065 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23067 // loadmask wil be hooked into this..
23068 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23071 var r = o.records, t = o.totalRecords || r.length;
23073 this.fireEvent("beforeloadadd", this, r, options, o);
23075 if(!options || options.add !== true){
23076 if(this.pruneModifiedRecords){
23077 this.modified = [];
23079 for(var i = 0, len = r.length; i < len; i++){
23083 this.data = this.snapshot;
23084 delete this.snapshot;
23087 this.data.addAll(r);
23088 this.totalLength = t;
23090 this.fireEvent("datachanged", this);
23092 this.totalLength = Math.max(t, this.data.length+r.length);
23096 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23098 var e = new Roo.data.Record({});
23100 e.set(this.parent.displayField, this.parent.emptyTitle);
23101 e.set(this.parent.valueField, '');
23106 this.fireEvent("load", this, r, options, o);
23107 if(options.callback){
23108 options.callback.call(options.scope || this, r, options, true);
23114 * Loads data from a passed data block. A Reader which understands the format of the data
23115 * must have been configured in the constructor.
23116 * @param {Object} data The data block from which to read the Records. The format of the data expected
23117 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23118 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23120 loadData : function(o, append){
23121 var r = this.reader.readRecords(o);
23122 this.loadRecords(r, {add: append}, true);
23126 * Gets the number of cached records.
23128 * <em>If using paging, this may not be the total size of the dataset. If the data object
23129 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23130 * the data set size</em>
23132 getCount : function(){
23133 return this.data.length || 0;
23137 * Gets the total number of records in the dataset as returned by the server.
23139 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23140 * the dataset size</em>
23142 getTotalCount : function(){
23143 return this.totalLength || 0;
23147 * Returns the sort state of the Store as an object with two properties:
23149 field {String} The name of the field by which the Records are sorted
23150 direction {String} The sort order, "ASC" or "DESC"
23153 getSortState : function(){
23154 return this.sortInfo;
23158 applySort : function(){
23159 if(this.sortInfo && !this.remoteSort){
23160 var s = this.sortInfo, f = s.field;
23161 var st = this.fields.get(f).sortType;
23162 var fn = function(r1, r2){
23163 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23164 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23166 this.data.sort(s.direction, fn);
23167 if(this.snapshot && this.snapshot != this.data){
23168 this.snapshot.sort(s.direction, fn);
23174 * Sets the default sort column and order to be used by the next load operation.
23175 * @param {String} fieldName The name of the field to sort by.
23176 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23178 setDefaultSort : function(field, dir){
23179 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23183 * Sort the Records.
23184 * If remote sorting is used, the sort is performed on the server, and the cache is
23185 * reloaded. If local sorting is used, the cache is sorted internally.
23186 * @param {String} fieldName The name of the field to sort by.
23187 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23189 sort : function(fieldName, dir){
23190 var f = this.fields.get(fieldName);
23192 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23194 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23195 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23200 this.sortToggle[f.name] = dir;
23201 this.sortInfo = {field: f.name, direction: dir};
23202 if(!this.remoteSort){
23204 this.fireEvent("datachanged", this);
23206 this.load(this.lastOptions);
23211 * Calls the specified function for each of the Records in the cache.
23212 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23213 * Returning <em>false</em> aborts and exits the iteration.
23214 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23216 each : function(fn, scope){
23217 this.data.each(fn, scope);
23221 * Gets all records modified since the last commit. Modified records are persisted across load operations
23222 * (e.g., during paging).
23223 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23225 getModifiedRecords : function(){
23226 return this.modified;
23230 createFilterFn : function(property, value, anyMatch){
23231 if(!value.exec){ // not a regex
23232 value = String(value);
23233 if(value.length == 0){
23236 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23238 return function(r){
23239 return value.test(r.data[property]);
23244 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23245 * @param {String} property A field on your records
23246 * @param {Number} start The record index to start at (defaults to 0)
23247 * @param {Number} end The last record index to include (defaults to length - 1)
23248 * @return {Number} The sum
23250 sum : function(property, start, end){
23251 var rs = this.data.items, v = 0;
23252 start = start || 0;
23253 end = (end || end === 0) ? end : rs.length-1;
23255 for(var i = start; i <= end; i++){
23256 v += (rs[i].data[property] || 0);
23262 * Filter the records by a specified property.
23263 * @param {String} field A field on your records
23264 * @param {String/RegExp} value Either a string that the field
23265 * should start with or a RegExp to test against the field
23266 * @param {Boolean} anyMatch True to match any part not just the beginning
23268 filter : function(property, value, anyMatch){
23269 var fn = this.createFilterFn(property, value, anyMatch);
23270 return fn ? this.filterBy(fn) : this.clearFilter();
23274 * Filter by a function. The specified function will be called with each
23275 * record in this data source. If the function returns true the record is included,
23276 * otherwise it is filtered.
23277 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23278 * @param {Object} scope (optional) The scope of the function (defaults to this)
23280 filterBy : function(fn, scope){
23281 this.snapshot = this.snapshot || this.data;
23282 this.data = this.queryBy(fn, scope||this);
23283 this.fireEvent("datachanged", this);
23287 * Query the records by a specified property.
23288 * @param {String} field A field on your records
23289 * @param {String/RegExp} value Either a string that the field
23290 * should start with or a RegExp to test against the field
23291 * @param {Boolean} anyMatch True to match any part not just the beginning
23292 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23294 query : function(property, value, anyMatch){
23295 var fn = this.createFilterFn(property, value, anyMatch);
23296 return fn ? this.queryBy(fn) : this.data.clone();
23300 * Query by a function. The specified function will be called with each
23301 * record in this data source. If the function returns true the record is included
23303 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23304 * @param {Object} scope (optional) The scope of the function (defaults to this)
23305 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23307 queryBy : function(fn, scope){
23308 var data = this.snapshot || this.data;
23309 return data.filterBy(fn, scope||this);
23313 * Collects unique values for a particular dataIndex from this store.
23314 * @param {String} dataIndex The property to collect
23315 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23316 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23317 * @return {Array} An array of the unique values
23319 collect : function(dataIndex, allowNull, bypassFilter){
23320 var d = (bypassFilter === true && this.snapshot) ?
23321 this.snapshot.items : this.data.items;
23322 var v, sv, r = [], l = {};
23323 for(var i = 0, len = d.length; i < len; i++){
23324 v = d[i].data[dataIndex];
23326 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23335 * Revert to a view of the Record cache with no filtering applied.
23336 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23338 clearFilter : function(suppressEvent){
23339 if(this.snapshot && this.snapshot != this.data){
23340 this.data = this.snapshot;
23341 delete this.snapshot;
23342 if(suppressEvent !== true){
23343 this.fireEvent("datachanged", this);
23349 afterEdit : function(record){
23350 if(this.modified.indexOf(record) == -1){
23351 this.modified.push(record);
23353 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23357 afterReject : function(record){
23358 this.modified.remove(record);
23359 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23363 afterCommit : function(record){
23364 this.modified.remove(record);
23365 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23369 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23370 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23372 commitChanges : function(){
23373 var m = this.modified.slice(0);
23374 this.modified = [];
23375 for(var i = 0, len = m.length; i < len; i++){
23381 * Cancel outstanding changes on all changed records.
23383 rejectChanges : function(){
23384 var m = this.modified.slice(0);
23385 this.modified = [];
23386 for(var i = 0, len = m.length; i < len; i++){
23391 onMetaChange : function(meta, rtype, o){
23392 this.recordType = rtype;
23393 this.fields = rtype.prototype.fields;
23394 delete this.snapshot;
23395 this.sortInfo = meta.sortInfo || this.sortInfo;
23396 this.modified = [];
23397 this.fireEvent('metachange', this, this.reader.meta);
23400 moveIndex : function(data, type)
23402 var index = this.indexOf(data);
23404 var newIndex = index + type;
23408 this.insert(newIndex, data);
23413 * Ext JS Library 1.1.1
23414 * Copyright(c) 2006-2007, Ext JS, LLC.
23416 * Originally Released Under LGPL - original licence link has changed is not relivant.
23419 * <script type="text/javascript">
23423 * @class Roo.data.SimpleStore
23424 * @extends Roo.data.Store
23425 * Small helper class to make creating Stores from Array data easier.
23426 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23427 * @cfg {Array} fields An array of field definition objects, or field name strings.
23428 * @cfg {Array} data The multi-dimensional array of data
23430 * @param {Object} config
23432 Roo.data.SimpleStore = function(config){
23433 Roo.data.SimpleStore.superclass.constructor.call(this, {
23435 reader: new Roo.data.ArrayReader({
23438 Roo.data.Record.create(config.fields)
23440 proxy : new Roo.data.MemoryProxy(config.data)
23444 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23446 * Ext JS Library 1.1.1
23447 * Copyright(c) 2006-2007, Ext JS, LLC.
23449 * Originally Released Under LGPL - original licence link has changed is not relivant.
23452 * <script type="text/javascript">
23457 * @extends Roo.data.Store
23458 * @class Roo.data.JsonStore
23459 * Small helper class to make creating Stores for JSON data easier. <br/>
23461 var store = new Roo.data.JsonStore({
23462 url: 'get-images.php',
23464 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23467 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23468 * JsonReader and HttpProxy (unless inline data is provided).</b>
23469 * @cfg {Array} fields An array of field definition objects, or field name strings.
23471 * @param {Object} config
23473 Roo.data.JsonStore = function(c){
23474 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23475 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23476 reader: new Roo.data.JsonReader(c, c.fields)
23479 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23481 * Ext JS Library 1.1.1
23482 * Copyright(c) 2006-2007, Ext JS, LLC.
23484 * Originally Released Under LGPL - original licence link has changed is not relivant.
23487 * <script type="text/javascript">
23491 Roo.data.Field = function(config){
23492 if(typeof config == "string"){
23493 config = {name: config};
23495 Roo.apply(this, config);
23498 this.type = "auto";
23501 var st = Roo.data.SortTypes;
23502 // named sortTypes are supported, here we look them up
23503 if(typeof this.sortType == "string"){
23504 this.sortType = st[this.sortType];
23507 // set default sortType for strings and dates
23508 if(!this.sortType){
23511 this.sortType = st.asUCString;
23514 this.sortType = st.asDate;
23517 this.sortType = st.none;
23522 var stripRe = /[\$,%]/g;
23524 // prebuilt conversion function for this field, instead of
23525 // switching every time we're reading a value
23527 var cv, dateFormat = this.dateFormat;
23532 cv = function(v){ return v; };
23535 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23539 return v !== undefined && v !== null && v !== '' ?
23540 parseInt(String(v).replace(stripRe, ""), 10) : '';
23545 return v !== undefined && v !== null && v !== '' ?
23546 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23551 cv = function(v){ return v === true || v === "true" || v == 1; };
23558 if(v instanceof Date){
23562 if(dateFormat == "timestamp"){
23563 return new Date(v*1000);
23565 return Date.parseDate(v, dateFormat);
23567 var parsed = Date.parse(v);
23568 return parsed ? new Date(parsed) : null;
23577 Roo.data.Field.prototype = {
23585 * Ext JS Library 1.1.1
23586 * Copyright(c) 2006-2007, Ext JS, LLC.
23588 * Originally Released Under LGPL - original licence link has changed is not relivant.
23591 * <script type="text/javascript">
23594 // Base class for reading structured data from a data source. This class is intended to be
23595 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23598 * @class Roo.data.DataReader
23599 * Base class for reading structured data from a data source. This class is intended to be
23600 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23603 Roo.data.DataReader = function(meta, recordType){
23607 this.recordType = recordType instanceof Array ?
23608 Roo.data.Record.create(recordType) : recordType;
23611 Roo.data.DataReader.prototype = {
23613 * Create an empty record
23614 * @param {Object} data (optional) - overlay some values
23615 * @return {Roo.data.Record} record created.
23617 newRow : function(d) {
23619 this.recordType.prototype.fields.each(function(c) {
23621 case 'int' : da[c.name] = 0; break;
23622 case 'date' : da[c.name] = new Date(); break;
23623 case 'float' : da[c.name] = 0.0; break;
23624 case 'boolean' : da[c.name] = false; break;
23625 default : da[c.name] = ""; break;
23629 return new this.recordType(Roo.apply(da, d));
23634 * Ext JS Library 1.1.1
23635 * Copyright(c) 2006-2007, Ext JS, LLC.
23637 * Originally Released Under LGPL - original licence link has changed is not relivant.
23640 * <script type="text/javascript">
23644 * @class Roo.data.DataProxy
23645 * @extends Roo.data.Observable
23646 * This class is an abstract base class for implementations which provide retrieval of
23647 * unformatted data objects.<br>
23649 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23650 * (of the appropriate type which knows how to parse the data object) to provide a block of
23651 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23653 * Custom implementations must implement the load method as described in
23654 * {@link Roo.data.HttpProxy#load}.
23656 Roo.data.DataProxy = function(){
23659 * @event beforeload
23660 * Fires before a network request is made to retrieve a data object.
23661 * @param {Object} This DataProxy object.
23662 * @param {Object} params The params parameter to the load function.
23667 * Fires before the load method's callback is called.
23668 * @param {Object} This DataProxy object.
23669 * @param {Object} o The data object.
23670 * @param {Object} arg The callback argument object passed to the load function.
23674 * @event loadexception
23675 * Fires if an Exception occurs during data retrieval.
23676 * @param {Object} This DataProxy object.
23677 * @param {Object} o The data object.
23678 * @param {Object} arg The callback argument object passed to the load function.
23679 * @param {Object} e The Exception.
23681 loadexception : true
23683 Roo.data.DataProxy.superclass.constructor.call(this);
23686 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23689 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23693 * Ext JS Library 1.1.1
23694 * Copyright(c) 2006-2007, Ext JS, LLC.
23696 * Originally Released Under LGPL - original licence link has changed is not relivant.
23699 * <script type="text/javascript">
23702 * @class Roo.data.MemoryProxy
23703 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23704 * to the Reader when its load method is called.
23706 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23708 Roo.data.MemoryProxy = function(data){
23712 Roo.data.MemoryProxy.superclass.constructor.call(this);
23716 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23719 * Load data from the requested source (in this case an in-memory
23720 * data object passed to the constructor), read the data object into
23721 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23722 * process that block using the passed callback.
23723 * @param {Object} params This parameter is not used by the MemoryProxy class.
23724 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23725 * object into a block of Roo.data.Records.
23726 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23727 * The function must be passed <ul>
23728 * <li>The Record block object</li>
23729 * <li>The "arg" argument from the load function</li>
23730 * <li>A boolean success indicator</li>
23732 * @param {Object} scope The scope in which to call the callback
23733 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23735 load : function(params, reader, callback, scope, arg){
23736 params = params || {};
23739 result = reader.readRecords(this.data);
23741 this.fireEvent("loadexception", this, arg, null, e);
23742 callback.call(scope, null, arg, false);
23745 callback.call(scope, result, arg, true);
23749 update : function(params, records){
23754 * Ext JS Library 1.1.1
23755 * Copyright(c) 2006-2007, Ext JS, LLC.
23757 * Originally Released Under LGPL - original licence link has changed is not relivant.
23760 * <script type="text/javascript">
23763 * @class Roo.data.HttpProxy
23764 * @extends Roo.data.DataProxy
23765 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23766 * configured to reference a certain URL.<br><br>
23768 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23769 * from which the running page was served.<br><br>
23771 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23773 * Be aware that to enable the browser to parse an XML document, the server must set
23774 * the Content-Type header in the HTTP response to "text/xml".
23776 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23777 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23778 * will be used to make the request.
23780 Roo.data.HttpProxy = function(conn){
23781 Roo.data.HttpProxy.superclass.constructor.call(this);
23782 // is conn a conn config or a real conn?
23784 this.useAjax = !conn || !conn.events;
23788 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23789 // thse are take from connection...
23792 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23795 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23796 * extra parameters to each request made by this object. (defaults to undefined)
23799 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23800 * to each request made by this object. (defaults to undefined)
23803 * @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)
23806 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23809 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23815 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23819 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23820 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23821 * a finer-grained basis than the DataProxy events.
23823 getConnection : function(){
23824 return this.useAjax ? Roo.Ajax : this.conn;
23828 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23829 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23830 * process that block using the passed callback.
23831 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23832 * for the request to the remote server.
23833 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23834 * object into a block of Roo.data.Records.
23835 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23836 * The function must be passed <ul>
23837 * <li>The Record block object</li>
23838 * <li>The "arg" argument from the load function</li>
23839 * <li>A boolean success indicator</li>
23841 * @param {Object} scope The scope in which to call the callback
23842 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23844 load : function(params, reader, callback, scope, arg){
23845 if(this.fireEvent("beforeload", this, params) !== false){
23847 params : params || {},
23849 callback : callback,
23854 callback : this.loadResponse,
23858 Roo.applyIf(o, this.conn);
23859 if(this.activeRequest){
23860 Roo.Ajax.abort(this.activeRequest);
23862 this.activeRequest = Roo.Ajax.request(o);
23864 this.conn.request(o);
23867 callback.call(scope||this, null, arg, false);
23872 loadResponse : function(o, success, response){
23873 delete this.activeRequest;
23875 this.fireEvent("loadexception", this, o, response);
23876 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23881 result = o.reader.read(response);
23883 this.fireEvent("loadexception", this, o, response, e);
23884 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23888 this.fireEvent("load", this, o, o.request.arg);
23889 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23893 update : function(dataSet){
23898 updateResponse : function(dataSet){
23903 * Ext JS Library 1.1.1
23904 * Copyright(c) 2006-2007, Ext JS, LLC.
23906 * Originally Released Under LGPL - original licence link has changed is not relivant.
23909 * <script type="text/javascript">
23913 * @class Roo.data.ScriptTagProxy
23914 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23915 * other than the originating domain of the running page.<br><br>
23917 * <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
23918 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23920 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23921 * source code that is used as the source inside a <script> tag.<br><br>
23923 * In order for the browser to process the returned data, the server must wrap the data object
23924 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23925 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23926 * depending on whether the callback name was passed:
23929 boolean scriptTag = false;
23930 String cb = request.getParameter("callback");
23933 response.setContentType("text/javascript");
23935 response.setContentType("application/x-json");
23937 Writer out = response.getWriter();
23939 out.write(cb + "(");
23941 out.print(dataBlock.toJsonString());
23948 * @param {Object} config A configuration object.
23950 Roo.data.ScriptTagProxy = function(config){
23951 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23952 Roo.apply(this, config);
23953 this.head = document.getElementsByTagName("head")[0];
23956 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23958 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23960 * @cfg {String} url The URL from which to request the data object.
23963 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23967 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23968 * the server the name of the callback function set up by the load call to process the returned data object.
23969 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23970 * javascript output which calls this named function passing the data object as its only parameter.
23972 callbackParam : "callback",
23974 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23975 * name to the request.
23980 * Load data from the configured URL, read the data object into
23981 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23982 * process that block using the passed callback.
23983 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23984 * for the request to the remote server.
23985 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23986 * object into a block of Roo.data.Records.
23987 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23988 * The function must be passed <ul>
23989 * <li>The Record block object</li>
23990 * <li>The "arg" argument from the load function</li>
23991 * <li>A boolean success indicator</li>
23993 * @param {Object} scope The scope in which to call the callback
23994 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23996 load : function(params, reader, callback, scope, arg){
23997 if(this.fireEvent("beforeload", this, params) !== false){
23999 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24001 var url = this.url;
24002 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24004 url += "&_dc=" + (new Date().getTime());
24006 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24009 cb : "stcCallback"+transId,
24010 scriptId : "stcScript"+transId,
24014 callback : callback,
24020 window[trans.cb] = function(o){
24021 conn.handleResponse(o, trans);
24024 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24026 if(this.autoAbort !== false){
24030 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24032 var script = document.createElement("script");
24033 script.setAttribute("src", url);
24034 script.setAttribute("type", "text/javascript");
24035 script.setAttribute("id", trans.scriptId);
24036 this.head.appendChild(script);
24038 this.trans = trans;
24040 callback.call(scope||this, null, arg, false);
24045 isLoading : function(){
24046 return this.trans ? true : false;
24050 * Abort the current server request.
24052 abort : function(){
24053 if(this.isLoading()){
24054 this.destroyTrans(this.trans);
24059 destroyTrans : function(trans, isLoaded){
24060 this.head.removeChild(document.getElementById(trans.scriptId));
24061 clearTimeout(trans.timeoutId);
24063 window[trans.cb] = undefined;
24065 delete window[trans.cb];
24068 // if hasn't been loaded, wait for load to remove it to prevent script error
24069 window[trans.cb] = function(){
24070 window[trans.cb] = undefined;
24072 delete window[trans.cb];
24079 handleResponse : function(o, trans){
24080 this.trans = false;
24081 this.destroyTrans(trans, true);
24084 result = trans.reader.readRecords(o);
24086 this.fireEvent("loadexception", this, o, trans.arg, e);
24087 trans.callback.call(trans.scope||window, null, trans.arg, false);
24090 this.fireEvent("load", this, o, trans.arg);
24091 trans.callback.call(trans.scope||window, result, trans.arg, true);
24095 handleFailure : function(trans){
24096 this.trans = false;
24097 this.destroyTrans(trans, false);
24098 this.fireEvent("loadexception", this, null, trans.arg);
24099 trans.callback.call(trans.scope||window, null, trans.arg, false);
24103 * Ext JS Library 1.1.1
24104 * Copyright(c) 2006-2007, Ext JS, LLC.
24106 * Originally Released Under LGPL - original licence link has changed is not relivant.
24109 * <script type="text/javascript">
24113 * @class Roo.data.JsonReader
24114 * @extends Roo.data.DataReader
24115 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24116 * based on mappings in a provided Roo.data.Record constructor.
24118 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24119 * in the reply previously.
24124 var RecordDef = Roo.data.Record.create([
24125 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24126 {name: 'occupation'} // This field will use "occupation" as the mapping.
24128 var myReader = new Roo.data.JsonReader({
24129 totalProperty: "results", // The property which contains the total dataset size (optional)
24130 root: "rows", // The property which contains an Array of row objects
24131 id: "id" // The property within each row object that provides an ID for the record (optional)
24135 * This would consume a JSON file like this:
24137 { 'results': 2, 'rows': [
24138 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24139 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24142 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24143 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24144 * paged from the remote server.
24145 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24146 * @cfg {String} root name of the property which contains the Array of row objects.
24147 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24148 * @cfg {Array} fields Array of field definition objects
24150 * Create a new JsonReader
24151 * @param {Object} meta Metadata configuration options
24152 * @param {Object} recordType Either an Array of field definition objects,
24153 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24155 Roo.data.JsonReader = function(meta, recordType){
24158 // set some defaults:
24159 Roo.applyIf(meta, {
24160 totalProperty: 'total',
24161 successProperty : 'success',
24166 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24168 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24171 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24172 * Used by Store query builder to append _requestMeta to params.
24175 metaFromRemote : false,
24177 * This method is only used by a DataProxy which has retrieved data from a remote server.
24178 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24179 * @return {Object} data A data block which is used by an Roo.data.Store object as
24180 * a cache of Roo.data.Records.
24182 read : function(response){
24183 var json = response.responseText;
24185 var o = /* eval:var:o */ eval("("+json+")");
24187 throw {message: "JsonReader.read: Json object not found"};
24193 this.metaFromRemote = true;
24194 this.meta = o.metaData;
24195 this.recordType = Roo.data.Record.create(o.metaData.fields);
24196 this.onMetaChange(this.meta, this.recordType, o);
24198 return this.readRecords(o);
24201 // private function a store will implement
24202 onMetaChange : function(meta, recordType, o){
24209 simpleAccess: function(obj, subsc) {
24216 getJsonAccessor: function(){
24218 return function(expr) {
24220 return(re.test(expr))
24221 ? new Function("obj", "return obj." + expr)
24226 return Roo.emptyFn;
24231 * Create a data block containing Roo.data.Records from an XML document.
24232 * @param {Object} o An object which contains an Array of row objects in the property specified
24233 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24234 * which contains the total size of the dataset.
24235 * @return {Object} data A data block which is used by an Roo.data.Store object as
24236 * a cache of Roo.data.Records.
24238 readRecords : function(o){
24240 * After any data loads, the raw JSON data is available for further custom processing.
24244 var s = this.meta, Record = this.recordType,
24245 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24247 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24249 if(s.totalProperty) {
24250 this.getTotal = this.getJsonAccessor(s.totalProperty);
24252 if(s.successProperty) {
24253 this.getSuccess = this.getJsonAccessor(s.successProperty);
24255 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24257 var g = this.getJsonAccessor(s.id);
24258 this.getId = function(rec) {
24260 return (r === undefined || r === "") ? null : r;
24263 this.getId = function(){return null;};
24266 for(var jj = 0; jj < fl; jj++){
24268 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24269 this.ef[jj] = this.getJsonAccessor(map);
24273 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24274 if(s.totalProperty){
24275 var vt = parseInt(this.getTotal(o), 10);
24280 if(s.successProperty){
24281 var vs = this.getSuccess(o);
24282 if(vs === false || vs === 'false'){
24287 for(var i = 0; i < c; i++){
24290 var id = this.getId(n);
24291 for(var j = 0; j < fl; j++){
24293 var v = this.ef[j](n);
24295 Roo.log('missing convert for ' + f.name);
24299 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24301 var record = new Record(values, id);
24303 records[i] = record;
24309 totalRecords : totalRecords
24314 * Ext JS Library 1.1.1
24315 * Copyright(c) 2006-2007, Ext JS, LLC.
24317 * Originally Released Under LGPL - original licence link has changed is not relivant.
24320 * <script type="text/javascript">
24324 * @class Roo.data.XmlReader
24325 * @extends Roo.data.DataReader
24326 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24327 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24329 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24330 * header in the HTTP response must be set to "text/xml".</em>
24334 var RecordDef = Roo.data.Record.create([
24335 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24336 {name: 'occupation'} // This field will use "occupation" as the mapping.
24338 var myReader = new Roo.data.XmlReader({
24339 totalRecords: "results", // The element which contains the total dataset size (optional)
24340 record: "row", // The repeated element which contains row information
24341 id: "id" // The element within the row that provides an ID for the record (optional)
24345 * This would consume an XML file like this:
24349 <results>2</results>
24352 <name>Bill</name>
24353 <occupation>Gardener</occupation>
24357 <name>Ben</name>
24358 <occupation>Horticulturalist</occupation>
24362 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24363 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24364 * paged from the remote server.
24365 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24366 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24367 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24368 * a record identifier value.
24370 * Create a new XmlReader
24371 * @param {Object} meta Metadata configuration options
24372 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24373 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24374 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24376 Roo.data.XmlReader = function(meta, recordType){
24378 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24380 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24382 * This method is only used by a DataProxy which has retrieved data from a remote server.
24383 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24384 * to contain a method called 'responseXML' that returns an XML document object.
24385 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24386 * a cache of Roo.data.Records.
24388 read : function(response){
24389 var doc = response.responseXML;
24391 throw {message: "XmlReader.read: XML Document not available"};
24393 return this.readRecords(doc);
24397 * Create a data block containing Roo.data.Records from an XML document.
24398 * @param {Object} doc A parsed XML document.
24399 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24400 * a cache of Roo.data.Records.
24402 readRecords : function(doc){
24404 * After any data loads/reads, the raw XML Document is available for further custom processing.
24405 * @type XMLDocument
24407 this.xmlData = doc;
24408 var root = doc.documentElement || doc;
24409 var q = Roo.DomQuery;
24410 var recordType = this.recordType, fields = recordType.prototype.fields;
24411 var sid = this.meta.id;
24412 var totalRecords = 0, success = true;
24413 if(this.meta.totalRecords){
24414 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24417 if(this.meta.success){
24418 var sv = q.selectValue(this.meta.success, root, true);
24419 success = sv !== false && sv !== 'false';
24422 var ns = q.select(this.meta.record, root);
24423 for(var i = 0, len = ns.length; i < len; i++) {
24426 var id = sid ? q.selectValue(sid, n) : undefined;
24427 for(var j = 0, jlen = fields.length; j < jlen; j++){
24428 var f = fields.items[j];
24429 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24431 values[f.name] = v;
24433 var record = new recordType(values, id);
24435 records[records.length] = record;
24441 totalRecords : totalRecords || records.length
24446 * Ext JS Library 1.1.1
24447 * Copyright(c) 2006-2007, Ext JS, LLC.
24449 * Originally Released Under LGPL - original licence link has changed is not relivant.
24452 * <script type="text/javascript">
24456 * @class Roo.data.ArrayReader
24457 * @extends Roo.data.DataReader
24458 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24459 * Each element of that Array represents a row of data fields. The
24460 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24461 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24465 var RecordDef = Roo.data.Record.create([
24466 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24467 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24469 var myReader = new Roo.data.ArrayReader({
24470 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24474 * This would consume an Array like this:
24476 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24478 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24480 * Create a new JsonReader
24481 * @param {Object} meta Metadata configuration options.
24482 * @param {Object} recordType Either an Array of field definition objects
24483 * as specified to {@link Roo.data.Record#create},
24484 * or an {@link Roo.data.Record} object
24485 * created using {@link Roo.data.Record#create}.
24487 Roo.data.ArrayReader = function(meta, recordType){
24488 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24491 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24493 * Create a data block containing Roo.data.Records from an XML document.
24494 * @param {Object} o An Array of row objects which represents the dataset.
24495 * @return {Object} data A data block which is used by an Roo.data.Store object as
24496 * a cache of Roo.data.Records.
24498 readRecords : function(o){
24499 var sid = this.meta ? this.meta.id : null;
24500 var recordType = this.recordType, fields = recordType.prototype.fields;
24503 for(var i = 0; i < root.length; i++){
24506 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24507 for(var j = 0, jlen = fields.length; j < jlen; j++){
24508 var f = fields.items[j];
24509 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24510 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24512 values[f.name] = v;
24514 var record = new recordType(values, id);
24516 records[records.length] = record;
24520 totalRecords : records.length
24525 * Ext JS Library 1.1.1
24526 * Copyright(c) 2006-2007, Ext JS, LLC.
24528 * Originally Released Under LGPL - original licence link has changed is not relivant.
24531 * <script type="text/javascript">
24536 * @class Roo.data.Tree
24537 * @extends Roo.util.Observable
24538 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24539 * in the tree have most standard DOM functionality.
24541 * @param {Node} root (optional) The root node
24543 Roo.data.Tree = function(root){
24544 this.nodeHash = {};
24546 * The root node for this tree
24551 this.setRootNode(root);
24556 * Fires when a new child node is appended to a node in this tree.
24557 * @param {Tree} tree The owner tree
24558 * @param {Node} parent The parent node
24559 * @param {Node} node The newly appended node
24560 * @param {Number} index The index of the newly appended node
24565 * Fires when a child node is removed from a node in this tree.
24566 * @param {Tree} tree The owner tree
24567 * @param {Node} parent The parent node
24568 * @param {Node} node The child node removed
24573 * Fires when a node is moved to a new location in the tree
24574 * @param {Tree} tree The owner tree
24575 * @param {Node} node The node moved
24576 * @param {Node} oldParent The old parent of this node
24577 * @param {Node} newParent The new parent of this node
24578 * @param {Number} index The index it was moved to
24583 * Fires when a new child node is inserted in a node in this tree.
24584 * @param {Tree} tree The owner tree
24585 * @param {Node} parent The parent node
24586 * @param {Node} node The child node inserted
24587 * @param {Node} refNode The child node the node was inserted before
24591 * @event beforeappend
24592 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24593 * @param {Tree} tree The owner tree
24594 * @param {Node} parent The parent node
24595 * @param {Node} node The child node to be appended
24597 "beforeappend" : true,
24599 * @event beforeremove
24600 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24601 * @param {Tree} tree The owner tree
24602 * @param {Node} parent The parent node
24603 * @param {Node} node The child node to be removed
24605 "beforeremove" : true,
24607 * @event beforemove
24608 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24609 * @param {Tree} tree The owner tree
24610 * @param {Node} node The node being moved
24611 * @param {Node} oldParent The parent of the node
24612 * @param {Node} newParent The new parent the node is moving to
24613 * @param {Number} index The index it is being moved to
24615 "beforemove" : true,
24617 * @event beforeinsert
24618 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24619 * @param {Tree} tree The owner tree
24620 * @param {Node} parent The parent node
24621 * @param {Node} node The child node to be inserted
24622 * @param {Node} refNode The child node the node is being inserted before
24624 "beforeinsert" : true
24627 Roo.data.Tree.superclass.constructor.call(this);
24630 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24631 pathSeparator: "/",
24633 proxyNodeEvent : function(){
24634 return this.fireEvent.apply(this, arguments);
24638 * Returns the root node for this tree.
24641 getRootNode : function(){
24646 * Sets the root node for this tree.
24647 * @param {Node} node
24650 setRootNode : function(node){
24652 node.ownerTree = this;
24653 node.isRoot = true;
24654 this.registerNode(node);
24659 * Gets a node in this tree by its id.
24660 * @param {String} id
24663 getNodeById : function(id){
24664 return this.nodeHash[id];
24667 registerNode : function(node){
24668 this.nodeHash[node.id] = node;
24671 unregisterNode : function(node){
24672 delete this.nodeHash[node.id];
24675 toString : function(){
24676 return "[Tree"+(this.id?" "+this.id:"")+"]";
24681 * @class Roo.data.Node
24682 * @extends Roo.util.Observable
24683 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24684 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24686 * @param {Object} attributes The attributes/config for the node
24688 Roo.data.Node = function(attributes){
24690 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24693 this.attributes = attributes || {};
24694 this.leaf = this.attributes.leaf;
24696 * The node id. @type String
24698 this.id = this.attributes.id;
24700 this.id = Roo.id(null, "ynode-");
24701 this.attributes.id = this.id;
24706 * All child nodes of this node. @type Array
24708 this.childNodes = [];
24709 if(!this.childNodes.indexOf){ // indexOf is a must
24710 this.childNodes.indexOf = function(o){
24711 for(var i = 0, len = this.length; i < len; i++){
24720 * The parent node for this node. @type Node
24722 this.parentNode = null;
24724 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24726 this.firstChild = null;
24728 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24730 this.lastChild = null;
24732 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24734 this.previousSibling = null;
24736 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24738 this.nextSibling = null;
24743 * Fires when a new child node is appended
24744 * @param {Tree} tree The owner tree
24745 * @param {Node} this This node
24746 * @param {Node} node The newly appended node
24747 * @param {Number} index The index of the newly appended node
24752 * Fires when a child node is removed
24753 * @param {Tree} tree The owner tree
24754 * @param {Node} this This node
24755 * @param {Node} node The removed node
24760 * Fires when this node is moved to a new location in the tree
24761 * @param {Tree} tree The owner tree
24762 * @param {Node} this This node
24763 * @param {Node} oldParent The old parent of this node
24764 * @param {Node} newParent The new parent of this node
24765 * @param {Number} index The index it was moved to
24770 * Fires when a new child node is inserted.
24771 * @param {Tree} tree The owner tree
24772 * @param {Node} this This node
24773 * @param {Node} node The child node inserted
24774 * @param {Node} refNode The child node the node was inserted before
24778 * @event beforeappend
24779 * Fires before a new child is appended, return false to cancel the append.
24780 * @param {Tree} tree The owner tree
24781 * @param {Node} this This node
24782 * @param {Node} node The child node to be appended
24784 "beforeappend" : true,
24786 * @event beforeremove
24787 * Fires before a child is removed, return false to cancel the remove.
24788 * @param {Tree} tree The owner tree
24789 * @param {Node} this This node
24790 * @param {Node} node The child node to be removed
24792 "beforeremove" : true,
24794 * @event beforemove
24795 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24796 * @param {Tree} tree The owner tree
24797 * @param {Node} this This node
24798 * @param {Node} oldParent The parent of this node
24799 * @param {Node} newParent The new parent this node is moving to
24800 * @param {Number} index The index it is being moved to
24802 "beforemove" : true,
24804 * @event beforeinsert
24805 * Fires before a new child is inserted, return false to cancel the insert.
24806 * @param {Tree} tree The owner tree
24807 * @param {Node} this This node
24808 * @param {Node} node The child node to be inserted
24809 * @param {Node} refNode The child node the node is being inserted before
24811 "beforeinsert" : true
24813 this.listeners = this.attributes.listeners;
24814 Roo.data.Node.superclass.constructor.call(this);
24817 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24818 fireEvent : function(evtName){
24819 // first do standard event for this node
24820 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24823 // then bubble it up to the tree if the event wasn't cancelled
24824 var ot = this.getOwnerTree();
24826 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24834 * Returns true if this node is a leaf
24835 * @return {Boolean}
24837 isLeaf : function(){
24838 return this.leaf === true;
24842 setFirstChild : function(node){
24843 this.firstChild = node;
24847 setLastChild : function(node){
24848 this.lastChild = node;
24853 * Returns true if this node is the last child of its parent
24854 * @return {Boolean}
24856 isLast : function(){
24857 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24861 * Returns true if this node is the first child of its parent
24862 * @return {Boolean}
24864 isFirst : function(){
24865 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24868 hasChildNodes : function(){
24869 return !this.isLeaf() && this.childNodes.length > 0;
24873 * Insert node(s) as the last child node of this node.
24874 * @param {Node/Array} node The node or Array of nodes to append
24875 * @return {Node} The appended node if single append, or null if an array was passed
24877 appendChild : function(node){
24879 if(node instanceof Array){
24881 }else if(arguments.length > 1){
24884 // if passed an array or multiple args do them one by one
24886 for(var i = 0, len = multi.length; i < len; i++) {
24887 this.appendChild(multi[i]);
24890 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24893 var index = this.childNodes.length;
24894 var oldParent = node.parentNode;
24895 // it's a move, make sure we move it cleanly
24897 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24900 oldParent.removeChild(node);
24902 index = this.childNodes.length;
24904 this.setFirstChild(node);
24906 this.childNodes.push(node);
24907 node.parentNode = this;
24908 var ps = this.childNodes[index-1];
24910 node.previousSibling = ps;
24911 ps.nextSibling = node;
24913 node.previousSibling = null;
24915 node.nextSibling = null;
24916 this.setLastChild(node);
24917 node.setOwnerTree(this.getOwnerTree());
24918 this.fireEvent("append", this.ownerTree, this, node, index);
24920 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24927 * Removes a child node from this node.
24928 * @param {Node} node The node to remove
24929 * @return {Node} The removed node
24931 removeChild : function(node){
24932 var index = this.childNodes.indexOf(node);
24936 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24940 // remove it from childNodes collection
24941 this.childNodes.splice(index, 1);
24944 if(node.previousSibling){
24945 node.previousSibling.nextSibling = node.nextSibling;
24947 if(node.nextSibling){
24948 node.nextSibling.previousSibling = node.previousSibling;
24951 // update child refs
24952 if(this.firstChild == node){
24953 this.setFirstChild(node.nextSibling);
24955 if(this.lastChild == node){
24956 this.setLastChild(node.previousSibling);
24959 node.setOwnerTree(null);
24960 // clear any references from the node
24961 node.parentNode = null;
24962 node.previousSibling = null;
24963 node.nextSibling = null;
24964 this.fireEvent("remove", this.ownerTree, this, node);
24969 * Inserts the first node before the second node in this nodes childNodes collection.
24970 * @param {Node} node The node to insert
24971 * @param {Node} refNode The node to insert before (if null the node is appended)
24972 * @return {Node} The inserted node
24974 insertBefore : function(node, refNode){
24975 if(!refNode){ // like standard Dom, refNode can be null for append
24976 return this.appendChild(node);
24979 if(node == refNode){
24983 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24986 var index = this.childNodes.indexOf(refNode);
24987 var oldParent = node.parentNode;
24988 var refIndex = index;
24990 // when moving internally, indexes will change after remove
24991 if(oldParent == this && this.childNodes.indexOf(node) < index){
24995 // it's a move, make sure we move it cleanly
24997 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25000 oldParent.removeChild(node);
25003 this.setFirstChild(node);
25005 this.childNodes.splice(refIndex, 0, node);
25006 node.parentNode = this;
25007 var ps = this.childNodes[refIndex-1];
25009 node.previousSibling = ps;
25010 ps.nextSibling = node;
25012 node.previousSibling = null;
25014 node.nextSibling = refNode;
25015 refNode.previousSibling = node;
25016 node.setOwnerTree(this.getOwnerTree());
25017 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25019 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25025 * Returns the child node at the specified index.
25026 * @param {Number} index
25029 item : function(index){
25030 return this.childNodes[index];
25034 * Replaces one child node in this node with another.
25035 * @param {Node} newChild The replacement node
25036 * @param {Node} oldChild The node to replace
25037 * @return {Node} The replaced node
25039 replaceChild : function(newChild, oldChild){
25040 this.insertBefore(newChild, oldChild);
25041 this.removeChild(oldChild);
25046 * Returns the index of a child node
25047 * @param {Node} node
25048 * @return {Number} The index of the node or -1 if it was not found
25050 indexOf : function(child){
25051 return this.childNodes.indexOf(child);
25055 * Returns the tree this node is in.
25058 getOwnerTree : function(){
25059 // if it doesn't have one, look for one
25060 if(!this.ownerTree){
25064 this.ownerTree = p.ownerTree;
25070 return this.ownerTree;
25074 * Returns depth of this node (the root node has a depth of 0)
25077 getDepth : function(){
25080 while(p.parentNode){
25088 setOwnerTree : function(tree){
25089 // if it's move, we need to update everyone
25090 if(tree != this.ownerTree){
25091 if(this.ownerTree){
25092 this.ownerTree.unregisterNode(this);
25094 this.ownerTree = tree;
25095 var cs = this.childNodes;
25096 for(var i = 0, len = cs.length; i < len; i++) {
25097 cs[i].setOwnerTree(tree);
25100 tree.registerNode(this);
25106 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25107 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25108 * @return {String} The path
25110 getPath : function(attr){
25111 attr = attr || "id";
25112 var p = this.parentNode;
25113 var b = [this.attributes[attr]];
25115 b.unshift(p.attributes[attr]);
25118 var sep = this.getOwnerTree().pathSeparator;
25119 return sep + b.join(sep);
25123 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25124 * function call will be the scope provided or the current node. The arguments to the function
25125 * will be the args provided or the current node. If the function returns false at any point,
25126 * the bubble is stopped.
25127 * @param {Function} fn The function to call
25128 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25129 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25131 bubble : function(fn, scope, args){
25134 if(fn.call(scope || p, args || p) === false){
25142 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25143 * function call will be the scope provided or the current node. The arguments to the function
25144 * will be the args provided or the current node. If the function returns false at any point,
25145 * the cascade is stopped on that branch.
25146 * @param {Function} fn The function to call
25147 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25148 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25150 cascade : function(fn, scope, args){
25151 if(fn.call(scope || this, args || this) !== false){
25152 var cs = this.childNodes;
25153 for(var i = 0, len = cs.length; i < len; i++) {
25154 cs[i].cascade(fn, scope, args);
25160 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25161 * function call will be the scope provided or the current node. The arguments to the function
25162 * will be the args provided or the current node. If the function returns false at any point,
25163 * the iteration stops.
25164 * @param {Function} fn The function to call
25165 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25166 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25168 eachChild : function(fn, scope, args){
25169 var cs = this.childNodes;
25170 for(var i = 0, len = cs.length; i < len; i++) {
25171 if(fn.call(scope || this, args || cs[i]) === false){
25178 * Finds the first child that has the attribute with the specified value.
25179 * @param {String} attribute The attribute name
25180 * @param {Mixed} value The value to search for
25181 * @return {Node} The found child or null if none was found
25183 findChild : function(attribute, value){
25184 var cs = this.childNodes;
25185 for(var i = 0, len = cs.length; i < len; i++) {
25186 if(cs[i].attributes[attribute] == value){
25194 * Finds the first child by a custom function. The child matches if the function passed
25196 * @param {Function} fn
25197 * @param {Object} scope (optional)
25198 * @return {Node} The found child or null if none was found
25200 findChildBy : function(fn, scope){
25201 var cs = this.childNodes;
25202 for(var i = 0, len = cs.length; i < len; i++) {
25203 if(fn.call(scope||cs[i], cs[i]) === true){
25211 * Sorts this nodes children using the supplied sort function
25212 * @param {Function} fn
25213 * @param {Object} scope (optional)
25215 sort : function(fn, scope){
25216 var cs = this.childNodes;
25217 var len = cs.length;
25219 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25221 for(var i = 0; i < len; i++){
25223 n.previousSibling = cs[i-1];
25224 n.nextSibling = cs[i+1];
25226 this.setFirstChild(n);
25229 this.setLastChild(n);
25236 * Returns true if this node is an ancestor (at any point) of the passed node.
25237 * @param {Node} node
25238 * @return {Boolean}
25240 contains : function(node){
25241 return node.isAncestor(this);
25245 * Returns true if the passed node is an ancestor (at any point) of this node.
25246 * @param {Node} node
25247 * @return {Boolean}
25249 isAncestor : function(node){
25250 var p = this.parentNode;
25260 toString : function(){
25261 return "[Node"+(this.id?" "+this.id:"")+"]";
25265 * Ext JS Library 1.1.1
25266 * Copyright(c) 2006-2007, Ext JS, LLC.
25268 * Originally Released Under LGPL - original licence link has changed is not relivant.
25271 * <script type="text/javascript">
25276 * @extends Roo.Element
25277 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25278 * automatic maintaining of shadow/shim positions.
25279 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25280 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25281 * you can pass a string with a CSS class name. False turns off the shadow.
25282 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25283 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25284 * @cfg {String} cls CSS class to add to the element
25285 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25286 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25288 * @param {Object} config An object with config options.
25289 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25292 Roo.Layer = function(config, existingEl){
25293 config = config || {};
25294 var dh = Roo.DomHelper;
25295 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25297 this.dom = Roo.getDom(existingEl);
25300 var o = config.dh || {tag: "div", cls: "x-layer"};
25301 this.dom = dh.append(pel, o);
25304 this.addClass(config.cls);
25306 this.constrain = config.constrain !== false;
25307 this.visibilityMode = Roo.Element.VISIBILITY;
25309 this.id = this.dom.id = config.id;
25311 this.id = Roo.id(this.dom);
25313 this.zindex = config.zindex || this.getZIndex();
25314 this.position("absolute", this.zindex);
25316 this.shadowOffset = config.shadowOffset || 4;
25317 this.shadow = new Roo.Shadow({
25318 offset : this.shadowOffset,
25319 mode : config.shadow
25322 this.shadowOffset = 0;
25324 this.useShim = config.shim !== false && Roo.useShims;
25325 this.useDisplay = config.useDisplay;
25329 var supr = Roo.Element.prototype;
25331 // shims are shared among layer to keep from having 100 iframes
25334 Roo.extend(Roo.Layer, Roo.Element, {
25336 getZIndex : function(){
25337 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25340 getShim : function(){
25347 var shim = shims.shift();
25349 shim = this.createShim();
25350 shim.enableDisplayMode('block');
25351 shim.dom.style.display = 'none';
25352 shim.dom.style.visibility = 'visible';
25354 var pn = this.dom.parentNode;
25355 if(shim.dom.parentNode != pn){
25356 pn.insertBefore(shim.dom, this.dom);
25358 shim.setStyle('z-index', this.getZIndex()-2);
25363 hideShim : function(){
25365 this.shim.setDisplayed(false);
25366 shims.push(this.shim);
25371 disableShadow : function(){
25373 this.shadowDisabled = true;
25374 this.shadow.hide();
25375 this.lastShadowOffset = this.shadowOffset;
25376 this.shadowOffset = 0;
25380 enableShadow : function(show){
25382 this.shadowDisabled = false;
25383 this.shadowOffset = this.lastShadowOffset;
25384 delete this.lastShadowOffset;
25392 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25393 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25394 sync : function(doShow){
25395 var sw = this.shadow;
25396 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25397 var sh = this.getShim();
25399 var w = this.getWidth(),
25400 h = this.getHeight();
25402 var l = this.getLeft(true),
25403 t = this.getTop(true);
25405 if(sw && !this.shadowDisabled){
25406 if(doShow && !sw.isVisible()){
25409 sw.realign(l, t, w, h);
25415 // fit the shim behind the shadow, so it is shimmed too
25416 var a = sw.adjusts, s = sh.dom.style;
25417 s.left = (Math.min(l, l+a.l))+"px";
25418 s.top = (Math.min(t, t+a.t))+"px";
25419 s.width = (w+a.w)+"px";
25420 s.height = (h+a.h)+"px";
25427 sh.setLeftTop(l, t);
25434 destroy : function(){
25437 this.shadow.hide();
25439 this.removeAllListeners();
25440 var pn = this.dom.parentNode;
25442 pn.removeChild(this.dom);
25444 Roo.Element.uncache(this.id);
25447 remove : function(){
25452 beginUpdate : function(){
25453 this.updating = true;
25457 endUpdate : function(){
25458 this.updating = false;
25463 hideUnders : function(negOffset){
25465 this.shadow.hide();
25471 constrainXY : function(){
25472 if(this.constrain){
25473 var vw = Roo.lib.Dom.getViewWidth(),
25474 vh = Roo.lib.Dom.getViewHeight();
25475 var s = Roo.get(document).getScroll();
25477 var xy = this.getXY();
25478 var x = xy[0], y = xy[1];
25479 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25480 // only move it if it needs it
25482 // first validate right/bottom
25483 if((x + w) > vw+s.left){
25484 x = vw - w - this.shadowOffset;
25487 if((y + h) > vh+s.top){
25488 y = vh - h - this.shadowOffset;
25491 // then make sure top/left isn't negative
25502 var ay = this.avoidY;
25503 if(y <= ay && (y+h) >= ay){
25509 supr.setXY.call(this, xy);
25515 isVisible : function(){
25516 return this.visible;
25520 showAction : function(){
25521 this.visible = true; // track visibility to prevent getStyle calls
25522 if(this.useDisplay === true){
25523 this.setDisplayed("");
25524 }else if(this.lastXY){
25525 supr.setXY.call(this, this.lastXY);
25526 }else if(this.lastLT){
25527 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25532 hideAction : function(){
25533 this.visible = false;
25534 if(this.useDisplay === true){
25535 this.setDisplayed(false);
25537 this.setLeftTop(-10000,-10000);
25541 // overridden Element method
25542 setVisible : function(v, a, d, c, e){
25547 var cb = function(){
25552 }.createDelegate(this);
25553 supr.setVisible.call(this, true, true, d, cb, e);
25556 this.hideUnders(true);
25565 }.createDelegate(this);
25567 supr.setVisible.call(this, v, a, d, cb, e);
25576 storeXY : function(xy){
25577 delete this.lastLT;
25581 storeLeftTop : function(left, top){
25582 delete this.lastXY;
25583 this.lastLT = [left, top];
25587 beforeFx : function(){
25588 this.beforeAction();
25589 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25593 afterFx : function(){
25594 Roo.Layer.superclass.afterFx.apply(this, arguments);
25595 this.sync(this.isVisible());
25599 beforeAction : function(){
25600 if(!this.updating && this.shadow){
25601 this.shadow.hide();
25605 // overridden Element method
25606 setLeft : function(left){
25607 this.storeLeftTop(left, this.getTop(true));
25608 supr.setLeft.apply(this, arguments);
25612 setTop : function(top){
25613 this.storeLeftTop(this.getLeft(true), top);
25614 supr.setTop.apply(this, arguments);
25618 setLeftTop : function(left, top){
25619 this.storeLeftTop(left, top);
25620 supr.setLeftTop.apply(this, arguments);
25624 setXY : function(xy, a, d, c, e){
25626 this.beforeAction();
25628 var cb = this.createCB(c);
25629 supr.setXY.call(this, xy, a, d, cb, e);
25636 createCB : function(c){
25647 // overridden Element method
25648 setX : function(x, a, d, c, e){
25649 this.setXY([x, this.getY()], a, d, c, e);
25652 // overridden Element method
25653 setY : function(y, a, d, c, e){
25654 this.setXY([this.getX(), y], a, d, c, e);
25657 // overridden Element method
25658 setSize : function(w, h, a, d, c, e){
25659 this.beforeAction();
25660 var cb = this.createCB(c);
25661 supr.setSize.call(this, w, h, a, d, cb, e);
25667 // overridden Element method
25668 setWidth : function(w, a, d, c, e){
25669 this.beforeAction();
25670 var cb = this.createCB(c);
25671 supr.setWidth.call(this, w, a, d, cb, e);
25677 // overridden Element method
25678 setHeight : function(h, a, d, c, e){
25679 this.beforeAction();
25680 var cb = this.createCB(c);
25681 supr.setHeight.call(this, h, a, d, cb, e);
25687 // overridden Element method
25688 setBounds : function(x, y, w, h, a, d, c, e){
25689 this.beforeAction();
25690 var cb = this.createCB(c);
25692 this.storeXY([x, y]);
25693 supr.setXY.call(this, [x, y]);
25694 supr.setSize.call(this, w, h, a, d, cb, e);
25697 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25703 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25704 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25705 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25706 * @param {Number} zindex The new z-index to set
25707 * @return {this} The Layer
25709 setZIndex : function(zindex){
25710 this.zindex = zindex;
25711 this.setStyle("z-index", zindex + 2);
25713 this.shadow.setZIndex(zindex + 1);
25716 this.shim.setStyle("z-index", zindex);
25722 * Ext JS Library 1.1.1
25723 * Copyright(c) 2006-2007, Ext JS, LLC.
25725 * Originally Released Under LGPL - original licence link has changed is not relivant.
25728 * <script type="text/javascript">
25733 * @class Roo.Shadow
25734 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25735 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25736 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25738 * Create a new Shadow
25739 * @param {Object} config The config object
25741 Roo.Shadow = function(config){
25742 Roo.apply(this, config);
25743 if(typeof this.mode != "string"){
25744 this.mode = this.defaultMode;
25746 var o = this.offset, a = {h: 0};
25747 var rad = Math.floor(this.offset/2);
25748 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25754 a.l -= this.offset + rad;
25755 a.t -= this.offset + rad;
25766 a.l -= (this.offset - rad);
25767 a.t -= this.offset + rad;
25769 a.w -= (this.offset - rad)*2;
25780 a.l -= (this.offset - rad);
25781 a.t -= (this.offset - rad);
25783 a.w -= (this.offset + rad + 1);
25784 a.h -= (this.offset + rad);
25793 Roo.Shadow.prototype = {
25795 * @cfg {String} mode
25796 * The shadow display mode. Supports the following options:<br />
25797 * sides: Shadow displays on both sides and bottom only<br />
25798 * frame: Shadow displays equally on all four sides<br />
25799 * drop: Traditional bottom-right drop shadow (default)
25802 * @cfg {String} offset
25803 * The number of pixels to offset the shadow from the element (defaults to 4)
25808 defaultMode: "drop",
25811 * Displays the shadow under the target element
25812 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25814 show : function(target){
25815 target = Roo.get(target);
25817 this.el = Roo.Shadow.Pool.pull();
25818 if(this.el.dom.nextSibling != target.dom){
25819 this.el.insertBefore(target);
25822 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25824 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25827 target.getLeft(true),
25828 target.getTop(true),
25832 this.el.dom.style.display = "block";
25836 * Returns true if the shadow is visible, else false
25838 isVisible : function(){
25839 return this.el ? true : false;
25843 * Direct alignment when values are already available. Show must be called at least once before
25844 * calling this method to ensure it is initialized.
25845 * @param {Number} left The target element left position
25846 * @param {Number} top The target element top position
25847 * @param {Number} width The target element width
25848 * @param {Number} height The target element height
25850 realign : function(l, t, w, h){
25854 var a = this.adjusts, d = this.el.dom, s = d.style;
25856 s.left = (l+a.l)+"px";
25857 s.top = (t+a.t)+"px";
25858 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25860 if(s.width != sws || s.height != shs){
25864 var cn = d.childNodes;
25865 var sww = Math.max(0, (sw-12))+"px";
25866 cn[0].childNodes[1].style.width = sww;
25867 cn[1].childNodes[1].style.width = sww;
25868 cn[2].childNodes[1].style.width = sww;
25869 cn[1].style.height = Math.max(0, (sh-12))+"px";
25875 * Hides this shadow
25879 this.el.dom.style.display = "none";
25880 Roo.Shadow.Pool.push(this.el);
25886 * Adjust the z-index of this shadow
25887 * @param {Number} zindex The new z-index
25889 setZIndex : function(z){
25892 this.el.setStyle("z-index", z);
25897 // Private utility class that manages the internal Shadow cache
25898 Roo.Shadow.Pool = function(){
25900 var markup = Roo.isIE ?
25901 '<div class="x-ie-shadow"></div>' :
25902 '<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>';
25905 var sh = p.shift();
25907 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25908 sh.autoBoxAdjust = false;
25913 push : function(sh){
25919 * Ext JS Library 1.1.1
25920 * Copyright(c) 2006-2007, Ext JS, LLC.
25922 * Originally Released Under LGPL - original licence link has changed is not relivant.
25925 * <script type="text/javascript">
25930 * @class Roo.SplitBar
25931 * @extends Roo.util.Observable
25932 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25936 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25937 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25938 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25939 split.minSize = 100;
25940 split.maxSize = 600;
25941 split.animate = true;
25942 split.on('moved', splitterMoved);
25945 * Create a new SplitBar
25946 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25947 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25948 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25949 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25950 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25951 position of the SplitBar).
25953 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25956 this.el = Roo.get(dragElement, true);
25957 this.el.dom.unselectable = "on";
25959 this.resizingEl = Roo.get(resizingElement, true);
25963 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25964 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25967 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25970 * The minimum size of the resizing element. (Defaults to 0)
25976 * The maximum size of the resizing element. (Defaults to 2000)
25979 this.maxSize = 2000;
25982 * Whether to animate the transition to the new size
25985 this.animate = false;
25988 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25991 this.useShim = false;
25996 if(!existingProxy){
25998 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26000 this.proxy = Roo.get(existingProxy).dom;
26003 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26006 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26009 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26012 this.dragSpecs = {};
26015 * @private The adapter to use to positon and resize elements
26017 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26018 this.adapter.init(this);
26020 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26022 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26023 this.el.addClass("x-splitbar-h");
26026 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26027 this.el.addClass("x-splitbar-v");
26033 * Fires when the splitter is moved (alias for {@link #event-moved})
26034 * @param {Roo.SplitBar} this
26035 * @param {Number} newSize the new width or height
26040 * Fires when the splitter is moved
26041 * @param {Roo.SplitBar} this
26042 * @param {Number} newSize the new width or height
26046 * @event beforeresize
26047 * Fires before the splitter is dragged
26048 * @param {Roo.SplitBar} this
26050 "beforeresize" : true,
26052 "beforeapply" : true
26055 Roo.util.Observable.call(this);
26058 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26059 onStartProxyDrag : function(x, y){
26060 this.fireEvent("beforeresize", this);
26062 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26064 o.enableDisplayMode("block");
26065 // all splitbars share the same overlay
26066 Roo.SplitBar.prototype.overlay = o;
26068 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26069 this.overlay.show();
26070 Roo.get(this.proxy).setDisplayed("block");
26071 var size = this.adapter.getElementSize(this);
26072 this.activeMinSize = this.getMinimumSize();;
26073 this.activeMaxSize = this.getMaximumSize();;
26074 var c1 = size - this.activeMinSize;
26075 var c2 = Math.max(this.activeMaxSize - size, 0);
26076 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26077 this.dd.resetConstraints();
26078 this.dd.setXConstraint(
26079 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26080 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26082 this.dd.setYConstraint(0, 0);
26084 this.dd.resetConstraints();
26085 this.dd.setXConstraint(0, 0);
26086 this.dd.setYConstraint(
26087 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26088 this.placement == Roo.SplitBar.TOP ? c2 : c1
26091 this.dragSpecs.startSize = size;
26092 this.dragSpecs.startPoint = [x, y];
26093 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26097 * @private Called after the drag operation by the DDProxy
26099 onEndProxyDrag : function(e){
26100 Roo.get(this.proxy).setDisplayed(false);
26101 var endPoint = Roo.lib.Event.getXY(e);
26103 this.overlay.hide();
26106 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26107 newSize = this.dragSpecs.startSize +
26108 (this.placement == Roo.SplitBar.LEFT ?
26109 endPoint[0] - this.dragSpecs.startPoint[0] :
26110 this.dragSpecs.startPoint[0] - endPoint[0]
26113 newSize = this.dragSpecs.startSize +
26114 (this.placement == Roo.SplitBar.TOP ?
26115 endPoint[1] - this.dragSpecs.startPoint[1] :
26116 this.dragSpecs.startPoint[1] - endPoint[1]
26119 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26120 if(newSize != this.dragSpecs.startSize){
26121 if(this.fireEvent('beforeapply', this, newSize) !== false){
26122 this.adapter.setElementSize(this, newSize);
26123 this.fireEvent("moved", this, newSize);
26124 this.fireEvent("resize", this, newSize);
26130 * Get the adapter this SplitBar uses
26131 * @return The adapter object
26133 getAdapter : function(){
26134 return this.adapter;
26138 * Set the adapter this SplitBar uses
26139 * @param {Object} adapter A SplitBar adapter object
26141 setAdapter : function(adapter){
26142 this.adapter = adapter;
26143 this.adapter.init(this);
26147 * Gets the minimum size for the resizing element
26148 * @return {Number} The minimum size
26150 getMinimumSize : function(){
26151 return this.minSize;
26155 * Sets the minimum size for the resizing element
26156 * @param {Number} minSize The minimum size
26158 setMinimumSize : function(minSize){
26159 this.minSize = minSize;
26163 * Gets the maximum size for the resizing element
26164 * @return {Number} The maximum size
26166 getMaximumSize : function(){
26167 return this.maxSize;
26171 * Sets the maximum size for the resizing element
26172 * @param {Number} maxSize The maximum size
26174 setMaximumSize : function(maxSize){
26175 this.maxSize = maxSize;
26179 * Sets the initialize size for the resizing element
26180 * @param {Number} size The initial size
26182 setCurrentSize : function(size){
26183 var oldAnimate = this.animate;
26184 this.animate = false;
26185 this.adapter.setElementSize(this, size);
26186 this.animate = oldAnimate;
26190 * Destroy this splitbar.
26191 * @param {Boolean} removeEl True to remove the element
26193 destroy : function(removeEl){
26195 this.shim.remove();
26198 this.proxy.parentNode.removeChild(this.proxy);
26206 * @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.
26208 Roo.SplitBar.createProxy = function(dir){
26209 var proxy = new Roo.Element(document.createElement("div"));
26210 proxy.unselectable();
26211 var cls = 'x-splitbar-proxy';
26212 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26213 document.body.appendChild(proxy.dom);
26218 * @class Roo.SplitBar.BasicLayoutAdapter
26219 * Default Adapter. It assumes the splitter and resizing element are not positioned
26220 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26222 Roo.SplitBar.BasicLayoutAdapter = function(){
26225 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26226 // do nothing for now
26227 init : function(s){
26231 * Called before drag operations to get the current size of the resizing element.
26232 * @param {Roo.SplitBar} s The SplitBar using this adapter
26234 getElementSize : function(s){
26235 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26236 return s.resizingEl.getWidth();
26238 return s.resizingEl.getHeight();
26243 * Called after drag operations to set the size of the resizing element.
26244 * @param {Roo.SplitBar} s The SplitBar using this adapter
26245 * @param {Number} newSize The new size to set
26246 * @param {Function} onComplete A function to be invoked when resizing is complete
26248 setElementSize : function(s, newSize, onComplete){
26249 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26251 s.resizingEl.setWidth(newSize);
26253 onComplete(s, newSize);
26256 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26261 s.resizingEl.setHeight(newSize);
26263 onComplete(s, newSize);
26266 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26273 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26274 * @extends Roo.SplitBar.BasicLayoutAdapter
26275 * Adapter that moves the splitter element to align with the resized sizing element.
26276 * Used with an absolute positioned SplitBar.
26277 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26278 * document.body, make sure you assign an id to the body element.
26280 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26281 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26282 this.container = Roo.get(container);
26285 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26286 init : function(s){
26287 this.basic.init(s);
26290 getElementSize : function(s){
26291 return this.basic.getElementSize(s);
26294 setElementSize : function(s, newSize, onComplete){
26295 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26298 moveSplitter : function(s){
26299 var yes = Roo.SplitBar;
26300 switch(s.placement){
26302 s.el.setX(s.resizingEl.getRight());
26305 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26308 s.el.setY(s.resizingEl.getBottom());
26311 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26318 * Orientation constant - Create a vertical SplitBar
26322 Roo.SplitBar.VERTICAL = 1;
26325 * Orientation constant - Create a horizontal SplitBar
26329 Roo.SplitBar.HORIZONTAL = 2;
26332 * Placement constant - The resizing element is to the left of the splitter element
26336 Roo.SplitBar.LEFT = 1;
26339 * Placement constant - The resizing element is to the right of the splitter element
26343 Roo.SplitBar.RIGHT = 2;
26346 * Placement constant - The resizing element is positioned above the splitter element
26350 Roo.SplitBar.TOP = 3;
26353 * Placement constant - The resizing element is positioned under splitter element
26357 Roo.SplitBar.BOTTOM = 4;
26360 * Ext JS Library 1.1.1
26361 * Copyright(c) 2006-2007, Ext JS, LLC.
26363 * Originally Released Under LGPL - original licence link has changed is not relivant.
26366 * <script type="text/javascript">
26371 * @extends Roo.util.Observable
26372 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26373 * This class also supports single and multi selection modes. <br>
26374 * Create a data model bound view:
26376 var store = new Roo.data.Store(...);
26378 var view = new Roo.View({
26380 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26382 singleSelect: true,
26383 selectedClass: "ydataview-selected",
26387 // listen for node click?
26388 view.on("click", function(vw, index, node, e){
26389 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26393 dataModel.load("foobar.xml");
26395 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26397 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26398 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26400 * Note: old style constructor is still suported (container, template, config)
26403 * Create a new View
26404 * @param {Object} config The config object
26407 Roo.View = function(config, depreciated_tpl, depreciated_config){
26409 this.parent = false;
26411 if (typeof(depreciated_tpl) == 'undefined') {
26412 // new way.. - universal constructor.
26413 Roo.apply(this, config);
26414 this.el = Roo.get(this.el);
26417 this.el = Roo.get(config);
26418 this.tpl = depreciated_tpl;
26419 Roo.apply(this, depreciated_config);
26421 this.wrapEl = this.el.wrap().wrap();
26422 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26425 if(typeof(this.tpl) == "string"){
26426 this.tpl = new Roo.Template(this.tpl);
26428 // support xtype ctors..
26429 this.tpl = new Roo.factory(this.tpl, Roo);
26433 this.tpl.compile();
26438 * @event beforeclick
26439 * Fires before a click is processed. Returns false to cancel the default action.
26440 * @param {Roo.View} this
26441 * @param {Number} index The index of the target node
26442 * @param {HTMLElement} node The target node
26443 * @param {Roo.EventObject} e The raw event object
26445 "beforeclick" : true,
26448 * Fires when a template node is clicked.
26449 * @param {Roo.View} this
26450 * @param {Number} index The index of the target node
26451 * @param {HTMLElement} node The target node
26452 * @param {Roo.EventObject} e The raw event object
26457 * Fires when a template node is double clicked.
26458 * @param {Roo.View} this
26459 * @param {Number} index The index of the target node
26460 * @param {HTMLElement} node The target node
26461 * @param {Roo.EventObject} e The raw event object
26465 * @event contextmenu
26466 * Fires when a template node is right clicked.
26467 * @param {Roo.View} this
26468 * @param {Number} index The index of the target node
26469 * @param {HTMLElement} node The target node
26470 * @param {Roo.EventObject} e The raw event object
26472 "contextmenu" : true,
26474 * @event selectionchange
26475 * Fires when the selected nodes change.
26476 * @param {Roo.View} this
26477 * @param {Array} selections Array of the selected nodes
26479 "selectionchange" : true,
26482 * @event beforeselect
26483 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26484 * @param {Roo.View} this
26485 * @param {HTMLElement} node The node to be selected
26486 * @param {Array} selections Array of currently selected nodes
26488 "beforeselect" : true,
26490 * @event preparedata
26491 * Fires on every row to render, to allow you to change the data.
26492 * @param {Roo.View} this
26493 * @param {Object} data to be rendered (change this)
26495 "preparedata" : true
26503 "click": this.onClick,
26504 "dblclick": this.onDblClick,
26505 "contextmenu": this.onContextMenu,
26509 this.selections = [];
26511 this.cmp = new Roo.CompositeElementLite([]);
26513 this.store = Roo.factory(this.store, Roo.data);
26514 this.setStore(this.store, true);
26517 if ( this.footer && this.footer.xtype) {
26519 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26521 this.footer.dataSource = this.store;
26522 this.footer.container = fctr;
26523 this.footer = Roo.factory(this.footer, Roo);
26524 fctr.insertFirst(this.el);
26526 // this is a bit insane - as the paging toolbar seems to detach the el..
26527 // dom.parentNode.parentNode.parentNode
26528 // they get detached?
26532 Roo.View.superclass.constructor.call(this);
26537 Roo.extend(Roo.View, Roo.util.Observable, {
26540 * @cfg {Roo.data.Store} store Data store to load data from.
26545 * @cfg {String|Roo.Element} el The container element.
26550 * @cfg {String|Roo.Template} tpl The template used by this View
26554 * @cfg {String} dataName the named area of the template to use as the data area
26555 * Works with domtemplates roo-name="name"
26559 * @cfg {String} selectedClass The css class to add to selected nodes
26561 selectedClass : "x-view-selected",
26563 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26568 * @cfg {String} text to display on mask (default Loading)
26572 * @cfg {Boolean} multiSelect Allow multiple selection
26574 multiSelect : false,
26576 * @cfg {Boolean} singleSelect Allow single selection
26578 singleSelect: false,
26581 * @cfg {Boolean} toggleSelect - selecting
26583 toggleSelect : false,
26586 * @cfg {Boolean} tickable - selecting
26591 * Returns the element this view is bound to.
26592 * @return {Roo.Element}
26594 getEl : function(){
26595 return this.wrapEl;
26601 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26603 refresh : function(){
26604 //Roo.log('refresh');
26607 // if we are using something like 'domtemplate', then
26608 // the what gets used is:
26609 // t.applySubtemplate(NAME, data, wrapping data..)
26610 // the outer template then get' applied with
26611 // the store 'extra data'
26612 // and the body get's added to the
26613 // roo-name="data" node?
26614 // <span class='roo-tpl-{name}'></span> ?????
26618 this.clearSelections();
26619 this.el.update("");
26621 var records = this.store.getRange();
26622 if(records.length < 1) {
26624 // is this valid?? = should it render a template??
26626 this.el.update(this.emptyText);
26630 if (this.dataName) {
26631 this.el.update(t.apply(this.store.meta)); //????
26632 el = this.el.child('.roo-tpl-' + this.dataName);
26635 for(var i = 0, len = records.length; i < len; i++){
26636 var data = this.prepareData(records[i].data, i, records[i]);
26637 this.fireEvent("preparedata", this, data, i, records[i]);
26639 var d = Roo.apply({}, data);
26642 Roo.apply(d, {'roo-id' : Roo.id()});
26646 Roo.each(this.parent.item, function(item){
26647 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26650 Roo.apply(d, {'roo-data-checked' : 'checked'});
26654 html[html.length] = Roo.util.Format.trim(
26656 t.applySubtemplate(this.dataName, d, this.store.meta) :
26663 el.update(html.join(""));
26664 this.nodes = el.dom.childNodes;
26665 this.updateIndexes(0);
26670 * Function to override to reformat the data that is sent to
26671 * the template for each node.
26672 * DEPRICATED - use the preparedata event handler.
26673 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26674 * a JSON object for an UpdateManager bound view).
26676 prepareData : function(data, index, record)
26678 this.fireEvent("preparedata", this, data, index, record);
26682 onUpdate : function(ds, record){
26683 // Roo.log('on update');
26684 this.clearSelections();
26685 var index = this.store.indexOf(record);
26686 var n = this.nodes[index];
26687 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26688 n.parentNode.removeChild(n);
26689 this.updateIndexes(index, index);
26695 onAdd : function(ds, records, index)
26697 //Roo.log(['on Add', ds, records, index] );
26698 this.clearSelections();
26699 if(this.nodes.length == 0){
26703 var n = this.nodes[index];
26704 for(var i = 0, len = records.length; i < len; i++){
26705 var d = this.prepareData(records[i].data, i, records[i]);
26707 this.tpl.insertBefore(n, d);
26710 this.tpl.append(this.el, d);
26713 this.updateIndexes(index);
26716 onRemove : function(ds, record, index){
26717 // Roo.log('onRemove');
26718 this.clearSelections();
26719 var el = this.dataName ?
26720 this.el.child('.roo-tpl-' + this.dataName) :
26723 el.dom.removeChild(this.nodes[index]);
26724 this.updateIndexes(index);
26728 * Refresh an individual node.
26729 * @param {Number} index
26731 refreshNode : function(index){
26732 this.onUpdate(this.store, this.store.getAt(index));
26735 updateIndexes : function(startIndex, endIndex){
26736 var ns = this.nodes;
26737 startIndex = startIndex || 0;
26738 endIndex = endIndex || ns.length - 1;
26739 for(var i = startIndex; i <= endIndex; i++){
26740 ns[i].nodeIndex = i;
26745 * Changes the data store this view uses and refresh the view.
26746 * @param {Store} store
26748 setStore : function(store, initial){
26749 if(!initial && this.store){
26750 this.store.un("datachanged", this.refresh);
26751 this.store.un("add", this.onAdd);
26752 this.store.un("remove", this.onRemove);
26753 this.store.un("update", this.onUpdate);
26754 this.store.un("clear", this.refresh);
26755 this.store.un("beforeload", this.onBeforeLoad);
26756 this.store.un("load", this.onLoad);
26757 this.store.un("loadexception", this.onLoad);
26761 store.on("datachanged", this.refresh, this);
26762 store.on("add", this.onAdd, this);
26763 store.on("remove", this.onRemove, this);
26764 store.on("update", this.onUpdate, this);
26765 store.on("clear", this.refresh, this);
26766 store.on("beforeload", this.onBeforeLoad, this);
26767 store.on("load", this.onLoad, this);
26768 store.on("loadexception", this.onLoad, this);
26776 * onbeforeLoad - masks the loading area.
26779 onBeforeLoad : function(store,opts)
26781 //Roo.log('onBeforeLoad');
26783 this.el.update("");
26785 this.el.mask(this.mask ? this.mask : "Loading" );
26787 onLoad : function ()
26794 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26795 * @param {HTMLElement} node
26796 * @return {HTMLElement} The template node
26798 findItemFromChild : function(node){
26799 var el = this.dataName ?
26800 this.el.child('.roo-tpl-' + this.dataName,true) :
26803 if(!node || node.parentNode == el){
26806 var p = node.parentNode;
26807 while(p && p != el){
26808 if(p.parentNode == el){
26817 onClick : function(e){
26818 var item = this.findItemFromChild(e.getTarget());
26820 var index = this.indexOf(item);
26821 if(this.onItemClick(item, index, e) !== false){
26822 this.fireEvent("click", this, index, item, e);
26825 this.clearSelections();
26830 onContextMenu : function(e){
26831 var item = this.findItemFromChild(e.getTarget());
26833 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26838 onDblClick : function(e){
26839 var item = this.findItemFromChild(e.getTarget());
26841 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26845 onItemClick : function(item, index, e)
26847 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26850 if (this.toggleSelect) {
26851 var m = this.isSelected(item) ? 'unselect' : 'select';
26854 _t[m](item, true, false);
26857 if(this.multiSelect || this.singleSelect){
26858 if(this.multiSelect && e.shiftKey && this.lastSelection){
26859 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26861 this.select(item, this.multiSelect && e.ctrlKey);
26862 this.lastSelection = item;
26865 if(!this.tickable){
26866 e.preventDefault();
26874 * Get the number of selected nodes.
26877 getSelectionCount : function(){
26878 return this.selections.length;
26882 * Get the currently selected nodes.
26883 * @return {Array} An array of HTMLElements
26885 getSelectedNodes : function(){
26886 return this.selections;
26890 * Get the indexes of the selected nodes.
26893 getSelectedIndexes : function(){
26894 var indexes = [], s = this.selections;
26895 for(var i = 0, len = s.length; i < len; i++){
26896 indexes.push(s[i].nodeIndex);
26902 * Clear all selections
26903 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26905 clearSelections : function(suppressEvent){
26906 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26907 this.cmp.elements = this.selections;
26908 this.cmp.removeClass(this.selectedClass);
26909 this.selections = [];
26910 if(!suppressEvent){
26911 this.fireEvent("selectionchange", this, this.selections);
26917 * Returns true if the passed node is selected
26918 * @param {HTMLElement/Number} node The node or node index
26919 * @return {Boolean}
26921 isSelected : function(node){
26922 var s = this.selections;
26926 node = this.getNode(node);
26927 return s.indexOf(node) !== -1;
26932 * @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
26933 * @param {Boolean} keepExisting (optional) true to keep existing selections
26934 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26936 select : function(nodeInfo, keepExisting, suppressEvent){
26937 if(nodeInfo instanceof Array){
26939 this.clearSelections(true);
26941 for(var i = 0, len = nodeInfo.length; i < len; i++){
26942 this.select(nodeInfo[i], true, true);
26946 var node = this.getNode(nodeInfo);
26947 if(!node || this.isSelected(node)){
26948 return; // already selected.
26951 this.clearSelections(true);
26954 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26955 Roo.fly(node).addClass(this.selectedClass);
26956 this.selections.push(node);
26957 if(!suppressEvent){
26958 this.fireEvent("selectionchange", this, this.selections);
26966 * @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
26967 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26968 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26970 unselect : function(nodeInfo, keepExisting, suppressEvent)
26972 if(nodeInfo instanceof Array){
26973 Roo.each(this.selections, function(s) {
26974 this.unselect(s, nodeInfo);
26978 var node = this.getNode(nodeInfo);
26979 if(!node || !this.isSelected(node)){
26980 //Roo.log("not selected");
26981 return; // not selected.
26985 Roo.each(this.selections, function(s) {
26987 Roo.fly(node).removeClass(this.selectedClass);
26994 this.selections= ns;
26995 this.fireEvent("selectionchange", this, this.selections);
26999 * Gets a template node.
27000 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27001 * @return {HTMLElement} The node or null if it wasn't found
27003 getNode : function(nodeInfo){
27004 if(typeof nodeInfo == "string"){
27005 return document.getElementById(nodeInfo);
27006 }else if(typeof nodeInfo == "number"){
27007 return this.nodes[nodeInfo];
27013 * Gets a range template nodes.
27014 * @param {Number} startIndex
27015 * @param {Number} endIndex
27016 * @return {Array} An array of nodes
27018 getNodes : function(start, end){
27019 var ns = this.nodes;
27020 start = start || 0;
27021 end = typeof end == "undefined" ? ns.length - 1 : end;
27024 for(var i = start; i <= end; i++){
27028 for(var i = start; i >= end; i--){
27036 * Finds the index of the passed node
27037 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27038 * @return {Number} The index of the node or -1
27040 indexOf : function(node){
27041 node = this.getNode(node);
27042 if(typeof node.nodeIndex == "number"){
27043 return node.nodeIndex;
27045 var ns = this.nodes;
27046 for(var i = 0, len = ns.length; i < len; i++){
27056 * Ext JS Library 1.1.1
27057 * Copyright(c) 2006-2007, Ext JS, LLC.
27059 * Originally Released Under LGPL - original licence link has changed is not relivant.
27062 * <script type="text/javascript">
27066 * @class Roo.JsonView
27067 * @extends Roo.View
27068 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27070 var view = new Roo.JsonView({
27071 container: "my-element",
27072 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27077 // listen for node click?
27078 view.on("click", function(vw, index, node, e){
27079 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27082 // direct load of JSON data
27083 view.load("foobar.php");
27085 // Example from my blog list
27086 var tpl = new Roo.Template(
27087 '<div class="entry">' +
27088 '<a class="entry-title" href="{link}">{title}</a>' +
27089 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27090 "</div><hr />"
27093 var moreView = new Roo.JsonView({
27094 container : "entry-list",
27098 moreView.on("beforerender", this.sortEntries, this);
27100 url: "/blog/get-posts.php",
27101 params: "allposts=true",
27102 text: "Loading Blog Entries..."
27106 * Note: old code is supported with arguments : (container, template, config)
27110 * Create a new JsonView
27112 * @param {Object} config The config object
27115 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27118 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27120 var um = this.el.getUpdateManager();
27121 um.setRenderer(this);
27122 um.on("update", this.onLoad, this);
27123 um.on("failure", this.onLoadException, this);
27126 * @event beforerender
27127 * Fires before rendering of the downloaded JSON data.
27128 * @param {Roo.JsonView} this
27129 * @param {Object} data The JSON data loaded
27133 * Fires when data is loaded.
27134 * @param {Roo.JsonView} this
27135 * @param {Object} data The JSON data loaded
27136 * @param {Object} response The raw Connect response object
27139 * @event loadexception
27140 * Fires when loading fails.
27141 * @param {Roo.JsonView} this
27142 * @param {Object} response The raw Connect response object
27145 'beforerender' : true,
27147 'loadexception' : true
27150 Roo.extend(Roo.JsonView, Roo.View, {
27152 * @type {String} The root property in the loaded JSON object that contains the data
27157 * Refreshes the view.
27159 refresh : function(){
27160 this.clearSelections();
27161 this.el.update("");
27163 var o = this.jsonData;
27164 if(o && o.length > 0){
27165 for(var i = 0, len = o.length; i < len; i++){
27166 var data = this.prepareData(o[i], i, o);
27167 html[html.length] = this.tpl.apply(data);
27170 html.push(this.emptyText);
27172 this.el.update(html.join(""));
27173 this.nodes = this.el.dom.childNodes;
27174 this.updateIndexes(0);
27178 * 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.
27179 * @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:
27182 url: "your-url.php",
27183 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27184 callback: yourFunction,
27185 scope: yourObject, //(optional scope)
27188 text: "Loading...",
27193 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27194 * 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.
27195 * @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}
27196 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27197 * @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.
27200 var um = this.el.getUpdateManager();
27201 um.update.apply(um, arguments);
27204 // note - render is a standard framework call...
27205 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27206 render : function(el, response){
27208 this.clearSelections();
27209 this.el.update("");
27212 if (response != '') {
27213 o = Roo.util.JSON.decode(response.responseText);
27216 o = o[this.jsonRoot];
27222 * The current JSON data or null
27225 this.beforeRender();
27230 * Get the number of records in the current JSON dataset
27233 getCount : function(){
27234 return this.jsonData ? this.jsonData.length : 0;
27238 * Returns the JSON object for the specified node(s)
27239 * @param {HTMLElement/Array} node The node or an array of nodes
27240 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27241 * you get the JSON object for the node
27243 getNodeData : function(node){
27244 if(node instanceof Array){
27246 for(var i = 0, len = node.length; i < len; i++){
27247 data.push(this.getNodeData(node[i]));
27251 return this.jsonData[this.indexOf(node)] || null;
27254 beforeRender : function(){
27255 this.snapshot = this.jsonData;
27257 this.sort.apply(this, this.sortInfo);
27259 this.fireEvent("beforerender", this, this.jsonData);
27262 onLoad : function(el, o){
27263 this.fireEvent("load", this, this.jsonData, o);
27266 onLoadException : function(el, o){
27267 this.fireEvent("loadexception", this, o);
27271 * Filter the data by a specific property.
27272 * @param {String} property A property on your JSON objects
27273 * @param {String/RegExp} value Either string that the property values
27274 * should start with, or a RegExp to test against the property
27276 filter : function(property, value){
27279 var ss = this.snapshot;
27280 if(typeof value == "string"){
27281 var vlen = value.length;
27283 this.clearFilter();
27286 value = value.toLowerCase();
27287 for(var i = 0, len = ss.length; i < len; i++){
27289 if(o[property].substr(0, vlen).toLowerCase() == value){
27293 } else if(value.exec){ // regex?
27294 for(var i = 0, len = ss.length; i < len; i++){
27296 if(value.test(o[property])){
27303 this.jsonData = data;
27309 * Filter by a function. The passed function will be called with each
27310 * object in the current dataset. If the function returns true the value is kept,
27311 * otherwise it is filtered.
27312 * @param {Function} fn
27313 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27315 filterBy : function(fn, scope){
27318 var ss = this.snapshot;
27319 for(var i = 0, len = ss.length; i < len; i++){
27321 if(fn.call(scope || this, o)){
27325 this.jsonData = data;
27331 * Clears the current filter.
27333 clearFilter : function(){
27334 if(this.snapshot && this.jsonData != this.snapshot){
27335 this.jsonData = this.snapshot;
27342 * Sorts the data for this view and refreshes it.
27343 * @param {String} property A property on your JSON objects to sort on
27344 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27345 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27347 sort : function(property, dir, sortType){
27348 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27351 var dsc = dir && dir.toLowerCase() == "desc";
27352 var f = function(o1, o2){
27353 var v1 = sortType ? sortType(o1[p]) : o1[p];
27354 var v2 = sortType ? sortType(o2[p]) : o2[p];
27357 return dsc ? +1 : -1;
27358 } else if(v1 > v2){
27359 return dsc ? -1 : +1;
27364 this.jsonData.sort(f);
27366 if(this.jsonData != this.snapshot){
27367 this.snapshot.sort(f);
27373 * Ext JS Library 1.1.1
27374 * Copyright(c) 2006-2007, Ext JS, LLC.
27376 * Originally Released Under LGPL - original licence link has changed is not relivant.
27379 * <script type="text/javascript">
27384 * @class Roo.ColorPalette
27385 * @extends Roo.Component
27386 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27387 * Here's an example of typical usage:
27389 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27390 cp.render('my-div');
27392 cp.on('select', function(palette, selColor){
27393 // do something with selColor
27397 * Create a new ColorPalette
27398 * @param {Object} config The config object
27400 Roo.ColorPalette = function(config){
27401 Roo.ColorPalette.superclass.constructor.call(this, config);
27405 * Fires when a color is selected
27406 * @param {ColorPalette} this
27407 * @param {String} color The 6-digit color hex code (without the # symbol)
27413 this.on("select", this.handler, this.scope, true);
27416 Roo.extend(Roo.ColorPalette, Roo.Component, {
27418 * @cfg {String} itemCls
27419 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27421 itemCls : "x-color-palette",
27423 * @cfg {String} value
27424 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27425 * the hex codes are case-sensitive.
27428 clickEvent:'click',
27430 ctype: "Roo.ColorPalette",
27433 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27435 allowReselect : false,
27438 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27439 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27440 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27441 * of colors with the width setting until the box is symmetrical.</p>
27442 * <p>You can override individual colors if needed:</p>
27444 var cp = new Roo.ColorPalette();
27445 cp.colors[0] = "FF0000"; // change the first box to red
27448 Or you can provide a custom array of your own for complete control:
27450 var cp = new Roo.ColorPalette();
27451 cp.colors = ["000000", "993300", "333300"];
27456 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27457 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27458 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27459 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27460 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27464 onRender : function(container, position){
27465 var t = new Roo.MasterTemplate(
27466 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27468 var c = this.colors;
27469 for(var i = 0, len = c.length; i < len; i++){
27472 var el = document.createElement("div");
27473 el.className = this.itemCls;
27475 container.dom.insertBefore(el, position);
27476 this.el = Roo.get(el);
27477 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27478 if(this.clickEvent != 'click'){
27479 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27484 afterRender : function(){
27485 Roo.ColorPalette.superclass.afterRender.call(this);
27487 var s = this.value;
27494 handleClick : function(e, t){
27495 e.preventDefault();
27496 if(!this.disabled){
27497 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27498 this.select(c.toUpperCase());
27503 * Selects the specified color in the palette (fires the select event)
27504 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27506 select : function(color){
27507 color = color.replace("#", "");
27508 if(color != this.value || this.allowReselect){
27511 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27513 el.child("a.color-"+color).addClass("x-color-palette-sel");
27514 this.value = color;
27515 this.fireEvent("select", this, color);
27520 * Ext JS Library 1.1.1
27521 * Copyright(c) 2006-2007, Ext JS, LLC.
27523 * Originally Released Under LGPL - original licence link has changed is not relivant.
27526 * <script type="text/javascript">
27530 * @class Roo.DatePicker
27531 * @extends Roo.Component
27532 * Simple date picker class.
27534 * Create a new DatePicker
27535 * @param {Object} config The config object
27537 Roo.DatePicker = function(config){
27538 Roo.DatePicker.superclass.constructor.call(this, config);
27540 this.value = config && config.value ?
27541 config.value.clearTime() : new Date().clearTime();
27546 * Fires when a date is selected
27547 * @param {DatePicker} this
27548 * @param {Date} date The selected date
27552 * @event monthchange
27553 * Fires when the displayed month changes
27554 * @param {DatePicker} this
27555 * @param {Date} date The selected month
27557 'monthchange': true
27561 this.on("select", this.handler, this.scope || this);
27563 // build the disabledDatesRE
27564 if(!this.disabledDatesRE && this.disabledDates){
27565 var dd = this.disabledDates;
27567 for(var i = 0; i < dd.length; i++){
27569 if(i != dd.length-1) {
27573 this.disabledDatesRE = new RegExp(re + ")");
27577 Roo.extend(Roo.DatePicker, Roo.Component, {
27579 * @cfg {String} todayText
27580 * The text to display on the button that selects the current date (defaults to "Today")
27582 todayText : "Today",
27584 * @cfg {String} okText
27585 * The text to display on the ok button
27587 okText : " OK ", //   to give the user extra clicking room
27589 * @cfg {String} cancelText
27590 * The text to display on the cancel button
27592 cancelText : "Cancel",
27594 * @cfg {String} todayTip
27595 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27597 todayTip : "{0} (Spacebar)",
27599 * @cfg {Date} minDate
27600 * Minimum allowable date (JavaScript date object, defaults to null)
27604 * @cfg {Date} maxDate
27605 * Maximum allowable date (JavaScript date object, defaults to null)
27609 * @cfg {String} minText
27610 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27612 minText : "This date is before the minimum date",
27614 * @cfg {String} maxText
27615 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27617 maxText : "This date is after the maximum date",
27619 * @cfg {String} format
27620 * The default date format string which can be overriden for localization support. The format must be
27621 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27625 * @cfg {Array} disabledDays
27626 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27628 disabledDays : null,
27630 * @cfg {String} disabledDaysText
27631 * The tooltip to display when the date falls on a disabled day (defaults to "")
27633 disabledDaysText : "",
27635 * @cfg {RegExp} disabledDatesRE
27636 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27638 disabledDatesRE : null,
27640 * @cfg {String} disabledDatesText
27641 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27643 disabledDatesText : "",
27645 * @cfg {Boolean} constrainToViewport
27646 * True to constrain the date picker to the viewport (defaults to true)
27648 constrainToViewport : true,
27650 * @cfg {Array} monthNames
27651 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27653 monthNames : Date.monthNames,
27655 * @cfg {Array} dayNames
27656 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27658 dayNames : Date.dayNames,
27660 * @cfg {String} nextText
27661 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27663 nextText: 'Next Month (Control+Right)',
27665 * @cfg {String} prevText
27666 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27668 prevText: 'Previous Month (Control+Left)',
27670 * @cfg {String} monthYearText
27671 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27673 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27675 * @cfg {Number} startDay
27676 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27680 * @cfg {Bool} showClear
27681 * Show a clear button (usefull for date form elements that can be blank.)
27687 * Sets the value of the date field
27688 * @param {Date} value The date to set
27690 setValue : function(value){
27691 var old = this.value;
27693 if (typeof(value) == 'string') {
27695 value = Date.parseDate(value, this.format);
27698 value = new Date();
27701 this.value = value.clearTime(true);
27703 this.update(this.value);
27708 * Gets the current selected value of the date field
27709 * @return {Date} The selected date
27711 getValue : function(){
27716 focus : function(){
27718 this.update(this.activeDate);
27723 onRender : function(container, position){
27726 '<table cellspacing="0">',
27727 '<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>',
27728 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27729 var dn = this.dayNames;
27730 for(var i = 0; i < 7; i++){
27731 var d = this.startDay+i;
27735 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27737 m[m.length] = "</tr></thead><tbody><tr>";
27738 for(var i = 0; i < 42; i++) {
27739 if(i % 7 == 0 && i != 0){
27740 m[m.length] = "</tr><tr>";
27742 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27744 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27745 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27747 var el = document.createElement("div");
27748 el.className = "x-date-picker";
27749 el.innerHTML = m.join("");
27751 container.dom.insertBefore(el, position);
27753 this.el = Roo.get(el);
27754 this.eventEl = Roo.get(el.firstChild);
27756 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27757 handler: this.showPrevMonth,
27759 preventDefault:true,
27763 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27764 handler: this.showNextMonth,
27766 preventDefault:true,
27770 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27772 this.monthPicker = this.el.down('div.x-date-mp');
27773 this.monthPicker.enableDisplayMode('block');
27775 var kn = new Roo.KeyNav(this.eventEl, {
27776 "left" : function(e){
27778 this.showPrevMonth() :
27779 this.update(this.activeDate.add("d", -1));
27782 "right" : function(e){
27784 this.showNextMonth() :
27785 this.update(this.activeDate.add("d", 1));
27788 "up" : function(e){
27790 this.showNextYear() :
27791 this.update(this.activeDate.add("d", -7));
27794 "down" : function(e){
27796 this.showPrevYear() :
27797 this.update(this.activeDate.add("d", 7));
27800 "pageUp" : function(e){
27801 this.showNextMonth();
27804 "pageDown" : function(e){
27805 this.showPrevMonth();
27808 "enter" : function(e){
27809 e.stopPropagation();
27816 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27818 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27820 this.el.unselectable();
27822 this.cells = this.el.select("table.x-date-inner tbody td");
27823 this.textNodes = this.el.query("table.x-date-inner tbody span");
27825 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27827 tooltip: this.monthYearText
27830 this.mbtn.on('click', this.showMonthPicker, this);
27831 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27834 var today = (new Date()).dateFormat(this.format);
27836 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27837 if (this.showClear) {
27838 baseTb.add( new Roo.Toolbar.Fill());
27841 text: String.format(this.todayText, today),
27842 tooltip: String.format(this.todayTip, today),
27843 handler: this.selectToday,
27847 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27850 if (this.showClear) {
27852 baseTb.add( new Roo.Toolbar.Fill());
27855 cls: 'x-btn-icon x-btn-clear',
27856 handler: function() {
27858 this.fireEvent("select", this, '');
27868 this.update(this.value);
27871 createMonthPicker : function(){
27872 if(!this.monthPicker.dom.firstChild){
27873 var buf = ['<table border="0" cellspacing="0">'];
27874 for(var i = 0; i < 6; i++){
27876 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27877 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27879 '<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>' :
27880 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27884 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27886 '</button><button type="button" class="x-date-mp-cancel">',
27888 '</button></td></tr>',
27891 this.monthPicker.update(buf.join(''));
27892 this.monthPicker.on('click', this.onMonthClick, this);
27893 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27895 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27896 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27898 this.mpMonths.each(function(m, a, i){
27901 m.dom.xmonth = 5 + Math.round(i * .5);
27903 m.dom.xmonth = Math.round((i-1) * .5);
27909 showMonthPicker : function(){
27910 this.createMonthPicker();
27911 var size = this.el.getSize();
27912 this.monthPicker.setSize(size);
27913 this.monthPicker.child('table').setSize(size);
27915 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27916 this.updateMPMonth(this.mpSelMonth);
27917 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27918 this.updateMPYear(this.mpSelYear);
27920 this.monthPicker.slideIn('t', {duration:.2});
27923 updateMPYear : function(y){
27925 var ys = this.mpYears.elements;
27926 for(var i = 1; i <= 10; i++){
27927 var td = ys[i-1], y2;
27929 y2 = y + Math.round(i * .5);
27930 td.firstChild.innerHTML = y2;
27933 y2 = y - (5-Math.round(i * .5));
27934 td.firstChild.innerHTML = y2;
27937 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27941 updateMPMonth : function(sm){
27942 this.mpMonths.each(function(m, a, i){
27943 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27947 selectMPMonth: function(m){
27951 onMonthClick : function(e, t){
27953 var el = new Roo.Element(t), pn;
27954 if(el.is('button.x-date-mp-cancel')){
27955 this.hideMonthPicker();
27957 else if(el.is('button.x-date-mp-ok')){
27958 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27959 this.hideMonthPicker();
27961 else if(pn = el.up('td.x-date-mp-month', 2)){
27962 this.mpMonths.removeClass('x-date-mp-sel');
27963 pn.addClass('x-date-mp-sel');
27964 this.mpSelMonth = pn.dom.xmonth;
27966 else if(pn = el.up('td.x-date-mp-year', 2)){
27967 this.mpYears.removeClass('x-date-mp-sel');
27968 pn.addClass('x-date-mp-sel');
27969 this.mpSelYear = pn.dom.xyear;
27971 else if(el.is('a.x-date-mp-prev')){
27972 this.updateMPYear(this.mpyear-10);
27974 else if(el.is('a.x-date-mp-next')){
27975 this.updateMPYear(this.mpyear+10);
27979 onMonthDblClick : function(e, t){
27981 var el = new Roo.Element(t), pn;
27982 if(pn = el.up('td.x-date-mp-month', 2)){
27983 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27984 this.hideMonthPicker();
27986 else if(pn = el.up('td.x-date-mp-year', 2)){
27987 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27988 this.hideMonthPicker();
27992 hideMonthPicker : function(disableAnim){
27993 if(this.monthPicker){
27994 if(disableAnim === true){
27995 this.monthPicker.hide();
27997 this.monthPicker.slideOut('t', {duration:.2});
28003 showPrevMonth : function(e){
28004 this.update(this.activeDate.add("mo", -1));
28008 showNextMonth : function(e){
28009 this.update(this.activeDate.add("mo", 1));
28013 showPrevYear : function(){
28014 this.update(this.activeDate.add("y", -1));
28018 showNextYear : function(){
28019 this.update(this.activeDate.add("y", 1));
28023 handleMouseWheel : function(e){
28024 var delta = e.getWheelDelta();
28026 this.showPrevMonth();
28028 } else if(delta < 0){
28029 this.showNextMonth();
28035 handleDateClick : function(e, t){
28037 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28038 this.setValue(new Date(t.dateValue));
28039 this.fireEvent("select", this, this.value);
28044 selectToday : function(){
28045 this.setValue(new Date().clearTime());
28046 this.fireEvent("select", this, this.value);
28050 update : function(date)
28052 var vd = this.activeDate;
28053 this.activeDate = date;
28055 var t = date.getTime();
28056 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28057 this.cells.removeClass("x-date-selected");
28058 this.cells.each(function(c){
28059 if(c.dom.firstChild.dateValue == t){
28060 c.addClass("x-date-selected");
28061 setTimeout(function(){
28062 try{c.dom.firstChild.focus();}catch(e){}
28071 var days = date.getDaysInMonth();
28072 var firstOfMonth = date.getFirstDateOfMonth();
28073 var startingPos = firstOfMonth.getDay()-this.startDay;
28075 if(startingPos <= this.startDay){
28079 var pm = date.add("mo", -1);
28080 var prevStart = pm.getDaysInMonth()-startingPos;
28082 var cells = this.cells.elements;
28083 var textEls = this.textNodes;
28084 days += startingPos;
28086 // convert everything to numbers so it's fast
28087 var day = 86400000;
28088 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28089 var today = new Date().clearTime().getTime();
28090 var sel = date.clearTime().getTime();
28091 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28092 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28093 var ddMatch = this.disabledDatesRE;
28094 var ddText = this.disabledDatesText;
28095 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28096 var ddaysText = this.disabledDaysText;
28097 var format = this.format;
28099 var setCellClass = function(cal, cell){
28101 var t = d.getTime();
28102 cell.firstChild.dateValue = t;
28104 cell.className += " x-date-today";
28105 cell.title = cal.todayText;
28108 cell.className += " x-date-selected";
28109 setTimeout(function(){
28110 try{cell.firstChild.focus();}catch(e){}
28115 cell.className = " x-date-disabled";
28116 cell.title = cal.minText;
28120 cell.className = " x-date-disabled";
28121 cell.title = cal.maxText;
28125 if(ddays.indexOf(d.getDay()) != -1){
28126 cell.title = ddaysText;
28127 cell.className = " x-date-disabled";
28130 if(ddMatch && format){
28131 var fvalue = d.dateFormat(format);
28132 if(ddMatch.test(fvalue)){
28133 cell.title = ddText.replace("%0", fvalue);
28134 cell.className = " x-date-disabled";
28140 for(; i < startingPos; i++) {
28141 textEls[i].innerHTML = (++prevStart);
28142 d.setDate(d.getDate()+1);
28143 cells[i].className = "x-date-prevday";
28144 setCellClass(this, cells[i]);
28146 for(; i < days; i++){
28147 intDay = i - startingPos + 1;
28148 textEls[i].innerHTML = (intDay);
28149 d.setDate(d.getDate()+1);
28150 cells[i].className = "x-date-active";
28151 setCellClass(this, cells[i]);
28154 for(; i < 42; i++) {
28155 textEls[i].innerHTML = (++extraDays);
28156 d.setDate(d.getDate()+1);
28157 cells[i].className = "x-date-nextday";
28158 setCellClass(this, cells[i]);
28161 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28162 this.fireEvent('monthchange', this, date);
28164 if(!this.internalRender){
28165 var main = this.el.dom.firstChild;
28166 var w = main.offsetWidth;
28167 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28168 Roo.fly(main).setWidth(w);
28169 this.internalRender = true;
28170 // opera does not respect the auto grow header center column
28171 // then, after it gets a width opera refuses to recalculate
28172 // without a second pass
28173 if(Roo.isOpera && !this.secondPass){
28174 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28175 this.secondPass = true;
28176 this.update.defer(10, this, [date]);
28184 * Ext JS Library 1.1.1
28185 * Copyright(c) 2006-2007, Ext JS, LLC.
28187 * Originally Released Under LGPL - original licence link has changed is not relivant.
28190 * <script type="text/javascript">
28193 * @class Roo.TabPanel
28194 * @extends Roo.util.Observable
28195 * A lightweight tab container.
28199 // basic tabs 1, built from existing content
28200 var tabs = new Roo.TabPanel("tabs1");
28201 tabs.addTab("script", "View Script");
28202 tabs.addTab("markup", "View Markup");
28203 tabs.activate("script");
28205 // more advanced tabs, built from javascript
28206 var jtabs = new Roo.TabPanel("jtabs");
28207 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28209 // set up the UpdateManager
28210 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28211 var updater = tab2.getUpdateManager();
28212 updater.setDefaultUrl("ajax1.htm");
28213 tab2.on('activate', updater.refresh, updater, true);
28215 // Use setUrl for Ajax loading
28216 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28217 tab3.setUrl("ajax2.htm", null, true);
28220 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28223 jtabs.activate("jtabs-1");
28226 * Create a new TabPanel.
28227 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28228 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28230 Roo.TabPanel = function(container, config){
28232 * The container element for this TabPanel.
28233 * @type Roo.Element
28235 this.el = Roo.get(container, true);
28237 if(typeof config == "boolean"){
28238 this.tabPosition = config ? "bottom" : "top";
28240 Roo.apply(this, config);
28243 if(this.tabPosition == "bottom"){
28244 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28245 this.el.addClass("x-tabs-bottom");
28247 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28248 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28249 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28251 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28253 if(this.tabPosition != "bottom"){
28254 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28255 * @type Roo.Element
28257 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28258 this.el.addClass("x-tabs-top");
28262 this.bodyEl.setStyle("position", "relative");
28264 this.active = null;
28265 this.activateDelegate = this.activate.createDelegate(this);
28270 * Fires when the active tab changes
28271 * @param {Roo.TabPanel} this
28272 * @param {Roo.TabPanelItem} activePanel The new active tab
28276 * @event beforetabchange
28277 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28278 * @param {Roo.TabPanel} this
28279 * @param {Object} e Set cancel to true on this object to cancel the tab change
28280 * @param {Roo.TabPanelItem} tab The tab being changed to
28282 "beforetabchange" : true
28285 Roo.EventManager.onWindowResize(this.onResize, this);
28286 this.cpad = this.el.getPadding("lr");
28287 this.hiddenCount = 0;
28290 // toolbar on the tabbar support...
28291 if (this.toolbar) {
28292 var tcfg = this.toolbar;
28293 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28294 this.toolbar = new Roo.Toolbar(tcfg);
28295 if (Roo.isSafari) {
28296 var tbl = tcfg.container.child('table', true);
28297 tbl.setAttribute('width', '100%');
28304 Roo.TabPanel.superclass.constructor.call(this);
28307 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28309 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28311 tabPosition : "top",
28313 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28315 currentTabWidth : 0,
28317 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28321 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28325 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28327 preferredTabWidth : 175,
28329 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28331 resizeTabs : false,
28333 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28335 monitorResize : true,
28337 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28342 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28343 * @param {String} id The id of the div to use <b>or create</b>
28344 * @param {String} text The text for the tab
28345 * @param {String} content (optional) Content to put in the TabPanelItem body
28346 * @param {Boolean} closable (optional) True to create a close icon on the tab
28347 * @return {Roo.TabPanelItem} The created TabPanelItem
28349 addTab : function(id, text, content, closable){
28350 var item = new Roo.TabPanelItem(this, id, text, closable);
28351 this.addTabItem(item);
28353 item.setContent(content);
28359 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28360 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28361 * @return {Roo.TabPanelItem}
28363 getTab : function(id){
28364 return this.items[id];
28368 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28369 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28371 hideTab : function(id){
28372 var t = this.items[id];
28375 this.hiddenCount++;
28376 this.autoSizeTabs();
28381 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28382 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28384 unhideTab : function(id){
28385 var t = this.items[id];
28387 t.setHidden(false);
28388 this.hiddenCount--;
28389 this.autoSizeTabs();
28394 * Adds an existing {@link Roo.TabPanelItem}.
28395 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28397 addTabItem : function(item){
28398 this.items[item.id] = item;
28399 this.items.push(item);
28400 if(this.resizeTabs){
28401 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28402 this.autoSizeTabs();
28409 * Removes a {@link Roo.TabPanelItem}.
28410 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28412 removeTab : function(id){
28413 var items = this.items;
28414 var tab = items[id];
28415 if(!tab) { return; }
28416 var index = items.indexOf(tab);
28417 if(this.active == tab && items.length > 1){
28418 var newTab = this.getNextAvailable(index);
28423 this.stripEl.dom.removeChild(tab.pnode.dom);
28424 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28425 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28427 items.splice(index, 1);
28428 delete this.items[tab.id];
28429 tab.fireEvent("close", tab);
28430 tab.purgeListeners();
28431 this.autoSizeTabs();
28434 getNextAvailable : function(start){
28435 var items = this.items;
28437 // look for a next tab that will slide over to
28438 // replace the one being removed
28439 while(index < items.length){
28440 var item = items[++index];
28441 if(item && !item.isHidden()){
28445 // if one isn't found select the previous tab (on the left)
28448 var item = items[--index];
28449 if(item && !item.isHidden()){
28457 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28458 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28460 disableTab : function(id){
28461 var tab = this.items[id];
28462 if(tab && this.active != tab){
28468 * Enables a {@link Roo.TabPanelItem} that is disabled.
28469 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28471 enableTab : function(id){
28472 var tab = this.items[id];
28477 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28478 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28479 * @return {Roo.TabPanelItem} The TabPanelItem.
28481 activate : function(id){
28482 var tab = this.items[id];
28486 if(tab == this.active || tab.disabled){
28490 this.fireEvent("beforetabchange", this, e, tab);
28491 if(e.cancel !== true && !tab.disabled){
28493 this.active.hide();
28495 this.active = this.items[id];
28496 this.active.show();
28497 this.fireEvent("tabchange", this, this.active);
28503 * Gets the active {@link Roo.TabPanelItem}.
28504 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28506 getActiveTab : function(){
28507 return this.active;
28511 * Updates the tab body element to fit the height of the container element
28512 * for overflow scrolling
28513 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28515 syncHeight : function(targetHeight){
28516 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28517 var bm = this.bodyEl.getMargins();
28518 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28519 this.bodyEl.setHeight(newHeight);
28523 onResize : function(){
28524 if(this.monitorResize){
28525 this.autoSizeTabs();
28530 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28532 beginUpdate : function(){
28533 this.updating = true;
28537 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28539 endUpdate : function(){
28540 this.updating = false;
28541 this.autoSizeTabs();
28545 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28547 autoSizeTabs : function(){
28548 var count = this.items.length;
28549 var vcount = count - this.hiddenCount;
28550 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28553 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28554 var availWidth = Math.floor(w / vcount);
28555 var b = this.stripBody;
28556 if(b.getWidth() > w){
28557 var tabs = this.items;
28558 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28559 if(availWidth < this.minTabWidth){
28560 /*if(!this.sleft){ // incomplete scrolling code
28561 this.createScrollButtons();
28564 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28567 if(this.currentTabWidth < this.preferredTabWidth){
28568 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28574 * Returns the number of tabs in this TabPanel.
28577 getCount : function(){
28578 return this.items.length;
28582 * Resizes all the tabs to the passed width
28583 * @param {Number} The new width
28585 setTabWidth : function(width){
28586 this.currentTabWidth = width;
28587 for(var i = 0, len = this.items.length; i < len; i++) {
28588 if(!this.items[i].isHidden()) {
28589 this.items[i].setWidth(width);
28595 * Destroys this TabPanel
28596 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28598 destroy : function(removeEl){
28599 Roo.EventManager.removeResizeListener(this.onResize, this);
28600 for(var i = 0, len = this.items.length; i < len; i++){
28601 this.items[i].purgeListeners();
28603 if(removeEl === true){
28604 this.el.update("");
28611 * @class Roo.TabPanelItem
28612 * @extends Roo.util.Observable
28613 * Represents an individual item (tab plus body) in a TabPanel.
28614 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28615 * @param {String} id The id of this TabPanelItem
28616 * @param {String} text The text for the tab of this TabPanelItem
28617 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28619 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28621 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28622 * @type Roo.TabPanel
28624 this.tabPanel = tabPanel;
28626 * The id for this TabPanelItem
28631 this.disabled = false;
28635 this.loaded = false;
28636 this.closable = closable;
28639 * The body element for this TabPanelItem.
28640 * @type Roo.Element
28642 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28643 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28644 this.bodyEl.setStyle("display", "block");
28645 this.bodyEl.setStyle("zoom", "1");
28648 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28650 this.el = Roo.get(els.el, true);
28651 this.inner = Roo.get(els.inner, true);
28652 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28653 this.pnode = Roo.get(els.el.parentNode, true);
28654 this.el.on("mousedown", this.onTabMouseDown, this);
28655 this.el.on("click", this.onTabClick, this);
28658 var c = Roo.get(els.close, true);
28659 c.dom.title = this.closeText;
28660 c.addClassOnOver("close-over");
28661 c.on("click", this.closeClick, this);
28667 * Fires when this tab becomes the active tab.
28668 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28669 * @param {Roo.TabPanelItem} this
28673 * @event beforeclose
28674 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28675 * @param {Roo.TabPanelItem} this
28676 * @param {Object} e Set cancel to true on this object to cancel the close.
28678 "beforeclose": true,
28681 * Fires when this tab is closed.
28682 * @param {Roo.TabPanelItem} this
28686 * @event deactivate
28687 * Fires when this tab is no longer the active tab.
28688 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28689 * @param {Roo.TabPanelItem} this
28691 "deactivate" : true
28693 this.hidden = false;
28695 Roo.TabPanelItem.superclass.constructor.call(this);
28698 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28699 purgeListeners : function(){
28700 Roo.util.Observable.prototype.purgeListeners.call(this);
28701 this.el.removeAllListeners();
28704 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28707 this.pnode.addClass("on");
28710 this.tabPanel.stripWrap.repaint();
28712 this.fireEvent("activate", this.tabPanel, this);
28716 * Returns true if this tab is the active tab.
28717 * @return {Boolean}
28719 isActive : function(){
28720 return this.tabPanel.getActiveTab() == this;
28724 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28727 this.pnode.removeClass("on");
28729 this.fireEvent("deactivate", this.tabPanel, this);
28732 hideAction : function(){
28733 this.bodyEl.hide();
28734 this.bodyEl.setStyle("position", "absolute");
28735 this.bodyEl.setLeft("-20000px");
28736 this.bodyEl.setTop("-20000px");
28739 showAction : function(){
28740 this.bodyEl.setStyle("position", "relative");
28741 this.bodyEl.setTop("");
28742 this.bodyEl.setLeft("");
28743 this.bodyEl.show();
28747 * Set the tooltip for the tab.
28748 * @param {String} tooltip The tab's tooltip
28750 setTooltip : function(text){
28751 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28752 this.textEl.dom.qtip = text;
28753 this.textEl.dom.removeAttribute('title');
28755 this.textEl.dom.title = text;
28759 onTabClick : function(e){
28760 e.preventDefault();
28761 this.tabPanel.activate(this.id);
28764 onTabMouseDown : function(e){
28765 e.preventDefault();
28766 this.tabPanel.activate(this.id);
28769 getWidth : function(){
28770 return this.inner.getWidth();
28773 setWidth : function(width){
28774 var iwidth = width - this.pnode.getPadding("lr");
28775 this.inner.setWidth(iwidth);
28776 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28777 this.pnode.setWidth(width);
28781 * Show or hide the tab
28782 * @param {Boolean} hidden True to hide or false to show.
28784 setHidden : function(hidden){
28785 this.hidden = hidden;
28786 this.pnode.setStyle("display", hidden ? "none" : "");
28790 * Returns true if this tab is "hidden"
28791 * @return {Boolean}
28793 isHidden : function(){
28794 return this.hidden;
28798 * Returns the text for this tab
28801 getText : function(){
28805 autoSize : function(){
28806 //this.el.beginMeasure();
28807 this.textEl.setWidth(1);
28809 * #2804 [new] Tabs in Roojs
28810 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28812 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28813 //this.el.endMeasure();
28817 * Sets the text for the tab (Note: this also sets the tooltip text)
28818 * @param {String} text The tab's text and tooltip
28820 setText : function(text){
28822 this.textEl.update(text);
28823 this.setTooltip(text);
28824 if(!this.tabPanel.resizeTabs){
28829 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28831 activate : function(){
28832 this.tabPanel.activate(this.id);
28836 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28838 disable : function(){
28839 if(this.tabPanel.active != this){
28840 this.disabled = true;
28841 this.pnode.addClass("disabled");
28846 * Enables this TabPanelItem if it was previously disabled.
28848 enable : function(){
28849 this.disabled = false;
28850 this.pnode.removeClass("disabled");
28854 * Sets the content for this TabPanelItem.
28855 * @param {String} content The content
28856 * @param {Boolean} loadScripts true to look for and load scripts
28858 setContent : function(content, loadScripts){
28859 this.bodyEl.update(content, loadScripts);
28863 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28864 * @return {Roo.UpdateManager} The UpdateManager
28866 getUpdateManager : function(){
28867 return this.bodyEl.getUpdateManager();
28871 * Set a URL to be used to load the content for this TabPanelItem.
28872 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28873 * @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)
28874 * @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)
28875 * @return {Roo.UpdateManager} The UpdateManager
28877 setUrl : function(url, params, loadOnce){
28878 if(this.refreshDelegate){
28879 this.un('activate', this.refreshDelegate);
28881 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28882 this.on("activate", this.refreshDelegate);
28883 return this.bodyEl.getUpdateManager();
28887 _handleRefresh : function(url, params, loadOnce){
28888 if(!loadOnce || !this.loaded){
28889 var updater = this.bodyEl.getUpdateManager();
28890 updater.update(url, params, this._setLoaded.createDelegate(this));
28895 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28896 * Will fail silently if the setUrl method has not been called.
28897 * This does not activate the panel, just updates its content.
28899 refresh : function(){
28900 if(this.refreshDelegate){
28901 this.loaded = false;
28902 this.refreshDelegate();
28907 _setLoaded : function(){
28908 this.loaded = true;
28912 closeClick : function(e){
28915 this.fireEvent("beforeclose", this, o);
28916 if(o.cancel !== true){
28917 this.tabPanel.removeTab(this.id);
28921 * The text displayed in the tooltip for the close icon.
28924 closeText : "Close this tab"
28928 Roo.TabPanel.prototype.createStrip = function(container){
28929 var strip = document.createElement("div");
28930 strip.className = "x-tabs-wrap";
28931 container.appendChild(strip);
28935 Roo.TabPanel.prototype.createStripList = function(strip){
28936 // div wrapper for retard IE
28937 // returns the "tr" element.
28938 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28939 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28940 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28941 return strip.firstChild.firstChild.firstChild.firstChild;
28944 Roo.TabPanel.prototype.createBody = function(container){
28945 var body = document.createElement("div");
28946 Roo.id(body, "tab-body");
28947 Roo.fly(body).addClass("x-tabs-body");
28948 container.appendChild(body);
28952 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28953 var body = Roo.getDom(id);
28955 body = document.createElement("div");
28958 Roo.fly(body).addClass("x-tabs-item-body");
28959 bodyEl.insertBefore(body, bodyEl.firstChild);
28963 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28964 var td = document.createElement("td");
28965 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28966 //stripEl.appendChild(td);
28968 td.className = "x-tabs-closable";
28969 if(!this.closeTpl){
28970 this.closeTpl = new Roo.Template(
28971 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28972 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28973 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28976 var el = this.closeTpl.overwrite(td, {"text": text});
28977 var close = el.getElementsByTagName("div")[0];
28978 var inner = el.getElementsByTagName("em")[0];
28979 return {"el": el, "close": close, "inner": inner};
28982 this.tabTpl = new Roo.Template(
28983 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28984 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28987 var el = this.tabTpl.overwrite(td, {"text": text});
28988 var inner = el.getElementsByTagName("em")[0];
28989 return {"el": el, "inner": inner};
28993 * Ext JS Library 1.1.1
28994 * Copyright(c) 2006-2007, Ext JS, LLC.
28996 * Originally Released Under LGPL - original licence link has changed is not relivant.
28999 * <script type="text/javascript">
29003 * @class Roo.Button
29004 * @extends Roo.util.Observable
29005 * Simple Button class
29006 * @cfg {String} text The button text
29007 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29008 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29009 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29010 * @cfg {Object} scope The scope of the handler
29011 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29012 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29013 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29014 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29015 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29016 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29017 applies if enableToggle = true)
29018 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29019 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29020 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29022 * Create a new button
29023 * @param {Object} config The config object
29025 Roo.Button = function(renderTo, config)
29029 renderTo = config.renderTo || false;
29032 Roo.apply(this, config);
29036 * Fires when this button is clicked
29037 * @param {Button} this
29038 * @param {EventObject} e The click event
29043 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29044 * @param {Button} this
29045 * @param {Boolean} pressed
29050 * Fires when the mouse hovers over the button
29051 * @param {Button} this
29052 * @param {Event} e The event object
29054 'mouseover' : true,
29057 * Fires when the mouse exits the button
29058 * @param {Button} this
29059 * @param {Event} e The event object
29064 * Fires when the button is rendered
29065 * @param {Button} this
29070 this.menu = Roo.menu.MenuMgr.get(this.menu);
29072 // register listeners first!! - so render can be captured..
29073 Roo.util.Observable.call(this);
29075 this.render(renderTo);
29081 Roo.extend(Roo.Button, Roo.util.Observable, {
29087 * Read-only. True if this button is hidden
29092 * Read-only. True if this button is disabled
29097 * Read-only. True if this button is pressed (only if enableToggle = true)
29103 * @cfg {Number} tabIndex
29104 * The DOM tabIndex for this button (defaults to undefined)
29106 tabIndex : undefined,
29109 * @cfg {Boolean} enableToggle
29110 * True to enable pressed/not pressed toggling (defaults to false)
29112 enableToggle: false,
29114 * @cfg {Mixed} menu
29115 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29119 * @cfg {String} menuAlign
29120 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29122 menuAlign : "tl-bl?",
29125 * @cfg {String} iconCls
29126 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29128 iconCls : undefined,
29130 * @cfg {String} type
29131 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29136 menuClassTarget: 'tr',
29139 * @cfg {String} clickEvent
29140 * The type of event to map to the button's event handler (defaults to 'click')
29142 clickEvent : 'click',
29145 * @cfg {Boolean} handleMouseEvents
29146 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29148 handleMouseEvents : true,
29151 * @cfg {String} tooltipType
29152 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29154 tooltipType : 'qtip',
29157 * @cfg {String} cls
29158 * A CSS class to apply to the button's main element.
29162 * @cfg {Roo.Template} template (Optional)
29163 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29164 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29165 * require code modifications if required elements (e.g. a button) aren't present.
29169 render : function(renderTo){
29171 if(this.hideParent){
29172 this.parentEl = Roo.get(renderTo);
29174 if(!this.dhconfig){
29175 if(!this.template){
29176 if(!Roo.Button.buttonTemplate){
29177 // hideous table template
29178 Roo.Button.buttonTemplate = new Roo.Template(
29179 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29180 '<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>',
29181 "</tr></tbody></table>");
29183 this.template = Roo.Button.buttonTemplate;
29185 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29186 var btnEl = btn.child("button:first");
29187 btnEl.on('focus', this.onFocus, this);
29188 btnEl.on('blur', this.onBlur, this);
29190 btn.addClass(this.cls);
29193 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29196 btnEl.addClass(this.iconCls);
29198 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29201 if(this.tabIndex !== undefined){
29202 btnEl.dom.tabIndex = this.tabIndex;
29205 if(typeof this.tooltip == 'object'){
29206 Roo.QuickTips.tips(Roo.apply({
29210 btnEl.dom[this.tooltipType] = this.tooltip;
29214 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29218 this.el.dom.id = this.el.id = this.id;
29221 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29222 this.menu.on("show", this.onMenuShow, this);
29223 this.menu.on("hide", this.onMenuHide, this);
29225 btn.addClass("x-btn");
29226 if(Roo.isIE && !Roo.isIE7){
29227 this.autoWidth.defer(1, this);
29231 if(this.handleMouseEvents){
29232 btn.on("mouseover", this.onMouseOver, this);
29233 btn.on("mouseout", this.onMouseOut, this);
29234 btn.on("mousedown", this.onMouseDown, this);
29236 btn.on(this.clickEvent, this.onClick, this);
29237 //btn.on("mouseup", this.onMouseUp, this);
29244 Roo.ButtonToggleMgr.register(this);
29246 this.el.addClass("x-btn-pressed");
29249 var repeater = new Roo.util.ClickRepeater(btn,
29250 typeof this.repeat == "object" ? this.repeat : {}
29252 repeater.on("click", this.onClick, this);
29255 this.fireEvent('render', this);
29259 * Returns the button's underlying element
29260 * @return {Roo.Element} The element
29262 getEl : function(){
29267 * Destroys this Button and removes any listeners.
29269 destroy : function(){
29270 Roo.ButtonToggleMgr.unregister(this);
29271 this.el.removeAllListeners();
29272 this.purgeListeners();
29277 autoWidth : function(){
29279 this.el.setWidth("auto");
29280 if(Roo.isIE7 && Roo.isStrict){
29281 var ib = this.el.child('button');
29282 if(ib && ib.getWidth() > 20){
29284 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29289 this.el.beginMeasure();
29291 if(this.el.getWidth() < this.minWidth){
29292 this.el.setWidth(this.minWidth);
29295 this.el.endMeasure();
29302 * Assigns this button's click handler
29303 * @param {Function} handler The function to call when the button is clicked
29304 * @param {Object} scope (optional) Scope for the function passed in
29306 setHandler : function(handler, scope){
29307 this.handler = handler;
29308 this.scope = scope;
29312 * Sets this button's text
29313 * @param {String} text The button text
29315 setText : function(text){
29318 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29324 * Gets the text for this button
29325 * @return {String} The button text
29327 getText : function(){
29335 this.hidden = false;
29337 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29345 this.hidden = true;
29347 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29352 * Convenience function for boolean show/hide
29353 * @param {Boolean} visible True to show, false to hide
29355 setVisible: function(visible){
29364 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29365 * @param {Boolean} state (optional) Force a particular state
29367 toggle : function(state){
29368 state = state === undefined ? !this.pressed : state;
29369 if(state != this.pressed){
29371 this.el.addClass("x-btn-pressed");
29372 this.pressed = true;
29373 this.fireEvent("toggle", this, true);
29375 this.el.removeClass("x-btn-pressed");
29376 this.pressed = false;
29377 this.fireEvent("toggle", this, false);
29379 if(this.toggleHandler){
29380 this.toggleHandler.call(this.scope || this, this, state);
29388 focus : function(){
29389 this.el.child('button:first').focus();
29393 * Disable this button
29395 disable : function(){
29397 this.el.addClass("x-btn-disabled");
29399 this.disabled = true;
29403 * Enable this button
29405 enable : function(){
29407 this.el.removeClass("x-btn-disabled");
29409 this.disabled = false;
29413 * Convenience function for boolean enable/disable
29414 * @param {Boolean} enabled True to enable, false to disable
29416 setDisabled : function(v){
29417 this[v !== true ? "enable" : "disable"]();
29421 onClick : function(e)
29424 e.preventDefault();
29429 if(!this.disabled){
29430 if(this.enableToggle){
29433 if(this.menu && !this.menu.isVisible()){
29434 this.menu.show(this.el, this.menuAlign);
29436 this.fireEvent("click", this, e);
29438 this.el.removeClass("x-btn-over");
29439 this.handler.call(this.scope || this, this, e);
29444 onMouseOver : function(e){
29445 if(!this.disabled){
29446 this.el.addClass("x-btn-over");
29447 this.fireEvent('mouseover', this, e);
29451 onMouseOut : function(e){
29452 if(!e.within(this.el, true)){
29453 this.el.removeClass("x-btn-over");
29454 this.fireEvent('mouseout', this, e);
29458 onFocus : function(e){
29459 if(!this.disabled){
29460 this.el.addClass("x-btn-focus");
29464 onBlur : function(e){
29465 this.el.removeClass("x-btn-focus");
29468 onMouseDown : function(e){
29469 if(!this.disabled && e.button == 0){
29470 this.el.addClass("x-btn-click");
29471 Roo.get(document).on('mouseup', this.onMouseUp, this);
29475 onMouseUp : function(e){
29477 this.el.removeClass("x-btn-click");
29478 Roo.get(document).un('mouseup', this.onMouseUp, this);
29482 onMenuShow : function(e){
29483 this.el.addClass("x-btn-menu-active");
29486 onMenuHide : function(e){
29487 this.el.removeClass("x-btn-menu-active");
29491 // Private utility class used by Button
29492 Roo.ButtonToggleMgr = function(){
29495 function toggleGroup(btn, state){
29497 var g = groups[btn.toggleGroup];
29498 for(var i = 0, l = g.length; i < l; i++){
29500 g[i].toggle(false);
29507 register : function(btn){
29508 if(!btn.toggleGroup){
29511 var g = groups[btn.toggleGroup];
29513 g = groups[btn.toggleGroup] = [];
29516 btn.on("toggle", toggleGroup);
29519 unregister : function(btn){
29520 if(!btn.toggleGroup){
29523 var g = groups[btn.toggleGroup];
29526 btn.un("toggle", toggleGroup);
29532 * Ext JS Library 1.1.1
29533 * Copyright(c) 2006-2007, Ext JS, LLC.
29535 * Originally Released Under LGPL - original licence link has changed is not relivant.
29538 * <script type="text/javascript">
29542 * @class Roo.SplitButton
29543 * @extends Roo.Button
29544 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29545 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29546 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29547 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29548 * @cfg {String} arrowTooltip The title attribute of the arrow
29550 * Create a new menu button
29551 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29552 * @param {Object} config The config object
29554 Roo.SplitButton = function(renderTo, config){
29555 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29557 * @event arrowclick
29558 * Fires when this button's arrow is clicked
29559 * @param {SplitButton} this
29560 * @param {EventObject} e The click event
29562 this.addEvents({"arrowclick":true});
29565 Roo.extend(Roo.SplitButton, Roo.Button, {
29566 render : function(renderTo){
29567 // this is one sweet looking template!
29568 var tpl = new Roo.Template(
29569 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29570 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29571 '<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>',
29572 "</tbody></table></td><td>",
29573 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29574 '<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>',
29575 "</tbody></table></td></tr></table>"
29577 var btn = tpl.append(renderTo, [this.text, this.type], true);
29578 var btnEl = btn.child("button");
29580 btn.addClass(this.cls);
29583 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29586 btnEl.addClass(this.iconCls);
29588 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29592 if(this.handleMouseEvents){
29593 btn.on("mouseover", this.onMouseOver, this);
29594 btn.on("mouseout", this.onMouseOut, this);
29595 btn.on("mousedown", this.onMouseDown, this);
29596 btn.on("mouseup", this.onMouseUp, this);
29598 btn.on(this.clickEvent, this.onClick, this);
29600 if(typeof this.tooltip == 'object'){
29601 Roo.QuickTips.tips(Roo.apply({
29605 btnEl.dom[this.tooltipType] = this.tooltip;
29608 if(this.arrowTooltip){
29609 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29618 this.el.addClass("x-btn-pressed");
29620 if(Roo.isIE && !Roo.isIE7){
29621 this.autoWidth.defer(1, this);
29626 this.menu.on("show", this.onMenuShow, this);
29627 this.menu.on("hide", this.onMenuHide, this);
29629 this.fireEvent('render', this);
29633 autoWidth : function(){
29635 var tbl = this.el.child("table:first");
29636 var tbl2 = this.el.child("table:last");
29637 this.el.setWidth("auto");
29638 tbl.setWidth("auto");
29639 if(Roo.isIE7 && Roo.isStrict){
29640 var ib = this.el.child('button:first');
29641 if(ib && ib.getWidth() > 20){
29643 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29648 this.el.beginMeasure();
29650 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29651 tbl.setWidth(this.minWidth-tbl2.getWidth());
29654 this.el.endMeasure();
29657 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29661 * Sets this button's click handler
29662 * @param {Function} handler The function to call when the button is clicked
29663 * @param {Object} scope (optional) Scope for the function passed above
29665 setHandler : function(handler, scope){
29666 this.handler = handler;
29667 this.scope = scope;
29671 * Sets this button's arrow click handler
29672 * @param {Function} handler The function to call when the arrow is clicked
29673 * @param {Object} scope (optional) Scope for the function passed above
29675 setArrowHandler : function(handler, scope){
29676 this.arrowHandler = handler;
29677 this.scope = scope;
29683 focus : function(){
29685 this.el.child("button:first").focus();
29690 onClick : function(e){
29691 e.preventDefault();
29692 if(!this.disabled){
29693 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29694 if(this.menu && !this.menu.isVisible()){
29695 this.menu.show(this.el, this.menuAlign);
29697 this.fireEvent("arrowclick", this, e);
29698 if(this.arrowHandler){
29699 this.arrowHandler.call(this.scope || this, this, e);
29702 this.fireEvent("click", this, e);
29704 this.handler.call(this.scope || this, this, e);
29710 onMouseDown : function(e){
29711 if(!this.disabled){
29712 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29716 onMouseUp : function(e){
29717 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29722 // backwards compat
29723 Roo.MenuButton = Roo.SplitButton;/*
29725 * Ext JS Library 1.1.1
29726 * Copyright(c) 2006-2007, Ext JS, LLC.
29728 * Originally Released Under LGPL - original licence link has changed is not relivant.
29731 * <script type="text/javascript">
29735 * @class Roo.Toolbar
29736 * Basic Toolbar class.
29738 * Creates a new Toolbar
29739 * @param {Object} container The config object
29741 Roo.Toolbar = function(container, buttons, config)
29743 /// old consturctor format still supported..
29744 if(container instanceof Array){ // omit the container for later rendering
29745 buttons = container;
29749 if (typeof(container) == 'object' && container.xtype) {
29750 config = container;
29751 container = config.container;
29752 buttons = config.buttons || []; // not really - use items!!
29755 if (config && config.items) {
29756 xitems = config.items;
29757 delete config.items;
29759 Roo.apply(this, config);
29760 this.buttons = buttons;
29763 this.render(container);
29765 this.xitems = xitems;
29766 Roo.each(xitems, function(b) {
29772 Roo.Toolbar.prototype = {
29774 * @cfg {Array} items
29775 * array of button configs or elements to add (will be converted to a MixedCollection)
29779 * @cfg {String/HTMLElement/Element} container
29780 * The id or element that will contain the toolbar
29783 render : function(ct){
29784 this.el = Roo.get(ct);
29786 this.el.addClass(this.cls);
29788 // using a table allows for vertical alignment
29789 // 100% width is needed by Safari...
29790 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29791 this.tr = this.el.child("tr", true);
29793 this.items = new Roo.util.MixedCollection(false, function(o){
29794 return o.id || ("item" + (++autoId));
29797 this.add.apply(this, this.buttons);
29798 delete this.buttons;
29803 * Adds element(s) to the toolbar -- this function takes a variable number of
29804 * arguments of mixed type and adds them to the toolbar.
29805 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29807 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29808 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29809 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29810 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29811 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29812 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29813 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29814 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29815 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29817 * @param {Mixed} arg2
29818 * @param {Mixed} etc.
29821 var a = arguments, l = a.length;
29822 for(var i = 0; i < l; i++){
29827 _add : function(el) {
29830 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29833 if (el.applyTo){ // some kind of form field
29834 return this.addField(el);
29836 if (el.render){ // some kind of Toolbar.Item
29837 return this.addItem(el);
29839 if (typeof el == "string"){ // string
29840 if(el == "separator" || el == "-"){
29841 return this.addSeparator();
29844 return this.addSpacer();
29847 return this.addFill();
29849 return this.addText(el);
29852 if(el.tagName){ // element
29853 return this.addElement(el);
29855 if(typeof el == "object"){ // must be button config?
29856 return this.addButton(el);
29858 // and now what?!?!
29864 * Add an Xtype element
29865 * @param {Object} xtype Xtype Object
29866 * @return {Object} created Object
29868 addxtype : function(e){
29869 return this.add(e);
29873 * Returns the Element for this toolbar.
29874 * @return {Roo.Element}
29876 getEl : function(){
29882 * @return {Roo.Toolbar.Item} The separator item
29884 addSeparator : function(){
29885 return this.addItem(new Roo.Toolbar.Separator());
29889 * Adds a spacer element
29890 * @return {Roo.Toolbar.Spacer} The spacer item
29892 addSpacer : function(){
29893 return this.addItem(new Roo.Toolbar.Spacer());
29897 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29898 * @return {Roo.Toolbar.Fill} The fill item
29900 addFill : function(){
29901 return this.addItem(new Roo.Toolbar.Fill());
29905 * Adds any standard HTML element to the toolbar
29906 * @param {String/HTMLElement/Element} el The element or id of the element to add
29907 * @return {Roo.Toolbar.Item} The element's item
29909 addElement : function(el){
29910 return this.addItem(new Roo.Toolbar.Item(el));
29913 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29914 * @type Roo.util.MixedCollection
29919 * Adds any Toolbar.Item or subclass
29920 * @param {Roo.Toolbar.Item} item
29921 * @return {Roo.Toolbar.Item} The item
29923 addItem : function(item){
29924 var td = this.nextBlock();
29926 this.items.add(item);
29931 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29932 * @param {Object/Array} config A button config or array of configs
29933 * @return {Roo.Toolbar.Button/Array}
29935 addButton : function(config){
29936 if(config instanceof Array){
29938 for(var i = 0, len = config.length; i < len; i++) {
29939 buttons.push(this.addButton(config[i]));
29944 if(!(config instanceof Roo.Toolbar.Button)){
29946 new Roo.Toolbar.SplitButton(config) :
29947 new Roo.Toolbar.Button(config);
29949 var td = this.nextBlock();
29956 * Adds text to the toolbar
29957 * @param {String} text The text to add
29958 * @return {Roo.Toolbar.Item} The element's item
29960 addText : function(text){
29961 return this.addItem(new Roo.Toolbar.TextItem(text));
29965 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29966 * @param {Number} index The index where the item is to be inserted
29967 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29968 * @return {Roo.Toolbar.Button/Item}
29970 insertButton : function(index, item){
29971 if(item instanceof Array){
29973 for(var i = 0, len = item.length; i < len; i++) {
29974 buttons.push(this.insertButton(index + i, item[i]));
29978 if (!(item instanceof Roo.Toolbar.Button)){
29979 item = new Roo.Toolbar.Button(item);
29981 var td = document.createElement("td");
29982 this.tr.insertBefore(td, this.tr.childNodes[index]);
29984 this.items.insert(index, item);
29989 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29990 * @param {Object} config
29991 * @return {Roo.Toolbar.Item} The element's item
29993 addDom : function(config, returnEl){
29994 var td = this.nextBlock();
29995 Roo.DomHelper.overwrite(td, config);
29996 var ti = new Roo.Toolbar.Item(td.firstChild);
29998 this.items.add(ti);
30003 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30004 * @type Roo.util.MixedCollection
30009 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30010 * Note: the field should not have been rendered yet. For a field that has already been
30011 * rendered, use {@link #addElement}.
30012 * @param {Roo.form.Field} field
30013 * @return {Roo.ToolbarItem}
30017 addField : function(field) {
30018 if (!this.fields) {
30020 this.fields = new Roo.util.MixedCollection(false, function(o){
30021 return o.id || ("item" + (++autoId));
30026 var td = this.nextBlock();
30028 var ti = new Roo.Toolbar.Item(td.firstChild);
30030 this.items.add(ti);
30031 this.fields.add(field);
30042 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30043 this.el.child('div').hide();
30051 this.el.child('div').show();
30055 nextBlock : function(){
30056 var td = document.createElement("td");
30057 this.tr.appendChild(td);
30062 destroy : function(){
30063 if(this.items){ // rendered?
30064 Roo.destroy.apply(Roo, this.items.items);
30066 if(this.fields){ // rendered?
30067 Roo.destroy.apply(Roo, this.fields.items);
30069 Roo.Element.uncache(this.el, this.tr);
30074 * @class Roo.Toolbar.Item
30075 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30077 * Creates a new Item
30078 * @param {HTMLElement} el
30080 Roo.Toolbar.Item = function(el){
30082 if (typeof (el.xtype) != 'undefined') {
30087 this.el = Roo.getDom(el);
30088 this.id = Roo.id(this.el);
30089 this.hidden = false;
30094 * Fires when the button is rendered
30095 * @param {Button} this
30099 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30101 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30102 //Roo.Toolbar.Item.prototype = {
30105 * Get this item's HTML Element
30106 * @return {HTMLElement}
30108 getEl : function(){
30113 render : function(td){
30116 td.appendChild(this.el);
30118 this.fireEvent('render', this);
30122 * Removes and destroys this item.
30124 destroy : function(){
30125 this.td.parentNode.removeChild(this.td);
30132 this.hidden = false;
30133 this.td.style.display = "";
30140 this.hidden = true;
30141 this.td.style.display = "none";
30145 * Convenience function for boolean show/hide.
30146 * @param {Boolean} visible true to show/false to hide
30148 setVisible: function(visible){
30157 * Try to focus this item.
30159 focus : function(){
30160 Roo.fly(this.el).focus();
30164 * Disables this item.
30166 disable : function(){
30167 Roo.fly(this.td).addClass("x-item-disabled");
30168 this.disabled = true;
30169 this.el.disabled = true;
30173 * Enables this item.
30175 enable : function(){
30176 Roo.fly(this.td).removeClass("x-item-disabled");
30177 this.disabled = false;
30178 this.el.disabled = false;
30184 * @class Roo.Toolbar.Separator
30185 * @extends Roo.Toolbar.Item
30186 * A simple toolbar separator class
30188 * Creates a new Separator
30190 Roo.Toolbar.Separator = function(cfg){
30192 var s = document.createElement("span");
30193 s.className = "ytb-sep";
30198 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30200 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30201 enable:Roo.emptyFn,
30202 disable:Roo.emptyFn,
30207 * @class Roo.Toolbar.Spacer
30208 * @extends Roo.Toolbar.Item
30209 * A simple element that adds extra horizontal space to a toolbar.
30211 * Creates a new Spacer
30213 Roo.Toolbar.Spacer = function(cfg){
30214 var s = document.createElement("div");
30215 s.className = "ytb-spacer";
30219 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30221 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30222 enable:Roo.emptyFn,
30223 disable:Roo.emptyFn,
30228 * @class Roo.Toolbar.Fill
30229 * @extends Roo.Toolbar.Spacer
30230 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30232 * Creates a new Spacer
30234 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30236 render : function(td){
30237 td.style.width = '100%';
30238 Roo.Toolbar.Fill.superclass.render.call(this, td);
30243 * @class Roo.Toolbar.TextItem
30244 * @extends Roo.Toolbar.Item
30245 * A simple class that renders text directly into a toolbar.
30247 * Creates a new TextItem
30248 * @param {String} text
30250 Roo.Toolbar.TextItem = function(cfg){
30251 var text = cfg || "";
30252 if (typeof(cfg) == 'object') {
30253 text = cfg.text || "";
30257 var s = document.createElement("span");
30258 s.className = "ytb-text";
30259 s.innerHTML = text;
30264 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30266 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30269 enable:Roo.emptyFn,
30270 disable:Roo.emptyFn,
30275 * @class Roo.Toolbar.Button
30276 * @extends Roo.Button
30277 * A button that renders into a toolbar.
30279 * Creates a new Button
30280 * @param {Object} config A standard {@link Roo.Button} config object
30282 Roo.Toolbar.Button = function(config){
30283 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30285 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30286 render : function(td){
30288 Roo.Toolbar.Button.superclass.render.call(this, td);
30292 * Removes and destroys this button
30294 destroy : function(){
30295 Roo.Toolbar.Button.superclass.destroy.call(this);
30296 this.td.parentNode.removeChild(this.td);
30300 * Shows this button
30303 this.hidden = false;
30304 this.td.style.display = "";
30308 * Hides this button
30311 this.hidden = true;
30312 this.td.style.display = "none";
30316 * Disables this item
30318 disable : function(){
30319 Roo.fly(this.td).addClass("x-item-disabled");
30320 this.disabled = true;
30324 * Enables this item
30326 enable : function(){
30327 Roo.fly(this.td).removeClass("x-item-disabled");
30328 this.disabled = false;
30331 // backwards compat
30332 Roo.ToolbarButton = Roo.Toolbar.Button;
30335 * @class Roo.Toolbar.SplitButton
30336 * @extends Roo.SplitButton
30337 * A menu button that renders into a toolbar.
30339 * Creates a new SplitButton
30340 * @param {Object} config A standard {@link Roo.SplitButton} config object
30342 Roo.Toolbar.SplitButton = function(config){
30343 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30345 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30346 render : function(td){
30348 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30352 * Removes and destroys this button
30354 destroy : function(){
30355 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30356 this.td.parentNode.removeChild(this.td);
30360 * Shows this button
30363 this.hidden = false;
30364 this.td.style.display = "";
30368 * Hides this button
30371 this.hidden = true;
30372 this.td.style.display = "none";
30376 // backwards compat
30377 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30379 * Ext JS Library 1.1.1
30380 * Copyright(c) 2006-2007, Ext JS, LLC.
30382 * Originally Released Under LGPL - original licence link has changed is not relivant.
30385 * <script type="text/javascript">
30389 * @class Roo.PagingToolbar
30390 * @extends Roo.Toolbar
30391 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30393 * Create a new PagingToolbar
30394 * @param {Object} config The config object
30396 Roo.PagingToolbar = function(el, ds, config)
30398 // old args format still supported... - xtype is prefered..
30399 if (typeof(el) == 'object' && el.xtype) {
30400 // created from xtype...
30402 ds = el.dataSource;
30403 el = config.container;
30406 if (config.items) {
30407 items = config.items;
30411 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30414 this.renderButtons(this.el);
30417 // supprot items array.
30419 Roo.each(items, function(e) {
30420 this.add(Roo.factory(e));
30425 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30427 * @cfg {Roo.data.Store} dataSource
30428 * The underlying data store providing the paged data
30431 * @cfg {String/HTMLElement/Element} container
30432 * container The id or element that will contain the toolbar
30435 * @cfg {Boolean} displayInfo
30436 * True to display the displayMsg (defaults to false)
30439 * @cfg {Number} pageSize
30440 * The number of records to display per page (defaults to 20)
30444 * @cfg {String} displayMsg
30445 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30447 displayMsg : 'Displaying {0} - {1} of {2}',
30449 * @cfg {String} emptyMsg
30450 * The message to display when no records are found (defaults to "No data to display")
30452 emptyMsg : 'No data to display',
30454 * Customizable piece of the default paging text (defaults to "Page")
30457 beforePageText : "Page",
30459 * Customizable piece of the default paging text (defaults to "of %0")
30462 afterPageText : "of {0}",
30464 * Customizable piece of the default paging text (defaults to "First Page")
30467 firstText : "First Page",
30469 * Customizable piece of the default paging text (defaults to "Previous Page")
30472 prevText : "Previous Page",
30474 * Customizable piece of the default paging text (defaults to "Next Page")
30477 nextText : "Next Page",
30479 * Customizable piece of the default paging text (defaults to "Last Page")
30482 lastText : "Last Page",
30484 * Customizable piece of the default paging text (defaults to "Refresh")
30487 refreshText : "Refresh",
30490 renderButtons : function(el){
30491 Roo.PagingToolbar.superclass.render.call(this, el);
30492 this.first = this.addButton({
30493 tooltip: this.firstText,
30494 cls: "x-btn-icon x-grid-page-first",
30496 handler: this.onClick.createDelegate(this, ["first"])
30498 this.prev = this.addButton({
30499 tooltip: this.prevText,
30500 cls: "x-btn-icon x-grid-page-prev",
30502 handler: this.onClick.createDelegate(this, ["prev"])
30504 //this.addSeparator();
30505 this.add(this.beforePageText);
30506 this.field = Roo.get(this.addDom({
30511 cls: "x-grid-page-number"
30513 this.field.on("keydown", this.onPagingKeydown, this);
30514 this.field.on("focus", function(){this.dom.select();});
30515 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30516 this.field.setHeight(18);
30517 //this.addSeparator();
30518 this.next = this.addButton({
30519 tooltip: this.nextText,
30520 cls: "x-btn-icon x-grid-page-next",
30522 handler: this.onClick.createDelegate(this, ["next"])
30524 this.last = this.addButton({
30525 tooltip: this.lastText,
30526 cls: "x-btn-icon x-grid-page-last",
30528 handler: this.onClick.createDelegate(this, ["last"])
30530 //this.addSeparator();
30531 this.loading = this.addButton({
30532 tooltip: this.refreshText,
30533 cls: "x-btn-icon x-grid-loading",
30534 handler: this.onClick.createDelegate(this, ["refresh"])
30537 if(this.displayInfo){
30538 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30543 updateInfo : function(){
30544 if(this.displayEl){
30545 var count = this.ds.getCount();
30546 var msg = count == 0 ?
30550 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30552 this.displayEl.update(msg);
30557 onLoad : function(ds, r, o){
30558 this.cursor = o.params ? o.params.start : 0;
30559 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30561 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30562 this.field.dom.value = ap;
30563 this.first.setDisabled(ap == 1);
30564 this.prev.setDisabled(ap == 1);
30565 this.next.setDisabled(ap == ps);
30566 this.last.setDisabled(ap == ps);
30567 this.loading.enable();
30572 getPageData : function(){
30573 var total = this.ds.getTotalCount();
30576 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30577 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30582 onLoadError : function(){
30583 this.loading.enable();
30587 onPagingKeydown : function(e){
30588 var k = e.getKey();
30589 var d = this.getPageData();
30591 var v = this.field.dom.value, pageNum;
30592 if(!v || isNaN(pageNum = parseInt(v, 10))){
30593 this.field.dom.value = d.activePage;
30596 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30597 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30600 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))
30602 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30603 this.field.dom.value = pageNum;
30604 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30607 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30609 var v = this.field.dom.value, pageNum;
30610 var increment = (e.shiftKey) ? 10 : 1;
30611 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30614 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30615 this.field.dom.value = d.activePage;
30618 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30620 this.field.dom.value = parseInt(v, 10) + increment;
30621 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30622 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30629 beforeLoad : function(){
30631 this.loading.disable();
30636 onClick : function(which){
30640 ds.load({params:{start: 0, limit: this.pageSize}});
30643 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30646 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30649 var total = ds.getTotalCount();
30650 var extra = total % this.pageSize;
30651 var lastStart = extra ? (total - extra) : total-this.pageSize;
30652 ds.load({params:{start: lastStart, limit: this.pageSize}});
30655 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30661 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30662 * @param {Roo.data.Store} store The data store to unbind
30664 unbind : function(ds){
30665 ds.un("beforeload", this.beforeLoad, this);
30666 ds.un("load", this.onLoad, this);
30667 ds.un("loadexception", this.onLoadError, this);
30668 ds.un("remove", this.updateInfo, this);
30669 ds.un("add", this.updateInfo, this);
30670 this.ds = undefined;
30674 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30675 * @param {Roo.data.Store} store The data store to bind
30677 bind : function(ds){
30678 ds.on("beforeload", this.beforeLoad, this);
30679 ds.on("load", this.onLoad, this);
30680 ds.on("loadexception", this.onLoadError, this);
30681 ds.on("remove", this.updateInfo, this);
30682 ds.on("add", this.updateInfo, this);
30687 * Ext JS Library 1.1.1
30688 * Copyright(c) 2006-2007, Ext JS, LLC.
30690 * Originally Released Under LGPL - original licence link has changed is not relivant.
30693 * <script type="text/javascript">
30697 * @class Roo.Resizable
30698 * @extends Roo.util.Observable
30699 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30700 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30701 * 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
30702 * the element will be wrapped for you automatically.</p>
30703 * <p>Here is the list of valid resize handles:</p>
30706 ------ -------------------
30715 'hd' horizontal drag
30718 * <p>Here's an example showing the creation of a typical Resizable:</p>
30720 var resizer = new Roo.Resizable("element-id", {
30728 resizer.on("resize", myHandler);
30730 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30731 * resizer.east.setDisplayed(false);</p>
30732 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30733 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30734 * resize operation's new size (defaults to [0, 0])
30735 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30736 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30737 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30738 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30739 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30740 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30741 * @cfg {Number} width The width of the element in pixels (defaults to null)
30742 * @cfg {Number} height The height of the element in pixels (defaults to null)
30743 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30744 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30745 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30746 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30747 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30748 * in favor of the handles config option (defaults to false)
30749 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30750 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30751 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30752 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30753 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30754 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30755 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30756 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30757 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30758 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30759 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30761 * Create a new resizable component
30762 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30763 * @param {Object} config configuration options
30765 Roo.Resizable = function(el, config)
30767 this.el = Roo.get(el);
30769 if(config && config.wrap){
30770 config.resizeChild = this.el;
30771 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30772 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30773 this.el.setStyle("overflow", "hidden");
30774 this.el.setPositioning(config.resizeChild.getPositioning());
30775 config.resizeChild.clearPositioning();
30776 if(!config.width || !config.height){
30777 var csize = config.resizeChild.getSize();
30778 this.el.setSize(csize.width, csize.height);
30780 if(config.pinned && !config.adjustments){
30781 config.adjustments = "auto";
30785 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30786 this.proxy.unselectable();
30787 this.proxy.enableDisplayMode('block');
30789 Roo.apply(this, config);
30792 this.disableTrackOver = true;
30793 this.el.addClass("x-resizable-pinned");
30795 // if the element isn't positioned, make it relative
30796 var position = this.el.getStyle("position");
30797 if(position != "absolute" && position != "fixed"){
30798 this.el.setStyle("position", "relative");
30800 if(!this.handles){ // no handles passed, must be legacy style
30801 this.handles = 's,e,se';
30802 if(this.multiDirectional){
30803 this.handles += ',n,w';
30806 if(this.handles == "all"){
30807 this.handles = "n s e w ne nw se sw";
30809 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30810 var ps = Roo.Resizable.positions;
30811 for(var i = 0, len = hs.length; i < len; i++){
30812 if(hs[i] && ps[hs[i]]){
30813 var pos = ps[hs[i]];
30814 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30818 this.corner = this.southeast;
30820 // updateBox = the box can move..
30821 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30822 this.updateBox = true;
30825 this.activeHandle = null;
30827 if(this.resizeChild){
30828 if(typeof this.resizeChild == "boolean"){
30829 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30831 this.resizeChild = Roo.get(this.resizeChild, true);
30835 if(this.adjustments == "auto"){
30836 var rc = this.resizeChild;
30837 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30838 if(rc && (hw || hn)){
30839 rc.position("relative");
30840 rc.setLeft(hw ? hw.el.getWidth() : 0);
30841 rc.setTop(hn ? hn.el.getHeight() : 0);
30843 this.adjustments = [
30844 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30845 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30849 if(this.draggable){
30850 this.dd = this.dynamic ?
30851 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30852 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30858 * @event beforeresize
30859 * Fired before resize is allowed. Set enabled to false to cancel resize.
30860 * @param {Roo.Resizable} this
30861 * @param {Roo.EventObject} e The mousedown event
30863 "beforeresize" : true,
30866 * Fired a resizing.
30867 * @param {Roo.Resizable} this
30868 * @param {Number} x The new x position
30869 * @param {Number} y The new y position
30870 * @param {Number} w The new w width
30871 * @param {Number} h The new h hight
30872 * @param {Roo.EventObject} e The mouseup event
30877 * Fired after a resize.
30878 * @param {Roo.Resizable} this
30879 * @param {Number} width The new width
30880 * @param {Number} height The new height
30881 * @param {Roo.EventObject} e The mouseup event
30886 if(this.width !== null && this.height !== null){
30887 this.resizeTo(this.width, this.height);
30889 this.updateChildSize();
30892 this.el.dom.style.zoom = 1;
30894 Roo.Resizable.superclass.constructor.call(this);
30897 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30898 resizeChild : false,
30899 adjustments : [0, 0],
30909 multiDirectional : false,
30910 disableTrackOver : false,
30911 easing : 'easeOutStrong',
30912 widthIncrement : 0,
30913 heightIncrement : 0,
30917 preserveRatio : false,
30918 transparent: false,
30924 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30926 constrainTo: undefined,
30928 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30930 resizeRegion: undefined,
30934 * Perform a manual resize
30935 * @param {Number} width
30936 * @param {Number} height
30938 resizeTo : function(width, height){
30939 this.el.setSize(width, height);
30940 this.updateChildSize();
30941 this.fireEvent("resize", this, width, height, null);
30945 startSizing : function(e, handle){
30946 this.fireEvent("beforeresize", this, e);
30947 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30950 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30951 this.overlay.unselectable();
30952 this.overlay.enableDisplayMode("block");
30953 this.overlay.on("mousemove", this.onMouseMove, this);
30954 this.overlay.on("mouseup", this.onMouseUp, this);
30956 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30958 this.resizing = true;
30959 this.startBox = this.el.getBox();
30960 this.startPoint = e.getXY();
30961 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30962 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30964 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30965 this.overlay.show();
30967 if(this.constrainTo) {
30968 var ct = Roo.get(this.constrainTo);
30969 this.resizeRegion = ct.getRegion().adjust(
30970 ct.getFrameWidth('t'),
30971 ct.getFrameWidth('l'),
30972 -ct.getFrameWidth('b'),
30973 -ct.getFrameWidth('r')
30977 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30979 this.proxy.setBox(this.startBox);
30981 this.proxy.setStyle('visibility', 'visible');
30987 onMouseDown : function(handle, e){
30990 this.activeHandle = handle;
30991 this.startSizing(e, handle);
30996 onMouseUp : function(e){
30997 var size = this.resizeElement();
30998 this.resizing = false;
31000 this.overlay.hide();
31002 this.fireEvent("resize", this, size.width, size.height, e);
31006 updateChildSize : function(){
31008 if(this.resizeChild){
31010 var child = this.resizeChild;
31011 var adj = this.adjustments;
31012 if(el.dom.offsetWidth){
31013 var b = el.getSize(true);
31014 child.setSize(b.width+adj[0], b.height+adj[1]);
31016 // Second call here for IE
31017 // The first call enables instant resizing and
31018 // the second call corrects scroll bars if they
31021 setTimeout(function(){
31022 if(el.dom.offsetWidth){
31023 var b = el.getSize(true);
31024 child.setSize(b.width+adj[0], b.height+adj[1]);
31032 snap : function(value, inc, min){
31033 if(!inc || !value) {
31036 var newValue = value;
31037 var m = value % inc;
31040 newValue = value + (inc-m);
31042 newValue = value - m;
31045 return Math.max(min, newValue);
31049 resizeElement : function(){
31050 var box = this.proxy.getBox();
31051 if(this.updateBox){
31052 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31054 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31056 this.updateChildSize();
31064 constrain : function(v, diff, m, mx){
31067 }else if(v - diff > mx){
31074 onMouseMove : function(e){
31077 try{// try catch so if something goes wrong the user doesn't get hung
31079 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31083 //var curXY = this.startPoint;
31084 var curSize = this.curSize || this.startBox;
31085 var x = this.startBox.x, y = this.startBox.y;
31086 var ox = x, oy = y;
31087 var w = curSize.width, h = curSize.height;
31088 var ow = w, oh = h;
31089 var mw = this.minWidth, mh = this.minHeight;
31090 var mxw = this.maxWidth, mxh = this.maxHeight;
31091 var wi = this.widthIncrement;
31092 var hi = this.heightIncrement;
31094 var eventXY = e.getXY();
31095 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31096 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31098 var pos = this.activeHandle.position;
31103 w = Math.min(Math.max(mw, w), mxw);
31108 h = Math.min(Math.max(mh, h), mxh);
31113 w = Math.min(Math.max(mw, w), mxw);
31114 h = Math.min(Math.max(mh, h), mxh);
31117 diffY = this.constrain(h, diffY, mh, mxh);
31124 var adiffX = Math.abs(diffX);
31125 var sub = (adiffX % wi); // how much
31126 if (sub > (wi/2)) { // far enough to snap
31127 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31129 // remove difference..
31130 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31134 x = Math.max(this.minX, x);
31137 diffX = this.constrain(w, diffX, mw, mxw);
31143 w = Math.min(Math.max(mw, w), mxw);
31144 diffY = this.constrain(h, diffY, mh, mxh);
31149 diffX = this.constrain(w, diffX, mw, mxw);
31150 diffY = this.constrain(h, diffY, mh, mxh);
31157 diffX = this.constrain(w, diffX, mw, mxw);
31159 h = Math.min(Math.max(mh, h), mxh);
31165 var sw = this.snap(w, wi, mw);
31166 var sh = this.snap(h, hi, mh);
31167 if(sw != w || sh != h){
31190 if(this.preserveRatio){
31195 h = Math.min(Math.max(mh, h), mxh);
31200 w = Math.min(Math.max(mw, w), mxw);
31205 w = Math.min(Math.max(mw, w), mxw);
31211 w = Math.min(Math.max(mw, w), mxw);
31217 h = Math.min(Math.max(mh, h), mxh);
31225 h = Math.min(Math.max(mh, h), mxh);
31235 h = Math.min(Math.max(mh, h), mxh);
31243 if (pos == 'hdrag') {
31246 this.proxy.setBounds(x, y, w, h);
31248 this.resizeElement();
31252 this.fireEvent("resizing", this, x, y, w, h, e);
31256 handleOver : function(){
31258 this.el.addClass("x-resizable-over");
31263 handleOut : function(){
31264 if(!this.resizing){
31265 this.el.removeClass("x-resizable-over");
31270 * Returns the element this component is bound to.
31271 * @return {Roo.Element}
31273 getEl : function(){
31278 * Returns the resizeChild element (or null).
31279 * @return {Roo.Element}
31281 getResizeChild : function(){
31282 return this.resizeChild;
31284 groupHandler : function()
31289 * Destroys this resizable. If the element was wrapped and
31290 * removeEl is not true then the element remains.
31291 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31293 destroy : function(removeEl){
31294 this.proxy.remove();
31296 this.overlay.removeAllListeners();
31297 this.overlay.remove();
31299 var ps = Roo.Resizable.positions;
31301 if(typeof ps[k] != "function" && this[ps[k]]){
31302 var h = this[ps[k]];
31303 h.el.removeAllListeners();
31308 this.el.update("");
31315 // hash to map config positions to true positions
31316 Roo.Resizable.positions = {
31317 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31322 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31324 // only initialize the template if resizable is used
31325 var tpl = Roo.DomHelper.createTemplate(
31326 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31329 Roo.Resizable.Handle.prototype.tpl = tpl;
31331 this.position = pos;
31333 // show north drag fro topdra
31334 var handlepos = pos == 'hdrag' ? 'north' : pos;
31336 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31337 if (pos == 'hdrag') {
31338 this.el.setStyle('cursor', 'pointer');
31340 this.el.unselectable();
31342 this.el.setOpacity(0);
31344 this.el.on("mousedown", this.onMouseDown, this);
31345 if(!disableTrackOver){
31346 this.el.on("mouseover", this.onMouseOver, this);
31347 this.el.on("mouseout", this.onMouseOut, this);
31352 Roo.Resizable.Handle.prototype = {
31353 afterResize : function(rz){
31358 onMouseDown : function(e){
31359 this.rz.onMouseDown(this, e);
31362 onMouseOver : function(e){
31363 this.rz.handleOver(this, e);
31366 onMouseOut : function(e){
31367 this.rz.handleOut(this, e);
31371 * Ext JS Library 1.1.1
31372 * Copyright(c) 2006-2007, Ext JS, LLC.
31374 * Originally Released Under LGPL - original licence link has changed is not relivant.
31377 * <script type="text/javascript">
31381 * @class Roo.Editor
31382 * @extends Roo.Component
31383 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31385 * Create a new Editor
31386 * @param {Roo.form.Field} field The Field object (or descendant)
31387 * @param {Object} config The config object
31389 Roo.Editor = function(field, config){
31390 Roo.Editor.superclass.constructor.call(this, config);
31391 this.field = field;
31394 * @event beforestartedit
31395 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31396 * false from the handler of this event.
31397 * @param {Editor} this
31398 * @param {Roo.Element} boundEl The underlying element bound to this editor
31399 * @param {Mixed} value The field value being set
31401 "beforestartedit" : true,
31404 * Fires when this editor is displayed
31405 * @param {Roo.Element} boundEl The underlying element bound to this editor
31406 * @param {Mixed} value The starting field value
31408 "startedit" : true,
31410 * @event beforecomplete
31411 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31412 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31413 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31414 * event will not fire since no edit actually occurred.
31415 * @param {Editor} this
31416 * @param {Mixed} value The current field value
31417 * @param {Mixed} startValue The original field value
31419 "beforecomplete" : true,
31422 * Fires after editing is complete and any changed value has been written to the underlying field.
31423 * @param {Editor} this
31424 * @param {Mixed} value The current field value
31425 * @param {Mixed} startValue The original field value
31429 * @event specialkey
31430 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31431 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31432 * @param {Roo.form.Field} this
31433 * @param {Roo.EventObject} e The event object
31435 "specialkey" : true
31439 Roo.extend(Roo.Editor, Roo.Component, {
31441 * @cfg {Boolean/String} autosize
31442 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31443 * or "height" to adopt the height only (defaults to false)
31446 * @cfg {Boolean} revertInvalid
31447 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31448 * validation fails (defaults to true)
31451 * @cfg {Boolean} ignoreNoChange
31452 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31453 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31454 * will never be ignored.
31457 * @cfg {Boolean} hideEl
31458 * False to keep the bound element visible while the editor is displayed (defaults to true)
31461 * @cfg {Mixed} value
31462 * The data value of the underlying field (defaults to "")
31466 * @cfg {String} alignment
31467 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31471 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31472 * for bottom-right shadow (defaults to "frame")
31476 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31480 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31482 completeOnEnter : false,
31484 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31486 cancelOnEsc : false,
31488 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31493 onRender : function(ct, position){
31494 this.el = new Roo.Layer({
31495 shadow: this.shadow,
31501 constrain: this.constrain
31503 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31504 if(this.field.msgTarget != 'title'){
31505 this.field.msgTarget = 'qtip';
31507 this.field.render(this.el);
31509 this.field.el.dom.setAttribute('autocomplete', 'off');
31511 this.field.on("specialkey", this.onSpecialKey, this);
31512 if(this.swallowKeys){
31513 this.field.el.swallowEvent(['keydown','keypress']);
31516 this.field.on("blur", this.onBlur, this);
31517 if(this.field.grow){
31518 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31522 onSpecialKey : function(field, e)
31524 //Roo.log('editor onSpecialKey');
31525 if(this.completeOnEnter && e.getKey() == e.ENTER){
31527 this.completeEdit();
31530 // do not fire special key otherwise it might hide close the editor...
31531 if(e.getKey() == e.ENTER){
31534 if(this.cancelOnEsc && e.getKey() == e.ESC){
31538 this.fireEvent('specialkey', field, e);
31543 * Starts the editing process and shows the editor.
31544 * @param {String/HTMLElement/Element} el The element to edit
31545 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31546 * to the innerHTML of el.
31548 startEdit : function(el, value){
31550 this.completeEdit();
31552 this.boundEl = Roo.get(el);
31553 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31554 if(!this.rendered){
31555 this.render(this.parentEl || document.body);
31557 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31560 this.startValue = v;
31561 this.field.setValue(v);
31563 var sz = this.boundEl.getSize();
31564 switch(this.autoSize){
31566 this.setSize(sz.width, "");
31569 this.setSize("", sz.height);
31572 this.setSize(sz.width, sz.height);
31575 this.el.alignTo(this.boundEl, this.alignment);
31576 this.editing = true;
31578 Roo.QuickTips.disable();
31584 * Sets the height and width of this editor.
31585 * @param {Number} width The new width
31586 * @param {Number} height The new height
31588 setSize : function(w, h){
31589 this.field.setSize(w, h);
31596 * Realigns the editor to the bound field based on the current alignment config value.
31598 realign : function(){
31599 this.el.alignTo(this.boundEl, this.alignment);
31603 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31604 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31606 completeEdit : function(remainVisible){
31610 var v = this.getValue();
31611 if(this.revertInvalid !== false && !this.field.isValid()){
31612 v = this.startValue;
31613 this.cancelEdit(true);
31615 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31616 this.editing = false;
31620 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31621 this.editing = false;
31622 if(this.updateEl && this.boundEl){
31623 this.boundEl.update(v);
31625 if(remainVisible !== true){
31628 this.fireEvent("complete", this, v, this.startValue);
31633 onShow : function(){
31635 if(this.hideEl !== false){
31636 this.boundEl.hide();
31639 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31640 this.fixIEFocus = true;
31641 this.deferredFocus.defer(50, this);
31643 this.field.focus();
31645 this.fireEvent("startedit", this.boundEl, this.startValue);
31648 deferredFocus : function(){
31650 this.field.focus();
31655 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31656 * reverted to the original starting value.
31657 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31658 * cancel (defaults to false)
31660 cancelEdit : function(remainVisible){
31662 this.setValue(this.startValue);
31663 if(remainVisible !== true){
31670 onBlur : function(){
31671 if(this.allowBlur !== true && this.editing){
31672 this.completeEdit();
31677 onHide : function(){
31679 this.completeEdit();
31683 if(this.field.collapse){
31684 this.field.collapse();
31687 if(this.hideEl !== false){
31688 this.boundEl.show();
31691 Roo.QuickTips.enable();
31696 * Sets the data value of the editor
31697 * @param {Mixed} value Any valid value supported by the underlying field
31699 setValue : function(v){
31700 this.field.setValue(v);
31704 * Gets the data value of the editor
31705 * @return {Mixed} The data value
31707 getValue : function(){
31708 return this.field.getValue();
31712 * Ext JS Library 1.1.1
31713 * Copyright(c) 2006-2007, Ext JS, LLC.
31715 * Originally Released Under LGPL - original licence link has changed is not relivant.
31718 * <script type="text/javascript">
31722 * @class Roo.BasicDialog
31723 * @extends Roo.util.Observable
31724 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31726 var dlg = new Roo.BasicDialog("my-dlg", {
31735 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31736 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31737 dlg.addButton('Cancel', dlg.hide, dlg);
31740 <b>A Dialog should always be a direct child of the body element.</b>
31741 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31742 * @cfg {String} title Default text to display in the title bar (defaults to null)
31743 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31744 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31745 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31746 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31747 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31748 * (defaults to null with no animation)
31749 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31750 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31751 * property for valid values (defaults to 'all')
31752 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31753 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31754 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31755 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31756 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31757 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31758 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31759 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31760 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31761 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31762 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31763 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31764 * draggable = true (defaults to false)
31765 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31766 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31767 * shadow (defaults to false)
31768 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31769 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31770 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31771 * @cfg {Array} buttons Array of buttons
31772 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31774 * Create a new BasicDialog.
31775 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31776 * @param {Object} config Configuration options
31778 Roo.BasicDialog = function(el, config){
31779 this.el = Roo.get(el);
31780 var dh = Roo.DomHelper;
31781 if(!this.el && config && config.autoCreate){
31782 if(typeof config.autoCreate == "object"){
31783 if(!config.autoCreate.id){
31784 config.autoCreate.id = el;
31786 this.el = dh.append(document.body,
31787 config.autoCreate, true);
31789 this.el = dh.append(document.body,
31790 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31794 el.setDisplayed(true);
31795 el.hide = this.hideAction;
31797 el.addClass("x-dlg");
31799 Roo.apply(this, config);
31801 this.proxy = el.createProxy("x-dlg-proxy");
31802 this.proxy.hide = this.hideAction;
31803 this.proxy.setOpacity(.5);
31807 el.setWidth(config.width);
31810 el.setHeight(config.height);
31812 this.size = el.getSize();
31813 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31814 this.xy = [config.x,config.y];
31816 this.xy = el.getCenterXY(true);
31818 /** The header element @type Roo.Element */
31819 this.header = el.child("> .x-dlg-hd");
31820 /** The body element @type Roo.Element */
31821 this.body = el.child("> .x-dlg-bd");
31822 /** The footer element @type Roo.Element */
31823 this.footer = el.child("> .x-dlg-ft");
31826 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31829 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31832 this.header.unselectable();
31834 this.header.update(this.title);
31836 // this element allows the dialog to be focused for keyboard event
31837 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31838 this.focusEl.swallowEvent("click", true);
31840 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31842 // wrap the body and footer for special rendering
31843 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31845 this.bwrap.dom.appendChild(this.footer.dom);
31848 this.bg = this.el.createChild({
31849 tag: "div", cls:"x-dlg-bg",
31850 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31852 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31855 if(this.autoScroll !== false && !this.autoTabs){
31856 this.body.setStyle("overflow", "auto");
31859 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31861 if(this.closable !== false){
31862 this.el.addClass("x-dlg-closable");
31863 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31864 this.close.on("click", this.closeClick, this);
31865 this.close.addClassOnOver("x-dlg-close-over");
31867 if(this.collapsible !== false){
31868 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31869 this.collapseBtn.on("click", this.collapseClick, this);
31870 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31871 this.header.on("dblclick", this.collapseClick, this);
31873 if(this.resizable !== false){
31874 this.el.addClass("x-dlg-resizable");
31875 this.resizer = new Roo.Resizable(el, {
31876 minWidth: this.minWidth || 80,
31877 minHeight:this.minHeight || 80,
31878 handles: this.resizeHandles || "all",
31881 this.resizer.on("beforeresize", this.beforeResize, this);
31882 this.resizer.on("resize", this.onResize, this);
31884 if(this.draggable !== false){
31885 el.addClass("x-dlg-draggable");
31886 if (!this.proxyDrag) {
31887 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31890 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31892 dd.setHandleElId(this.header.id);
31893 dd.endDrag = this.endMove.createDelegate(this);
31894 dd.startDrag = this.startMove.createDelegate(this);
31895 dd.onDrag = this.onDrag.createDelegate(this);
31900 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31901 this.mask.enableDisplayMode("block");
31903 this.el.addClass("x-dlg-modal");
31906 this.shadow = new Roo.Shadow({
31907 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31908 offset : this.shadowOffset
31911 this.shadowOffset = 0;
31913 if(Roo.useShims && this.shim !== false){
31914 this.shim = this.el.createShim();
31915 this.shim.hide = this.hideAction;
31923 if (this.buttons) {
31924 var bts= this.buttons;
31926 Roo.each(bts, function(b) {
31935 * Fires when a key is pressed
31936 * @param {Roo.BasicDialog} this
31937 * @param {Roo.EventObject} e
31942 * Fires when this dialog is moved by the user.
31943 * @param {Roo.BasicDialog} this
31944 * @param {Number} x The new page X
31945 * @param {Number} y The new page Y
31950 * Fires when this dialog is resized by the user.
31951 * @param {Roo.BasicDialog} this
31952 * @param {Number} width The new width
31953 * @param {Number} height The new height
31957 * @event beforehide
31958 * Fires before this dialog is hidden.
31959 * @param {Roo.BasicDialog} this
31961 "beforehide" : true,
31964 * Fires when this dialog is hidden.
31965 * @param {Roo.BasicDialog} this
31969 * @event beforeshow
31970 * Fires before this dialog is shown.
31971 * @param {Roo.BasicDialog} this
31973 "beforeshow" : true,
31976 * Fires when this dialog is shown.
31977 * @param {Roo.BasicDialog} this
31981 el.on("keydown", this.onKeyDown, this);
31982 el.on("mousedown", this.toFront, this);
31983 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31985 Roo.DialogManager.register(this);
31986 Roo.BasicDialog.superclass.constructor.call(this);
31989 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31990 shadowOffset: Roo.isIE ? 6 : 5,
31993 minButtonWidth: 75,
31994 defaultButton: null,
31995 buttonAlign: "right",
32000 * Sets the dialog title text
32001 * @param {String} text The title text to display
32002 * @return {Roo.BasicDialog} this
32004 setTitle : function(text){
32005 this.header.update(text);
32010 closeClick : function(){
32015 collapseClick : function(){
32016 this[this.collapsed ? "expand" : "collapse"]();
32020 * Collapses the dialog to its minimized state (only the title bar is visible).
32021 * Equivalent to the user clicking the collapse dialog button.
32023 collapse : function(){
32024 if(!this.collapsed){
32025 this.collapsed = true;
32026 this.el.addClass("x-dlg-collapsed");
32027 this.restoreHeight = this.el.getHeight();
32028 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32033 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32034 * clicking the expand dialog button.
32036 expand : function(){
32037 if(this.collapsed){
32038 this.collapsed = false;
32039 this.el.removeClass("x-dlg-collapsed");
32040 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32045 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32046 * @return {Roo.TabPanel} The tabs component
32048 initTabs : function(){
32049 var tabs = this.getTabs();
32050 while(tabs.getTab(0)){
32053 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32055 tabs.addTab(Roo.id(dom), dom.title);
32063 beforeResize : function(){
32064 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32068 onResize : function(){
32069 this.refreshSize();
32070 this.syncBodyHeight();
32071 this.adjustAssets();
32073 this.fireEvent("resize", this, this.size.width, this.size.height);
32077 onKeyDown : function(e){
32078 if(this.isVisible()){
32079 this.fireEvent("keydown", this, e);
32084 * Resizes the dialog.
32085 * @param {Number} width
32086 * @param {Number} height
32087 * @return {Roo.BasicDialog} this
32089 resizeTo : function(width, height){
32090 this.el.setSize(width, height);
32091 this.size = {width: width, height: height};
32092 this.syncBodyHeight();
32093 if(this.fixedcenter){
32096 if(this.isVisible()){
32097 this.constrainXY();
32098 this.adjustAssets();
32100 this.fireEvent("resize", this, width, height);
32106 * Resizes the dialog to fit the specified content size.
32107 * @param {Number} width
32108 * @param {Number} height
32109 * @return {Roo.BasicDialog} this
32111 setContentSize : function(w, h){
32112 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32113 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32114 //if(!this.el.isBorderBox()){
32115 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32116 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32119 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32120 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32122 this.resizeTo(w, h);
32127 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32128 * executed in response to a particular key being pressed while the dialog is active.
32129 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32130 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32131 * @param {Function} fn The function to call
32132 * @param {Object} scope (optional) The scope of the function
32133 * @return {Roo.BasicDialog} this
32135 addKeyListener : function(key, fn, scope){
32136 var keyCode, shift, ctrl, alt;
32137 if(typeof key == "object" && !(key instanceof Array)){
32138 keyCode = key["key"];
32139 shift = key["shift"];
32140 ctrl = key["ctrl"];
32145 var handler = function(dlg, e){
32146 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32147 var k = e.getKey();
32148 if(keyCode instanceof Array){
32149 for(var i = 0, len = keyCode.length; i < len; i++){
32150 if(keyCode[i] == k){
32151 fn.call(scope || window, dlg, k, e);
32157 fn.call(scope || window, dlg, k, e);
32162 this.on("keydown", handler);
32167 * Returns the TabPanel component (creates it if it doesn't exist).
32168 * Note: If you wish to simply check for the existence of tabs without creating them,
32169 * check for a null 'tabs' property.
32170 * @return {Roo.TabPanel} The tabs component
32172 getTabs : function(){
32174 this.el.addClass("x-dlg-auto-tabs");
32175 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32176 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32182 * Adds a button to the footer section of the dialog.
32183 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32184 * object or a valid Roo.DomHelper element config
32185 * @param {Function} handler The function called when the button is clicked
32186 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32187 * @return {Roo.Button} The new button
32189 addButton : function(config, handler, scope){
32190 var dh = Roo.DomHelper;
32192 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32194 if(!this.btnContainer){
32195 var tb = this.footer.createChild({
32197 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32198 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32200 this.btnContainer = tb.firstChild.firstChild.firstChild;
32205 minWidth: this.minButtonWidth,
32208 if(typeof config == "string"){
32209 bconfig.text = config;
32212 bconfig.dhconfig = config;
32214 Roo.apply(bconfig, config);
32218 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32219 bconfig.position = Math.max(0, bconfig.position);
32220 fc = this.btnContainer.childNodes[bconfig.position];
32223 var btn = new Roo.Button(
32225 this.btnContainer.insertBefore(document.createElement("td"),fc)
32226 : this.btnContainer.appendChild(document.createElement("td")),
32227 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32230 this.syncBodyHeight();
32233 * Array of all the buttons that have been added to this dialog via addButton
32238 this.buttons.push(btn);
32243 * Sets the default button to be focused when the dialog is displayed.
32244 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32245 * @return {Roo.BasicDialog} this
32247 setDefaultButton : function(btn){
32248 this.defaultButton = btn;
32253 getHeaderFooterHeight : function(safe){
32256 height += this.header.getHeight();
32259 var fm = this.footer.getMargins();
32260 height += (this.footer.getHeight()+fm.top+fm.bottom);
32262 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32263 height += this.centerBg.getPadding("tb");
32268 syncBodyHeight : function()
32270 var bd = this.body, // the text
32271 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32273 var height = this.size.height - this.getHeaderFooterHeight(false);
32274 bd.setHeight(height-bd.getMargins("tb"));
32275 var hh = this.header.getHeight();
32276 var h = this.size.height-hh;
32279 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32280 bw.setHeight(h-cb.getPadding("tb"));
32282 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32283 bd.setWidth(bw.getWidth(true));
32285 this.tabs.syncHeight();
32287 this.tabs.el.repaint();
32293 * Restores the previous state of the dialog if Roo.state is configured.
32294 * @return {Roo.BasicDialog} this
32296 restoreState : function(){
32297 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32298 if(box && box.width){
32299 this.xy = [box.x, box.y];
32300 this.resizeTo(box.width, box.height);
32306 beforeShow : function(){
32308 if(this.fixedcenter){
32309 this.xy = this.el.getCenterXY(true);
32312 Roo.get(document.body).addClass("x-body-masked");
32313 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32316 this.constrainXY();
32320 animShow : function(){
32321 var b = Roo.get(this.animateTarget).getBox();
32322 this.proxy.setSize(b.width, b.height);
32323 this.proxy.setLocation(b.x, b.y);
32325 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32326 true, .35, this.showEl.createDelegate(this));
32330 * Shows the dialog.
32331 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32332 * @return {Roo.BasicDialog} this
32334 show : function(animateTarget){
32335 if (this.fireEvent("beforeshow", this) === false){
32338 if(this.syncHeightBeforeShow){
32339 this.syncBodyHeight();
32340 }else if(this.firstShow){
32341 this.firstShow = false;
32342 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32344 this.animateTarget = animateTarget || this.animateTarget;
32345 if(!this.el.isVisible()){
32347 if(this.animateTarget && Roo.get(this.animateTarget)){
32357 showEl : function(){
32359 this.el.setXY(this.xy);
32361 this.adjustAssets(true);
32364 // IE peekaboo bug - fix found by Dave Fenwick
32368 this.fireEvent("show", this);
32372 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32373 * dialog itself will receive focus.
32375 focus : function(){
32376 if(this.defaultButton){
32377 this.defaultButton.focus();
32379 this.focusEl.focus();
32384 constrainXY : function(){
32385 if(this.constraintoviewport !== false){
32386 if(!this.viewSize){
32387 if(this.container){
32388 var s = this.container.getSize();
32389 this.viewSize = [s.width, s.height];
32391 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32394 var s = Roo.get(this.container||document).getScroll();
32396 var x = this.xy[0], y = this.xy[1];
32397 var w = this.size.width, h = this.size.height;
32398 var vw = this.viewSize[0], vh = this.viewSize[1];
32399 // only move it if it needs it
32401 // first validate right/bottom
32402 if(x + w > vw+s.left){
32406 if(y + h > vh+s.top){
32410 // then make sure top/left isn't negative
32422 if(this.isVisible()){
32423 this.el.setLocation(x, y);
32424 this.adjustAssets();
32431 onDrag : function(){
32432 if(!this.proxyDrag){
32433 this.xy = this.el.getXY();
32434 this.adjustAssets();
32439 adjustAssets : function(doShow){
32440 var x = this.xy[0], y = this.xy[1];
32441 var w = this.size.width, h = this.size.height;
32442 if(doShow === true){
32444 this.shadow.show(this.el);
32450 if(this.shadow && this.shadow.isVisible()){
32451 this.shadow.show(this.el);
32453 if(this.shim && this.shim.isVisible()){
32454 this.shim.setBounds(x, y, w, h);
32459 adjustViewport : function(w, h){
32461 w = Roo.lib.Dom.getViewWidth();
32462 h = Roo.lib.Dom.getViewHeight();
32465 this.viewSize = [w, h];
32466 if(this.modal && this.mask.isVisible()){
32467 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32468 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32470 if(this.isVisible()){
32471 this.constrainXY();
32476 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32477 * shadow, proxy, mask, etc.) Also removes all event listeners.
32478 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32480 destroy : function(removeEl){
32481 if(this.isVisible()){
32482 this.animateTarget = null;
32485 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32487 this.tabs.destroy(removeEl);
32500 for(var i = 0, len = this.buttons.length; i < len; i++){
32501 this.buttons[i].destroy();
32504 this.el.removeAllListeners();
32505 if(removeEl === true){
32506 this.el.update("");
32509 Roo.DialogManager.unregister(this);
32513 startMove : function(){
32514 if(this.proxyDrag){
32517 if(this.constraintoviewport !== false){
32518 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32523 endMove : function(){
32524 if(!this.proxyDrag){
32525 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32527 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32530 this.refreshSize();
32531 this.adjustAssets();
32533 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32537 * Brings this dialog to the front of any other visible dialogs
32538 * @return {Roo.BasicDialog} this
32540 toFront : function(){
32541 Roo.DialogManager.bringToFront(this);
32546 * Sends this dialog to the back (under) of any other visible dialogs
32547 * @return {Roo.BasicDialog} this
32549 toBack : function(){
32550 Roo.DialogManager.sendToBack(this);
32555 * Centers this dialog in the viewport
32556 * @return {Roo.BasicDialog} this
32558 center : function(){
32559 var xy = this.el.getCenterXY(true);
32560 this.moveTo(xy[0], xy[1]);
32565 * Moves the dialog's top-left corner to the specified point
32566 * @param {Number} x
32567 * @param {Number} y
32568 * @return {Roo.BasicDialog} this
32570 moveTo : function(x, y){
32572 if(this.isVisible()){
32573 this.el.setXY(this.xy);
32574 this.adjustAssets();
32580 * Aligns the dialog to the specified element
32581 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32582 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32583 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32584 * @return {Roo.BasicDialog} this
32586 alignTo : function(element, position, offsets){
32587 this.xy = this.el.getAlignToXY(element, position, offsets);
32588 if(this.isVisible()){
32589 this.el.setXY(this.xy);
32590 this.adjustAssets();
32596 * Anchors an element to another element and realigns it when the window is resized.
32597 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32598 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32599 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32600 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32601 * is a number, it is used as the buffer delay (defaults to 50ms).
32602 * @return {Roo.BasicDialog} this
32604 anchorTo : function(el, alignment, offsets, monitorScroll){
32605 var action = function(){
32606 this.alignTo(el, alignment, offsets);
32608 Roo.EventManager.onWindowResize(action, this);
32609 var tm = typeof monitorScroll;
32610 if(tm != 'undefined'){
32611 Roo.EventManager.on(window, 'scroll', action, this,
32612 {buffer: tm == 'number' ? monitorScroll : 50});
32619 * Returns true if the dialog is visible
32620 * @return {Boolean}
32622 isVisible : function(){
32623 return this.el.isVisible();
32627 animHide : function(callback){
32628 var b = Roo.get(this.animateTarget).getBox();
32630 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32632 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32633 this.hideEl.createDelegate(this, [callback]));
32637 * Hides the dialog.
32638 * @param {Function} callback (optional) Function to call when the dialog is hidden
32639 * @return {Roo.BasicDialog} this
32641 hide : function(callback){
32642 if (this.fireEvent("beforehide", this) === false){
32646 this.shadow.hide();
32651 // sometimes animateTarget seems to get set.. causing problems...
32652 // this just double checks..
32653 if(this.animateTarget && Roo.get(this.animateTarget)) {
32654 this.animHide(callback);
32657 this.hideEl(callback);
32663 hideEl : function(callback){
32667 Roo.get(document.body).removeClass("x-body-masked");
32669 this.fireEvent("hide", this);
32670 if(typeof callback == "function"){
32676 hideAction : function(){
32677 this.setLeft("-10000px");
32678 this.setTop("-10000px");
32679 this.setStyle("visibility", "hidden");
32683 refreshSize : function(){
32684 this.size = this.el.getSize();
32685 this.xy = this.el.getXY();
32686 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32690 // z-index is managed by the DialogManager and may be overwritten at any time
32691 setZIndex : function(index){
32693 this.mask.setStyle("z-index", index);
32696 this.shim.setStyle("z-index", ++index);
32699 this.shadow.setZIndex(++index);
32701 this.el.setStyle("z-index", ++index);
32703 this.proxy.setStyle("z-index", ++index);
32706 this.resizer.proxy.setStyle("z-index", ++index);
32709 this.lastZIndex = index;
32713 * Returns the element for this dialog
32714 * @return {Roo.Element} The underlying dialog Element
32716 getEl : function(){
32722 * @class Roo.DialogManager
32723 * Provides global access to BasicDialogs that have been created and
32724 * support for z-indexing (layering) multiple open dialogs.
32726 Roo.DialogManager = function(){
32728 var accessList = [];
32732 var sortDialogs = function(d1, d2){
32733 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32737 var orderDialogs = function(){
32738 accessList.sort(sortDialogs);
32739 var seed = Roo.DialogManager.zseed;
32740 for(var i = 0, len = accessList.length; i < len; i++){
32741 var dlg = accessList[i];
32743 dlg.setZIndex(seed + (i*10));
32750 * The starting z-index for BasicDialogs (defaults to 9000)
32751 * @type Number The z-index value
32756 register : function(dlg){
32757 list[dlg.id] = dlg;
32758 accessList.push(dlg);
32762 unregister : function(dlg){
32763 delete list[dlg.id];
32766 if(!accessList.indexOf){
32767 for( i = 0, len = accessList.length; i < len; i++){
32768 if(accessList[i] == dlg){
32769 accessList.splice(i, 1);
32774 i = accessList.indexOf(dlg);
32776 accessList.splice(i, 1);
32782 * Gets a registered dialog by id
32783 * @param {String/Object} id The id of the dialog or a dialog
32784 * @return {Roo.BasicDialog} this
32786 get : function(id){
32787 return typeof id == "object" ? id : list[id];
32791 * Brings the specified dialog to the front
32792 * @param {String/Object} dlg The id of the dialog or a dialog
32793 * @return {Roo.BasicDialog} this
32795 bringToFront : function(dlg){
32796 dlg = this.get(dlg);
32799 dlg._lastAccess = new Date().getTime();
32806 * Sends the specified dialog to the back
32807 * @param {String/Object} dlg The id of the dialog or a dialog
32808 * @return {Roo.BasicDialog} this
32810 sendToBack : function(dlg){
32811 dlg = this.get(dlg);
32812 dlg._lastAccess = -(new Date().getTime());
32818 * Hides all dialogs
32820 hideAll : function(){
32821 for(var id in list){
32822 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32831 * @class Roo.LayoutDialog
32832 * @extends Roo.BasicDialog
32833 * Dialog which provides adjustments for working with a layout in a Dialog.
32834 * Add your necessary layout config options to the dialog's config.<br>
32835 * Example usage (including a nested layout):
32838 dialog = new Roo.LayoutDialog("download-dlg", {
32847 // layout config merges with the dialog config
32849 tabPosition: "top",
32850 alwaysShowTabs: true
32853 dialog.addKeyListener(27, dialog.hide, dialog);
32854 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32855 dialog.addButton("Build It!", this.getDownload, this);
32857 // we can even add nested layouts
32858 var innerLayout = new Roo.BorderLayout("dl-inner", {
32868 innerLayout.beginUpdate();
32869 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32870 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32871 innerLayout.endUpdate(true);
32873 var layout = dialog.getLayout();
32874 layout.beginUpdate();
32875 layout.add("center", new Roo.ContentPanel("standard-panel",
32876 {title: "Download the Source", fitToFrame:true}));
32877 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32878 {title: "Build your own roo.js"}));
32879 layout.getRegion("center").showPanel(sp);
32880 layout.endUpdate();
32884 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32885 * @param {Object} config configuration options
32887 Roo.LayoutDialog = function(el, cfg){
32890 if (typeof(cfg) == 'undefined') {
32891 config = Roo.apply({}, el);
32892 // not sure why we use documentElement here.. - it should always be body.
32893 // IE7 borks horribly if we use documentElement.
32894 // webkit also does not like documentElement - it creates a body element...
32895 el = Roo.get( document.body || document.documentElement ).createChild();
32896 //config.autoCreate = true;
32900 config.autoTabs = false;
32901 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32902 this.body.setStyle({overflow:"hidden", position:"relative"});
32903 this.layout = new Roo.BorderLayout(this.body.dom, config);
32904 this.layout.monitorWindowResize = false;
32905 this.el.addClass("x-dlg-auto-layout");
32906 // fix case when center region overwrites center function
32907 this.center = Roo.BasicDialog.prototype.center;
32908 this.on("show", this.layout.layout, this.layout, true);
32909 if (config.items) {
32910 var xitems = config.items;
32911 delete config.items;
32912 Roo.each(xitems, this.addxtype, this);
32917 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32919 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32922 endUpdate : function(){
32923 this.layout.endUpdate();
32927 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32930 beginUpdate : function(){
32931 this.layout.beginUpdate();
32935 * Get the BorderLayout for this dialog
32936 * @return {Roo.BorderLayout}
32938 getLayout : function(){
32939 return this.layout;
32942 showEl : function(){
32943 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32945 this.layout.layout();
32950 // Use the syncHeightBeforeShow config option to control this automatically
32951 syncBodyHeight : function(){
32952 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32953 if(this.layout){this.layout.layout();}
32957 * Add an xtype element (actually adds to the layout.)
32958 * @return {Object} xdata xtype object data.
32961 addxtype : function(c) {
32962 return this.layout.addxtype(c);
32966 * Ext JS Library 1.1.1
32967 * Copyright(c) 2006-2007, Ext JS, LLC.
32969 * Originally Released Under LGPL - original licence link has changed is not relivant.
32972 * <script type="text/javascript">
32976 * @class Roo.MessageBox
32977 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32981 Roo.Msg.alert('Status', 'Changes saved successfully.');
32983 // Prompt for user data:
32984 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32986 // process text value...
32990 // Show a dialog using config options:
32992 title:'Save Changes?',
32993 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32994 buttons: Roo.Msg.YESNOCANCEL,
33001 Roo.MessageBox = function(){
33002 var dlg, opt, mask, waitTimer;
33003 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33004 var buttons, activeTextEl, bwidth;
33007 var handleButton = function(button){
33009 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33013 var handleHide = function(){
33014 if(opt && opt.cls){
33015 dlg.el.removeClass(opt.cls);
33018 Roo.TaskMgr.stop(waitTimer);
33024 var updateButtons = function(b){
33027 buttons["ok"].hide();
33028 buttons["cancel"].hide();
33029 buttons["yes"].hide();
33030 buttons["no"].hide();
33031 dlg.footer.dom.style.display = 'none';
33034 dlg.footer.dom.style.display = '';
33035 for(var k in buttons){
33036 if(typeof buttons[k] != "function"){
33039 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33040 width += buttons[k].el.getWidth()+15;
33050 var handleEsc = function(d, k, e){
33051 if(opt && opt.closable !== false){
33061 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33062 * @return {Roo.BasicDialog} The BasicDialog element
33064 getDialog : function(){
33066 dlg = new Roo.BasicDialog("x-msg-box", {
33071 constraintoviewport:false,
33073 collapsible : false,
33076 width:400, height:100,
33077 buttonAlign:"center",
33078 closeClick : function(){
33079 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33080 handleButton("no");
33082 handleButton("cancel");
33086 dlg.on("hide", handleHide);
33088 dlg.addKeyListener(27, handleEsc);
33090 var bt = this.buttonText;
33091 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33092 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33093 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33094 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33095 bodyEl = dlg.body.createChild({
33097 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>'
33099 msgEl = bodyEl.dom.firstChild;
33100 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33101 textboxEl.enableDisplayMode();
33102 textboxEl.addKeyListener([10,13], function(){
33103 if(dlg.isVisible() && opt && opt.buttons){
33104 if(opt.buttons.ok){
33105 handleButton("ok");
33106 }else if(opt.buttons.yes){
33107 handleButton("yes");
33111 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33112 textareaEl.enableDisplayMode();
33113 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33114 progressEl.enableDisplayMode();
33115 var pf = progressEl.dom.firstChild;
33117 pp = Roo.get(pf.firstChild);
33118 pp.setHeight(pf.offsetHeight);
33126 * Updates the message box body text
33127 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33128 * the XHTML-compliant non-breaking space character '&#160;')
33129 * @return {Roo.MessageBox} This message box
33131 updateText : function(text){
33132 if(!dlg.isVisible() && !opt.width){
33133 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33135 msgEl.innerHTML = text || ' ';
33137 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33138 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33140 Math.min(opt.width || cw , this.maxWidth),
33141 Math.max(opt.minWidth || this.minWidth, bwidth)
33144 activeTextEl.setWidth(w);
33146 if(dlg.isVisible()){
33147 dlg.fixedcenter = false;
33149 // to big, make it scroll. = But as usual stupid IE does not support
33152 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33153 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33154 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33156 bodyEl.dom.style.height = '';
33157 bodyEl.dom.style.overflowY = '';
33160 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33162 bodyEl.dom.style.overflowX = '';
33165 dlg.setContentSize(w, bodyEl.getHeight());
33166 if(dlg.isVisible()){
33167 dlg.fixedcenter = true;
33173 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33174 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33175 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33176 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33177 * @return {Roo.MessageBox} This message box
33179 updateProgress : function(value, text){
33181 this.updateText(text);
33183 if (pp) { // weird bug on my firefox - for some reason this is not defined
33184 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33190 * Returns true if the message box is currently displayed
33191 * @return {Boolean} True if the message box is visible, else false
33193 isVisible : function(){
33194 return dlg && dlg.isVisible();
33198 * Hides the message box if it is displayed
33201 if(this.isVisible()){
33207 * Displays a new message box, or reinitializes an existing message box, based on the config options
33208 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33209 * The following config object properties are supported:
33211 Property Type Description
33212 ---------- --------------- ------------------------------------------------------------------------------------
33213 animEl String/Element An id or Element from which the message box should animate as it opens and
33214 closes (defaults to undefined)
33215 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33216 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33217 closable Boolean False to hide the top-right close button (defaults to true). Note that
33218 progress and wait dialogs will ignore this property and always hide the
33219 close button as they can only be closed programmatically.
33220 cls String A custom CSS class to apply to the message box element
33221 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33222 displayed (defaults to 75)
33223 fn Function A callback function to execute after closing the dialog. The arguments to the
33224 function will be btn (the name of the button that was clicked, if applicable,
33225 e.g. "ok"), and text (the value of the active text field, if applicable).
33226 Progress and wait dialogs will ignore this option since they do not respond to
33227 user actions and can only be closed programmatically, so any required function
33228 should be called by the same code after it closes the dialog.
33229 icon String A CSS class that provides a background image to be used as an icon for
33230 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33231 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33232 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33233 modal Boolean False to allow user interaction with the page while the message box is
33234 displayed (defaults to true)
33235 msg String A string that will replace the existing message box body text (defaults
33236 to the XHTML-compliant non-breaking space character ' ')
33237 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33238 progress Boolean True to display a progress bar (defaults to false)
33239 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33240 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33241 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33242 title String The title text
33243 value String The string value to set into the active textbox element if displayed
33244 wait Boolean True to display a progress bar (defaults to false)
33245 width Number The width of the dialog in pixels
33252 msg: 'Please enter your address:',
33254 buttons: Roo.MessageBox.OKCANCEL,
33257 animEl: 'addAddressBtn'
33260 * @param {Object} config Configuration options
33261 * @return {Roo.MessageBox} This message box
33263 show : function(options)
33266 // this causes nightmares if you show one dialog after another
33267 // especially on callbacks..
33269 if(this.isVisible()){
33272 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33273 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33274 Roo.log("New Dialog Message:" + options.msg )
33275 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33276 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33279 var d = this.getDialog();
33281 d.setTitle(opt.title || " ");
33282 d.close.setDisplayed(opt.closable !== false);
33283 activeTextEl = textboxEl;
33284 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33289 textareaEl.setHeight(typeof opt.multiline == "number" ?
33290 opt.multiline : this.defaultTextHeight);
33291 activeTextEl = textareaEl;
33300 progressEl.setDisplayed(opt.progress === true);
33301 this.updateProgress(0);
33302 activeTextEl.dom.value = opt.value || "";
33304 dlg.setDefaultButton(activeTextEl);
33306 var bs = opt.buttons;
33309 db = buttons["ok"];
33310 }else if(bs && bs.yes){
33311 db = buttons["yes"];
33313 dlg.setDefaultButton(db);
33315 bwidth = updateButtons(opt.buttons);
33316 this.updateText(opt.msg);
33318 d.el.addClass(opt.cls);
33320 d.proxyDrag = opt.proxyDrag === true;
33321 d.modal = opt.modal !== false;
33322 d.mask = opt.modal !== false ? mask : false;
33323 if(!d.isVisible()){
33324 // force it to the end of the z-index stack so it gets a cursor in FF
33325 document.body.appendChild(dlg.el.dom);
33326 d.animateTarget = null;
33327 d.show(options.animEl);
33333 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33334 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33335 * and closing the message box when the process is complete.
33336 * @param {String} title The title bar text
33337 * @param {String} msg The message box body text
33338 * @return {Roo.MessageBox} This message box
33340 progress : function(title, msg){
33347 minWidth: this.minProgressWidth,
33354 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33355 * If a callback function is passed it will be called after the user clicks the button, and the
33356 * id of the button that was clicked will be passed as the only parameter to the callback
33357 * (could also be the top-right close button).
33358 * @param {String} title The title bar text
33359 * @param {String} msg The message box body text
33360 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33361 * @param {Object} scope (optional) The scope of the callback function
33362 * @return {Roo.MessageBox} This message box
33364 alert : function(title, msg, fn, scope){
33377 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33378 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33379 * You are responsible for closing the message box when the process is complete.
33380 * @param {String} msg The message box body text
33381 * @param {String} title (optional) The title bar text
33382 * @return {Roo.MessageBox} This message box
33384 wait : function(msg, title){
33395 waitTimer = Roo.TaskMgr.start({
33397 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33405 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33406 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33407 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33408 * @param {String} title The title bar text
33409 * @param {String} msg The message box body text
33410 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33411 * @param {Object} scope (optional) The scope of the callback function
33412 * @return {Roo.MessageBox} This message box
33414 confirm : function(title, msg, fn, scope){
33418 buttons: this.YESNO,
33427 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33428 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33429 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33430 * (could also be the top-right close button) and the text that was entered will be passed as the two
33431 * parameters to the callback.
33432 * @param {String} title The title bar text
33433 * @param {String} msg The message box body text
33434 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33435 * @param {Object} scope (optional) The scope of the callback function
33436 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33437 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33438 * @return {Roo.MessageBox} This message box
33440 prompt : function(title, msg, fn, scope, multiline){
33444 buttons: this.OKCANCEL,
33449 multiline: multiline,
33456 * Button config that displays a single OK button
33461 * Button config that displays Yes and No buttons
33464 YESNO : {yes:true, no:true},
33466 * Button config that displays OK and Cancel buttons
33469 OKCANCEL : {ok:true, cancel:true},
33471 * Button config that displays Yes, No and Cancel buttons
33474 YESNOCANCEL : {yes:true, no:true, cancel:true},
33477 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33480 defaultTextHeight : 75,
33482 * The maximum width in pixels of the message box (defaults to 600)
33487 * The minimum width in pixels of the message box (defaults to 100)
33492 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33493 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33496 minProgressWidth : 250,
33498 * An object containing the default button text strings that can be overriden for localized language support.
33499 * Supported properties are: ok, cancel, yes and no.
33500 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33513 * Shorthand for {@link Roo.MessageBox}
33515 Roo.Msg = Roo.MessageBox;/*
33517 * Ext JS Library 1.1.1
33518 * Copyright(c) 2006-2007, Ext JS, LLC.
33520 * Originally Released Under LGPL - original licence link has changed is not relivant.
33523 * <script type="text/javascript">
33526 * @class Roo.QuickTips
33527 * Provides attractive and customizable tooltips for any element.
33530 Roo.QuickTips = function(){
33531 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33532 var ce, bd, xy, dd;
33533 var visible = false, disabled = true, inited = false;
33534 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33536 var onOver = function(e){
33540 var t = e.getTarget();
33541 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33544 if(ce && t == ce.el){
33545 clearTimeout(hideProc);
33548 if(t && tagEls[t.id]){
33549 tagEls[t.id].el = t;
33550 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33553 var ttp, et = Roo.fly(t);
33554 var ns = cfg.namespace;
33555 if(tm.interceptTitles && t.title){
33558 t.removeAttribute("title");
33559 e.preventDefault();
33561 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33564 showProc = show.defer(tm.showDelay, tm, [{
33567 width: et.getAttributeNS(ns, cfg.width),
33568 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33569 title: et.getAttributeNS(ns, cfg.title),
33570 cls: et.getAttributeNS(ns, cfg.cls)
33575 var onOut = function(e){
33576 clearTimeout(showProc);
33577 var t = e.getTarget();
33578 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33579 hideProc = setTimeout(hide, tm.hideDelay);
33583 var onMove = function(e){
33589 if(tm.trackMouse && ce){
33594 var onDown = function(e){
33595 clearTimeout(showProc);
33596 clearTimeout(hideProc);
33598 if(tm.hideOnClick){
33601 tm.enable.defer(100, tm);
33606 var getPad = function(){
33607 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33610 var show = function(o){
33614 clearTimeout(dismissProc);
33616 if(removeCls){ // in case manually hidden
33617 el.removeClass(removeCls);
33621 el.addClass(ce.cls);
33622 removeCls = ce.cls;
33625 tipTitle.update(ce.title);
33628 tipTitle.update('');
33631 el.dom.style.width = tm.maxWidth+'px';
33632 //tipBody.dom.style.width = '';
33633 tipBodyText.update(o.text);
33634 var p = getPad(), w = ce.width;
33636 var td = tipBodyText.dom;
33637 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33638 if(aw > tm.maxWidth){
33640 }else if(aw < tm.minWidth){
33646 //tipBody.setWidth(w);
33647 el.setWidth(parseInt(w, 10) + p);
33648 if(ce.autoHide === false){
33649 close.setDisplayed(true);
33654 close.setDisplayed(false);
33660 el.avoidY = xy[1]-18;
33665 el.setStyle("visibility", "visible");
33666 el.fadeIn({callback: afterShow});
33672 var afterShow = function(){
33676 if(tm.autoDismiss && ce.autoHide !== false){
33677 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33682 var hide = function(noanim){
33683 clearTimeout(dismissProc);
33684 clearTimeout(hideProc);
33686 if(el.isVisible()){
33688 if(noanim !== true && tm.animate){
33689 el.fadeOut({callback: afterHide});
33696 var afterHide = function(){
33699 el.removeClass(removeCls);
33706 * @cfg {Number} minWidth
33707 * The minimum width of the quick tip (defaults to 40)
33711 * @cfg {Number} maxWidth
33712 * The maximum width of the quick tip (defaults to 300)
33716 * @cfg {Boolean} interceptTitles
33717 * True to automatically use the element's DOM title value if available (defaults to false)
33719 interceptTitles : false,
33721 * @cfg {Boolean} trackMouse
33722 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33724 trackMouse : false,
33726 * @cfg {Boolean} hideOnClick
33727 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33729 hideOnClick : true,
33731 * @cfg {Number} showDelay
33732 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33736 * @cfg {Number} hideDelay
33737 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33741 * @cfg {Boolean} autoHide
33742 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33743 * Used in conjunction with hideDelay.
33748 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33749 * (defaults to true). Used in conjunction with autoDismissDelay.
33751 autoDismiss : true,
33754 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33756 autoDismissDelay : 5000,
33758 * @cfg {Boolean} animate
33759 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33764 * @cfg {String} title
33765 * Title text to display (defaults to ''). This can be any valid HTML markup.
33769 * @cfg {String} text
33770 * Body text to display (defaults to ''). This can be any valid HTML markup.
33774 * @cfg {String} cls
33775 * A CSS class to apply to the base quick tip element (defaults to '').
33779 * @cfg {Number} width
33780 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33781 * minWidth or maxWidth.
33786 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33787 * or display QuickTips in a page.
33790 tm = Roo.QuickTips;
33791 cfg = tm.tagConfig;
33793 if(!Roo.isReady){ // allow calling of init() before onReady
33794 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33797 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33798 el.fxDefaults = {stopFx: true};
33799 // maximum custom styling
33800 //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>');
33801 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>');
33802 tipTitle = el.child('h3');
33803 tipTitle.enableDisplayMode("block");
33804 tipBody = el.child('div.x-tip-bd');
33805 tipBodyText = el.child('div.x-tip-bd-inner');
33806 //bdLeft = el.child('div.x-tip-bd-left');
33807 //bdRight = el.child('div.x-tip-bd-right');
33808 close = el.child('div.x-tip-close');
33809 close.enableDisplayMode("block");
33810 close.on("click", hide);
33811 var d = Roo.get(document);
33812 d.on("mousedown", onDown);
33813 d.on("mouseover", onOver);
33814 d.on("mouseout", onOut);
33815 d.on("mousemove", onMove);
33816 esc = d.addKeyListener(27, hide);
33819 dd = el.initDD("default", null, {
33820 onDrag : function(){
33824 dd.setHandleElId(tipTitle.id);
33833 * Configures a new quick tip instance and assigns it to a target element. The following config options
33836 Property Type Description
33837 ---------- --------------------- ------------------------------------------------------------------------
33838 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33840 * @param {Object} config The config object
33842 register : function(config){
33843 var cs = config instanceof Array ? config : arguments;
33844 for(var i = 0, len = cs.length; i < len; i++) {
33846 var target = c.target;
33848 if(target instanceof Array){
33849 for(var j = 0, jlen = target.length; j < jlen; j++){
33850 tagEls[target[j]] = c;
33853 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33860 * Removes this quick tip from its element and destroys it.
33861 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33863 unregister : function(el){
33864 delete tagEls[Roo.id(el)];
33868 * Enable this quick tip.
33870 enable : function(){
33871 if(inited && disabled){
33873 if(locks.length < 1){
33880 * Disable this quick tip.
33882 disable : function(){
33884 clearTimeout(showProc);
33885 clearTimeout(hideProc);
33886 clearTimeout(dismissProc);
33894 * Returns true if the quick tip is enabled, else false.
33896 isEnabled : function(){
33902 namespace : "roo", // was ext?? this may break..
33903 alt_namespace : "ext",
33904 attribute : "qtip",
33914 // backwards compat
33915 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33917 * Ext JS Library 1.1.1
33918 * Copyright(c) 2006-2007, Ext JS, LLC.
33920 * Originally Released Under LGPL - original licence link has changed is not relivant.
33923 * <script type="text/javascript">
33928 * @class Roo.tree.TreePanel
33929 * @extends Roo.data.Tree
33931 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33932 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33933 * @cfg {Boolean} enableDD true to enable drag and drop
33934 * @cfg {Boolean} enableDrag true to enable just drag
33935 * @cfg {Boolean} enableDrop true to enable just drop
33936 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33937 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33938 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33939 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33940 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33941 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33942 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33943 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33944 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33945 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33946 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33947 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33948 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33949 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33950 * @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>
33951 * @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>
33954 * @param {String/HTMLElement/Element} el The container element
33955 * @param {Object} config
33957 Roo.tree.TreePanel = function(el, config){
33959 var loader = false;
33961 root = config.root;
33962 delete config.root;
33964 if (config.loader) {
33965 loader = config.loader;
33966 delete config.loader;
33969 Roo.apply(this, config);
33970 Roo.tree.TreePanel.superclass.constructor.call(this);
33971 this.el = Roo.get(el);
33972 this.el.addClass('x-tree');
33973 //console.log(root);
33975 this.setRootNode( Roo.factory(root, Roo.tree));
33978 this.loader = Roo.factory(loader, Roo.tree);
33981 * Read-only. The id of the container element becomes this TreePanel's id.
33983 this.id = this.el.id;
33986 * @event beforeload
33987 * Fires before a node is loaded, return false to cancel
33988 * @param {Node} node The node being loaded
33990 "beforeload" : true,
33993 * Fires when a node is loaded
33994 * @param {Node} node The node that was loaded
33998 * @event textchange
33999 * Fires when the text for a node is changed
34000 * @param {Node} node The node
34001 * @param {String} text The new text
34002 * @param {String} oldText The old text
34004 "textchange" : true,
34006 * @event beforeexpand
34007 * Fires before a node is expanded, return false to cancel.
34008 * @param {Node} node The node
34009 * @param {Boolean} deep
34010 * @param {Boolean} anim
34012 "beforeexpand" : true,
34014 * @event beforecollapse
34015 * Fires before a node is collapsed, return false to cancel.
34016 * @param {Node} node The node
34017 * @param {Boolean} deep
34018 * @param {Boolean} anim
34020 "beforecollapse" : true,
34023 * Fires when a node is expanded
34024 * @param {Node} node The node
34028 * @event disabledchange
34029 * Fires when the disabled status of a node changes
34030 * @param {Node} node The node
34031 * @param {Boolean} disabled
34033 "disabledchange" : true,
34036 * Fires when a node is collapsed
34037 * @param {Node} node The node
34041 * @event beforeclick
34042 * Fires before click processing on a node. Return false to cancel the default action.
34043 * @param {Node} node The node
34044 * @param {Roo.EventObject} e The event object
34046 "beforeclick":true,
34048 * @event checkchange
34049 * Fires when a node with a checkbox's checked property changes
34050 * @param {Node} this This node
34051 * @param {Boolean} checked
34053 "checkchange":true,
34056 * Fires when a node is clicked
34057 * @param {Node} node The node
34058 * @param {Roo.EventObject} e The event object
34063 * Fires when a node is double clicked
34064 * @param {Node} node The node
34065 * @param {Roo.EventObject} e The event object
34069 * @event contextmenu
34070 * Fires when a node is right clicked
34071 * @param {Node} node The node
34072 * @param {Roo.EventObject} e The event object
34074 "contextmenu":true,
34076 * @event beforechildrenrendered
34077 * Fires right before the child nodes for a node are rendered
34078 * @param {Node} node The node
34080 "beforechildrenrendered":true,
34083 * Fires when a node starts being dragged
34084 * @param {Roo.tree.TreePanel} this
34085 * @param {Roo.tree.TreeNode} node
34086 * @param {event} e The raw browser event
34088 "startdrag" : true,
34091 * Fires when a drag operation is complete
34092 * @param {Roo.tree.TreePanel} this
34093 * @param {Roo.tree.TreeNode} node
34094 * @param {event} e The raw browser event
34099 * Fires when a dragged node is dropped on a valid DD target
34100 * @param {Roo.tree.TreePanel} this
34101 * @param {Roo.tree.TreeNode} node
34102 * @param {DD} dd The dd it was dropped on
34103 * @param {event} e The raw browser event
34107 * @event beforenodedrop
34108 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34109 * passed to handlers has the following properties:<br />
34110 * <ul style="padding:5px;padding-left:16px;">
34111 * <li>tree - The TreePanel</li>
34112 * <li>target - The node being targeted for the drop</li>
34113 * <li>data - The drag data from the drag source</li>
34114 * <li>point - The point of the drop - append, above or below</li>
34115 * <li>source - The drag source</li>
34116 * <li>rawEvent - Raw mouse event</li>
34117 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34118 * to be inserted by setting them on this object.</li>
34119 * <li>cancel - Set this to true to cancel the drop.</li>
34121 * @param {Object} dropEvent
34123 "beforenodedrop" : true,
34126 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34127 * passed to handlers has the following properties:<br />
34128 * <ul style="padding:5px;padding-left:16px;">
34129 * <li>tree - The TreePanel</li>
34130 * <li>target - The node being targeted for the drop</li>
34131 * <li>data - The drag data from the drag source</li>
34132 * <li>point - The point of the drop - append, above or below</li>
34133 * <li>source - The drag source</li>
34134 * <li>rawEvent - Raw mouse event</li>
34135 * <li>dropNode - Dropped node(s).</li>
34137 * @param {Object} dropEvent
34141 * @event nodedragover
34142 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34143 * passed to handlers has the following properties:<br />
34144 * <ul style="padding:5px;padding-left:16px;">
34145 * <li>tree - The TreePanel</li>
34146 * <li>target - The node being targeted for the drop</li>
34147 * <li>data - The drag data from the drag source</li>
34148 * <li>point - The point of the drop - append, above or below</li>
34149 * <li>source - The drag source</li>
34150 * <li>rawEvent - Raw mouse event</li>
34151 * <li>dropNode - Drop node(s) provided by the source.</li>
34152 * <li>cancel - Set this to true to signal drop not allowed.</li>
34154 * @param {Object} dragOverEvent
34156 "nodedragover" : true
34159 if(this.singleExpand){
34160 this.on("beforeexpand", this.restrictExpand, this);
34163 this.editor.tree = this;
34164 this.editor = Roo.factory(this.editor, Roo.tree);
34167 if (this.selModel) {
34168 this.selModel = Roo.factory(this.selModel, Roo.tree);
34172 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34173 rootVisible : true,
34174 animate: Roo.enableFx,
34177 hlDrop : Roo.enableFx,
34181 rendererTip: false,
34183 restrictExpand : function(node){
34184 var p = node.parentNode;
34186 if(p.expandedChild && p.expandedChild.parentNode == p){
34187 p.expandedChild.collapse();
34189 p.expandedChild = node;
34193 // private override
34194 setRootNode : function(node){
34195 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34196 if(!this.rootVisible){
34197 node.ui = new Roo.tree.RootTreeNodeUI(node);
34203 * Returns the container element for this TreePanel
34205 getEl : function(){
34210 * Returns the default TreeLoader for this TreePanel
34212 getLoader : function(){
34213 return this.loader;
34219 expandAll : function(){
34220 this.root.expand(true);
34224 * Collapse all nodes
34226 collapseAll : function(){
34227 this.root.collapse(true);
34231 * Returns the selection model used by this TreePanel
34233 getSelectionModel : function(){
34234 if(!this.selModel){
34235 this.selModel = new Roo.tree.DefaultSelectionModel();
34237 return this.selModel;
34241 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34242 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34243 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34246 getChecked : function(a, startNode){
34247 startNode = startNode || this.root;
34249 var f = function(){
34250 if(this.attributes.checked){
34251 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34254 startNode.cascade(f);
34259 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34260 * @param {String} path
34261 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34262 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34263 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34265 expandPath : function(path, attr, callback){
34266 attr = attr || "id";
34267 var keys = path.split(this.pathSeparator);
34268 var curNode = this.root;
34269 if(curNode.attributes[attr] != keys[1]){ // invalid root
34271 callback(false, null);
34276 var f = function(){
34277 if(++index == keys.length){
34279 callback(true, curNode);
34283 var c = curNode.findChild(attr, keys[index]);
34286 callback(false, curNode);
34291 c.expand(false, false, f);
34293 curNode.expand(false, false, f);
34297 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34298 * @param {String} path
34299 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34300 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34301 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34303 selectPath : function(path, attr, callback){
34304 attr = attr || "id";
34305 var keys = path.split(this.pathSeparator);
34306 var v = keys.pop();
34307 if(keys.length > 0){
34308 var f = function(success, node){
34309 if(success && node){
34310 var n = node.findChild(attr, v);
34316 }else if(callback){
34317 callback(false, n);
34321 callback(false, n);
34325 this.expandPath(keys.join(this.pathSeparator), attr, f);
34327 this.root.select();
34329 callback(true, this.root);
34334 getTreeEl : function(){
34339 * Trigger rendering of this TreePanel
34341 render : function(){
34342 if (this.innerCt) {
34343 return this; // stop it rendering more than once!!
34346 this.innerCt = this.el.createChild({tag:"ul",
34347 cls:"x-tree-root-ct " +
34348 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34350 if(this.containerScroll){
34351 Roo.dd.ScrollManager.register(this.el);
34353 if((this.enableDD || this.enableDrop) && !this.dropZone){
34355 * The dropZone used by this tree if drop is enabled
34356 * @type Roo.tree.TreeDropZone
34358 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34359 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34362 if((this.enableDD || this.enableDrag) && !this.dragZone){
34364 * The dragZone used by this tree if drag is enabled
34365 * @type Roo.tree.TreeDragZone
34367 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34368 ddGroup: this.ddGroup || "TreeDD",
34369 scroll: this.ddScroll
34372 this.getSelectionModel().init(this);
34374 Roo.log("ROOT not set in tree");
34377 this.root.render();
34378 if(!this.rootVisible){
34379 this.root.renderChildren();
34385 * Ext JS Library 1.1.1
34386 * Copyright(c) 2006-2007, Ext JS, LLC.
34388 * Originally Released Under LGPL - original licence link has changed is not relivant.
34391 * <script type="text/javascript">
34396 * @class Roo.tree.DefaultSelectionModel
34397 * @extends Roo.util.Observable
34398 * The default single selection for a TreePanel.
34399 * @param {Object} cfg Configuration
34401 Roo.tree.DefaultSelectionModel = function(cfg){
34402 this.selNode = null;
34408 * @event selectionchange
34409 * Fires when the selected node changes
34410 * @param {DefaultSelectionModel} this
34411 * @param {TreeNode} node the new selection
34413 "selectionchange" : true,
34416 * @event beforeselect
34417 * Fires before the selected node changes, return false to cancel the change
34418 * @param {DefaultSelectionModel} this
34419 * @param {TreeNode} node the new selection
34420 * @param {TreeNode} node the old selection
34422 "beforeselect" : true
34425 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34428 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34429 init : function(tree){
34431 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34432 tree.on("click", this.onNodeClick, this);
34435 onNodeClick : function(node, e){
34436 if (e.ctrlKey && this.selNode == node) {
34437 this.unselect(node);
34445 * @param {TreeNode} node The node to select
34446 * @return {TreeNode} The selected node
34448 select : function(node){
34449 var last = this.selNode;
34450 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34452 last.ui.onSelectedChange(false);
34454 this.selNode = node;
34455 node.ui.onSelectedChange(true);
34456 this.fireEvent("selectionchange", this, node, last);
34463 * @param {TreeNode} node The node to unselect
34465 unselect : function(node){
34466 if(this.selNode == node){
34467 this.clearSelections();
34472 * Clear all selections
34474 clearSelections : function(){
34475 var n = this.selNode;
34477 n.ui.onSelectedChange(false);
34478 this.selNode = null;
34479 this.fireEvent("selectionchange", this, null);
34485 * Get the selected node
34486 * @return {TreeNode} The selected node
34488 getSelectedNode : function(){
34489 return this.selNode;
34493 * Returns true if the node is selected
34494 * @param {TreeNode} node The node to check
34495 * @return {Boolean}
34497 isSelected : function(node){
34498 return this.selNode == node;
34502 * Selects the node above the selected node in the tree, intelligently walking the nodes
34503 * @return TreeNode The new selection
34505 selectPrevious : function(){
34506 var s = this.selNode || this.lastSelNode;
34510 var ps = s.previousSibling;
34512 if(!ps.isExpanded() || ps.childNodes.length < 1){
34513 return this.select(ps);
34515 var lc = ps.lastChild;
34516 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34519 return this.select(lc);
34521 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34522 return this.select(s.parentNode);
34528 * Selects the node above the selected node in the tree, intelligently walking the nodes
34529 * @return TreeNode The new selection
34531 selectNext : function(){
34532 var s = this.selNode || this.lastSelNode;
34536 if(s.firstChild && s.isExpanded()){
34537 return this.select(s.firstChild);
34538 }else if(s.nextSibling){
34539 return this.select(s.nextSibling);
34540 }else if(s.parentNode){
34542 s.parentNode.bubble(function(){
34543 if(this.nextSibling){
34544 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34553 onKeyDown : function(e){
34554 var s = this.selNode || this.lastSelNode;
34555 // undesirable, but required
34560 var k = e.getKey();
34568 this.selectPrevious();
34571 e.preventDefault();
34572 if(s.hasChildNodes()){
34573 if(!s.isExpanded()){
34575 }else if(s.firstChild){
34576 this.select(s.firstChild, e);
34581 e.preventDefault();
34582 if(s.hasChildNodes() && s.isExpanded()){
34584 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34585 this.select(s.parentNode, e);
34593 * @class Roo.tree.MultiSelectionModel
34594 * @extends Roo.util.Observable
34595 * Multi selection for a TreePanel.
34596 * @param {Object} cfg Configuration
34598 Roo.tree.MultiSelectionModel = function(){
34599 this.selNodes = [];
34603 * @event selectionchange
34604 * Fires when the selected nodes change
34605 * @param {MultiSelectionModel} this
34606 * @param {Array} nodes Array of the selected nodes
34608 "selectionchange" : true
34610 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34614 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34615 init : function(tree){
34617 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34618 tree.on("click", this.onNodeClick, this);
34621 onNodeClick : function(node, e){
34622 this.select(node, e, e.ctrlKey);
34627 * @param {TreeNode} node The node to select
34628 * @param {EventObject} e (optional) An event associated with the selection
34629 * @param {Boolean} keepExisting True to retain existing selections
34630 * @return {TreeNode} The selected node
34632 select : function(node, e, keepExisting){
34633 if(keepExisting !== true){
34634 this.clearSelections(true);
34636 if(this.isSelected(node)){
34637 this.lastSelNode = node;
34640 this.selNodes.push(node);
34641 this.selMap[node.id] = node;
34642 this.lastSelNode = node;
34643 node.ui.onSelectedChange(true);
34644 this.fireEvent("selectionchange", this, this.selNodes);
34650 * @param {TreeNode} node The node to unselect
34652 unselect : function(node){
34653 if(this.selMap[node.id]){
34654 node.ui.onSelectedChange(false);
34655 var sn = this.selNodes;
34658 index = sn.indexOf(node);
34660 for(var i = 0, len = sn.length; i < len; i++){
34668 this.selNodes.splice(index, 1);
34670 delete this.selMap[node.id];
34671 this.fireEvent("selectionchange", this, this.selNodes);
34676 * Clear all selections
34678 clearSelections : function(suppressEvent){
34679 var sn = this.selNodes;
34681 for(var i = 0, len = sn.length; i < len; i++){
34682 sn[i].ui.onSelectedChange(false);
34684 this.selNodes = [];
34686 if(suppressEvent !== true){
34687 this.fireEvent("selectionchange", this, this.selNodes);
34693 * Returns true if the node is selected
34694 * @param {TreeNode} node The node to check
34695 * @return {Boolean}
34697 isSelected : function(node){
34698 return this.selMap[node.id] ? true : false;
34702 * Returns an array of the selected nodes
34705 getSelectedNodes : function(){
34706 return this.selNodes;
34709 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34711 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34713 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34716 * Ext JS Library 1.1.1
34717 * Copyright(c) 2006-2007, Ext JS, LLC.
34719 * Originally Released Under LGPL - original licence link has changed is not relivant.
34722 * <script type="text/javascript">
34726 * @class Roo.tree.TreeNode
34727 * @extends Roo.data.Node
34728 * @cfg {String} text The text for this node
34729 * @cfg {Boolean} expanded true to start the node expanded
34730 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34731 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34732 * @cfg {Boolean} disabled true to start the node disabled
34733 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34734 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34735 * @cfg {String} cls A css class to be added to the node
34736 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34737 * @cfg {String} href URL of the link used for the node (defaults to #)
34738 * @cfg {String} hrefTarget target frame for the link
34739 * @cfg {String} qtip An Ext QuickTip for the node
34740 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34741 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34742 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34743 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34744 * (defaults to undefined with no checkbox rendered)
34746 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34748 Roo.tree.TreeNode = function(attributes){
34749 attributes = attributes || {};
34750 if(typeof attributes == "string"){
34751 attributes = {text: attributes};
34753 this.childrenRendered = false;
34754 this.rendered = false;
34755 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34756 this.expanded = attributes.expanded === true;
34757 this.isTarget = attributes.isTarget !== false;
34758 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34759 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34762 * Read-only. The text for this node. To change it use setText().
34765 this.text = attributes.text;
34767 * True if this node is disabled.
34770 this.disabled = attributes.disabled === true;
34774 * @event textchange
34775 * Fires when the text for this node is changed
34776 * @param {Node} this This node
34777 * @param {String} text The new text
34778 * @param {String} oldText The old text
34780 "textchange" : true,
34782 * @event beforeexpand
34783 * Fires before this node is expanded, return false to cancel.
34784 * @param {Node} this This node
34785 * @param {Boolean} deep
34786 * @param {Boolean} anim
34788 "beforeexpand" : true,
34790 * @event beforecollapse
34791 * Fires before this node is collapsed, return false to cancel.
34792 * @param {Node} this This node
34793 * @param {Boolean} deep
34794 * @param {Boolean} anim
34796 "beforecollapse" : true,
34799 * Fires when this node is expanded
34800 * @param {Node} this This node
34804 * @event disabledchange
34805 * Fires when the disabled status of this node changes
34806 * @param {Node} this This node
34807 * @param {Boolean} disabled
34809 "disabledchange" : true,
34812 * Fires when this node is collapsed
34813 * @param {Node} this This node
34817 * @event beforeclick
34818 * Fires before click processing. Return false to cancel the default action.
34819 * @param {Node} this This node
34820 * @param {Roo.EventObject} e The event object
34822 "beforeclick":true,
34824 * @event checkchange
34825 * Fires when a node with a checkbox's checked property changes
34826 * @param {Node} this This node
34827 * @param {Boolean} checked
34829 "checkchange":true,
34832 * Fires when this node is clicked
34833 * @param {Node} this This node
34834 * @param {Roo.EventObject} e The event object
34839 * Fires when this node is double clicked
34840 * @param {Node} this This node
34841 * @param {Roo.EventObject} e The event object
34845 * @event contextmenu
34846 * Fires when this node is right clicked
34847 * @param {Node} this This node
34848 * @param {Roo.EventObject} e The event object
34850 "contextmenu":true,
34852 * @event beforechildrenrendered
34853 * Fires right before the child nodes for this node are rendered
34854 * @param {Node} this This node
34856 "beforechildrenrendered":true
34859 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34862 * Read-only. The UI for this node
34865 this.ui = new uiClass(this);
34867 // finally support items[]
34868 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34873 Roo.each(this.attributes.items, function(c) {
34874 this.appendChild(Roo.factory(c,Roo.Tree));
34876 delete this.attributes.items;
34881 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34882 preventHScroll: true,
34884 * Returns true if this node is expanded
34885 * @return {Boolean}
34887 isExpanded : function(){
34888 return this.expanded;
34892 * Returns the UI object for this node
34893 * @return {TreeNodeUI}
34895 getUI : function(){
34899 // private override
34900 setFirstChild : function(node){
34901 var of = this.firstChild;
34902 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34903 if(this.childrenRendered && of && node != of){
34904 of.renderIndent(true, true);
34907 this.renderIndent(true, true);
34911 // private override
34912 setLastChild : function(node){
34913 var ol = this.lastChild;
34914 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34915 if(this.childrenRendered && ol && node != ol){
34916 ol.renderIndent(true, true);
34919 this.renderIndent(true, true);
34923 // these methods are overridden to provide lazy rendering support
34924 // private override
34925 appendChild : function()
34927 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34928 if(node && this.childrenRendered){
34931 this.ui.updateExpandIcon();
34935 // private override
34936 removeChild : function(node){
34937 this.ownerTree.getSelectionModel().unselect(node);
34938 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34939 // if it's been rendered remove dom node
34940 if(this.childrenRendered){
34943 if(this.childNodes.length < 1){
34944 this.collapse(false, false);
34946 this.ui.updateExpandIcon();
34948 if(!this.firstChild) {
34949 this.childrenRendered = false;
34954 // private override
34955 insertBefore : function(node, refNode){
34956 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34957 if(newNode && refNode && this.childrenRendered){
34960 this.ui.updateExpandIcon();
34965 * Sets the text for this node
34966 * @param {String} text
34968 setText : function(text){
34969 var oldText = this.text;
34971 this.attributes.text = text;
34972 if(this.rendered){ // event without subscribing
34973 this.ui.onTextChange(this, text, oldText);
34975 this.fireEvent("textchange", this, text, oldText);
34979 * Triggers selection of this node
34981 select : function(){
34982 this.getOwnerTree().getSelectionModel().select(this);
34986 * Triggers deselection of this node
34988 unselect : function(){
34989 this.getOwnerTree().getSelectionModel().unselect(this);
34993 * Returns true if this node is selected
34994 * @return {Boolean}
34996 isSelected : function(){
34997 return this.getOwnerTree().getSelectionModel().isSelected(this);
35001 * Expand this node.
35002 * @param {Boolean} deep (optional) True to expand all children as well
35003 * @param {Boolean} anim (optional) false to cancel the default animation
35004 * @param {Function} callback (optional) A callback to be called when
35005 * expanding this node completes (does not wait for deep expand to complete).
35006 * Called with 1 parameter, this node.
35008 expand : function(deep, anim, callback){
35009 if(!this.expanded){
35010 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35013 if(!this.childrenRendered){
35014 this.renderChildren();
35016 this.expanded = true;
35017 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35018 this.ui.animExpand(function(){
35019 this.fireEvent("expand", this);
35020 if(typeof callback == "function"){
35024 this.expandChildNodes(true);
35026 }.createDelegate(this));
35030 this.fireEvent("expand", this);
35031 if(typeof callback == "function"){
35036 if(typeof callback == "function"){
35041 this.expandChildNodes(true);
35045 isHiddenRoot : function(){
35046 return this.isRoot && !this.getOwnerTree().rootVisible;
35050 * Collapse this node.
35051 * @param {Boolean} deep (optional) True to collapse all children as well
35052 * @param {Boolean} anim (optional) false to cancel the default animation
35054 collapse : function(deep, anim){
35055 if(this.expanded && !this.isHiddenRoot()){
35056 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35059 this.expanded = false;
35060 if((this.getOwnerTree().animate && anim !== false) || anim){
35061 this.ui.animCollapse(function(){
35062 this.fireEvent("collapse", this);
35064 this.collapseChildNodes(true);
35066 }.createDelegate(this));
35069 this.ui.collapse();
35070 this.fireEvent("collapse", this);
35074 var cs = this.childNodes;
35075 for(var i = 0, len = cs.length; i < len; i++) {
35076 cs[i].collapse(true, false);
35082 delayedExpand : function(delay){
35083 if(!this.expandProcId){
35084 this.expandProcId = this.expand.defer(delay, this);
35089 cancelExpand : function(){
35090 if(this.expandProcId){
35091 clearTimeout(this.expandProcId);
35093 this.expandProcId = false;
35097 * Toggles expanded/collapsed state of the node
35099 toggle : function(){
35108 * Ensures all parent nodes are expanded
35110 ensureVisible : function(callback){
35111 var tree = this.getOwnerTree();
35112 tree.expandPath(this.parentNode.getPath(), false, function(){
35113 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35114 Roo.callback(callback);
35115 }.createDelegate(this));
35119 * Expand all child nodes
35120 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35122 expandChildNodes : function(deep){
35123 var cs = this.childNodes;
35124 for(var i = 0, len = cs.length; i < len; i++) {
35125 cs[i].expand(deep);
35130 * Collapse all child nodes
35131 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35133 collapseChildNodes : function(deep){
35134 var cs = this.childNodes;
35135 for(var i = 0, len = cs.length; i < len; i++) {
35136 cs[i].collapse(deep);
35141 * Disables this node
35143 disable : function(){
35144 this.disabled = true;
35146 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35147 this.ui.onDisableChange(this, true);
35149 this.fireEvent("disabledchange", this, true);
35153 * Enables this node
35155 enable : function(){
35156 this.disabled = false;
35157 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35158 this.ui.onDisableChange(this, false);
35160 this.fireEvent("disabledchange", this, false);
35164 renderChildren : function(suppressEvent){
35165 if(suppressEvent !== false){
35166 this.fireEvent("beforechildrenrendered", this);
35168 var cs = this.childNodes;
35169 for(var i = 0, len = cs.length; i < len; i++){
35170 cs[i].render(true);
35172 this.childrenRendered = true;
35176 sort : function(fn, scope){
35177 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35178 if(this.childrenRendered){
35179 var cs = this.childNodes;
35180 for(var i = 0, len = cs.length; i < len; i++){
35181 cs[i].render(true);
35187 render : function(bulkRender){
35188 this.ui.render(bulkRender);
35189 if(!this.rendered){
35190 this.rendered = true;
35192 this.expanded = false;
35193 this.expand(false, false);
35199 renderIndent : function(deep, refresh){
35201 this.ui.childIndent = null;
35203 this.ui.renderIndent();
35204 if(deep === true && this.childrenRendered){
35205 var cs = this.childNodes;
35206 for(var i = 0, len = cs.length; i < len; i++){
35207 cs[i].renderIndent(true, refresh);
35213 * Ext JS Library 1.1.1
35214 * Copyright(c) 2006-2007, Ext JS, LLC.
35216 * Originally Released Under LGPL - original licence link has changed is not relivant.
35219 * <script type="text/javascript">
35223 * @class Roo.tree.AsyncTreeNode
35224 * @extends Roo.tree.TreeNode
35225 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35227 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35229 Roo.tree.AsyncTreeNode = function(config){
35230 this.loaded = false;
35231 this.loading = false;
35232 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35234 * @event beforeload
35235 * Fires before this node is loaded, return false to cancel
35236 * @param {Node} this This node
35238 this.addEvents({'beforeload':true, 'load': true});
35241 * Fires when this node is loaded
35242 * @param {Node} this This node
35245 * The loader used by this node (defaults to using the tree's defined loader)
35250 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35251 expand : function(deep, anim, callback){
35252 if(this.loading){ // if an async load is already running, waiting til it's done
35254 var f = function(){
35255 if(!this.loading){ // done loading
35256 clearInterval(timer);
35257 this.expand(deep, anim, callback);
35259 }.createDelegate(this);
35260 timer = setInterval(f, 200);
35264 if(this.fireEvent("beforeload", this) === false){
35267 this.loading = true;
35268 this.ui.beforeLoad(this);
35269 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35271 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35275 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35279 * Returns true if this node is currently loading
35280 * @return {Boolean}
35282 isLoading : function(){
35283 return this.loading;
35286 loadComplete : function(deep, anim, callback){
35287 this.loading = false;
35288 this.loaded = true;
35289 this.ui.afterLoad(this);
35290 this.fireEvent("load", this);
35291 this.expand(deep, anim, callback);
35295 * Returns true if this node has been loaded
35296 * @return {Boolean}
35298 isLoaded : function(){
35299 return this.loaded;
35302 hasChildNodes : function(){
35303 if(!this.isLeaf() && !this.loaded){
35306 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35311 * Trigger a reload for this node
35312 * @param {Function} callback
35314 reload : function(callback){
35315 this.collapse(false, false);
35316 while(this.firstChild){
35317 this.removeChild(this.firstChild);
35319 this.childrenRendered = false;
35320 this.loaded = false;
35321 if(this.isHiddenRoot()){
35322 this.expanded = false;
35324 this.expand(false, false, callback);
35328 * Ext JS Library 1.1.1
35329 * Copyright(c) 2006-2007, Ext JS, LLC.
35331 * Originally Released Under LGPL - original licence link has changed is not relivant.
35334 * <script type="text/javascript">
35338 * @class Roo.tree.TreeNodeUI
35340 * @param {Object} node The node to render
35341 * The TreeNode UI implementation is separate from the
35342 * tree implementation. Unless you are customizing the tree UI,
35343 * you should never have to use this directly.
35345 Roo.tree.TreeNodeUI = function(node){
35347 this.rendered = false;
35348 this.animating = false;
35349 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35352 Roo.tree.TreeNodeUI.prototype = {
35353 removeChild : function(node){
35355 this.ctNode.removeChild(node.ui.getEl());
35359 beforeLoad : function(){
35360 this.addClass("x-tree-node-loading");
35363 afterLoad : function(){
35364 this.removeClass("x-tree-node-loading");
35367 onTextChange : function(node, text, oldText){
35369 this.textNode.innerHTML = text;
35373 onDisableChange : function(node, state){
35374 this.disabled = state;
35376 this.addClass("x-tree-node-disabled");
35378 this.removeClass("x-tree-node-disabled");
35382 onSelectedChange : function(state){
35385 this.addClass("x-tree-selected");
35388 this.removeClass("x-tree-selected");
35392 onMove : function(tree, node, oldParent, newParent, index, refNode){
35393 this.childIndent = null;
35395 var targetNode = newParent.ui.getContainer();
35396 if(!targetNode){//target not rendered
35397 this.holder = document.createElement("div");
35398 this.holder.appendChild(this.wrap);
35401 var insertBefore = refNode ? refNode.ui.getEl() : null;
35403 targetNode.insertBefore(this.wrap, insertBefore);
35405 targetNode.appendChild(this.wrap);
35407 this.node.renderIndent(true);
35411 addClass : function(cls){
35413 Roo.fly(this.elNode).addClass(cls);
35417 removeClass : function(cls){
35419 Roo.fly(this.elNode).removeClass(cls);
35423 remove : function(){
35425 this.holder = document.createElement("div");
35426 this.holder.appendChild(this.wrap);
35430 fireEvent : function(){
35431 return this.node.fireEvent.apply(this.node, arguments);
35434 initEvents : function(){
35435 this.node.on("move", this.onMove, this);
35436 var E = Roo.EventManager;
35437 var a = this.anchor;
35439 var el = Roo.fly(a, '_treeui');
35441 if(Roo.isOpera){ // opera render bug ignores the CSS
35442 el.setStyle("text-decoration", "none");
35445 el.on("click", this.onClick, this);
35446 el.on("dblclick", this.onDblClick, this);
35449 Roo.EventManager.on(this.checkbox,
35450 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35453 el.on("contextmenu", this.onContextMenu, this);
35455 var icon = Roo.fly(this.iconNode);
35456 icon.on("click", this.onClick, this);
35457 icon.on("dblclick", this.onDblClick, this);
35458 icon.on("contextmenu", this.onContextMenu, this);
35459 E.on(this.ecNode, "click", this.ecClick, this, true);
35461 if(this.node.disabled){
35462 this.addClass("x-tree-node-disabled");
35464 if(this.node.hidden){
35465 this.addClass("x-tree-node-disabled");
35467 var ot = this.node.getOwnerTree();
35468 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35469 if(dd && (!this.node.isRoot || ot.rootVisible)){
35470 Roo.dd.Registry.register(this.elNode, {
35472 handles: this.getDDHandles(),
35478 getDDHandles : function(){
35479 return [this.iconNode, this.textNode];
35484 this.wrap.style.display = "none";
35490 this.wrap.style.display = "";
35494 onContextMenu : function(e){
35495 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35496 e.preventDefault();
35498 this.fireEvent("contextmenu", this.node, e);
35502 onClick : function(e){
35507 if(this.fireEvent("beforeclick", this.node, e) !== false){
35508 if(!this.disabled && this.node.attributes.href){
35509 this.fireEvent("click", this.node, e);
35512 e.preventDefault();
35517 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35518 this.node.toggle();
35521 this.fireEvent("click", this.node, e);
35527 onDblClick : function(e){
35528 e.preventDefault();
35533 this.toggleCheck();
35535 if(!this.animating && this.node.hasChildNodes()){
35536 this.node.toggle();
35538 this.fireEvent("dblclick", this.node, e);
35541 onCheckChange : function(){
35542 var checked = this.checkbox.checked;
35543 this.node.attributes.checked = checked;
35544 this.fireEvent('checkchange', this.node, checked);
35547 ecClick : function(e){
35548 if(!this.animating && this.node.hasChildNodes()){
35549 this.node.toggle();
35553 startDrop : function(){
35554 this.dropping = true;
35557 // delayed drop so the click event doesn't get fired on a drop
35558 endDrop : function(){
35559 setTimeout(function(){
35560 this.dropping = false;
35561 }.createDelegate(this), 50);
35564 expand : function(){
35565 this.updateExpandIcon();
35566 this.ctNode.style.display = "";
35569 focus : function(){
35570 if(!this.node.preventHScroll){
35571 try{this.anchor.focus();
35573 }else if(!Roo.isIE){
35575 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35576 var l = noscroll.scrollLeft;
35577 this.anchor.focus();
35578 noscroll.scrollLeft = l;
35583 toggleCheck : function(value){
35584 var cb = this.checkbox;
35586 cb.checked = (value === undefined ? !cb.checked : value);
35592 this.anchor.blur();
35596 animExpand : function(callback){
35597 var ct = Roo.get(this.ctNode);
35599 if(!this.node.hasChildNodes()){
35600 this.updateExpandIcon();
35601 this.ctNode.style.display = "";
35602 Roo.callback(callback);
35605 this.animating = true;
35606 this.updateExpandIcon();
35609 callback : function(){
35610 this.animating = false;
35611 Roo.callback(callback);
35614 duration: this.node.ownerTree.duration || .25
35618 highlight : function(){
35619 var tree = this.node.getOwnerTree();
35620 Roo.fly(this.wrap).highlight(
35621 tree.hlColor || "C3DAF9",
35622 {endColor: tree.hlBaseColor}
35626 collapse : function(){
35627 this.updateExpandIcon();
35628 this.ctNode.style.display = "none";
35631 animCollapse : function(callback){
35632 var ct = Roo.get(this.ctNode);
35633 ct.enableDisplayMode('block');
35636 this.animating = true;
35637 this.updateExpandIcon();
35640 callback : function(){
35641 this.animating = false;
35642 Roo.callback(callback);
35645 duration: this.node.ownerTree.duration || .25
35649 getContainer : function(){
35650 return this.ctNode;
35653 getEl : function(){
35657 appendDDGhost : function(ghostNode){
35658 ghostNode.appendChild(this.elNode.cloneNode(true));
35661 getDDRepairXY : function(){
35662 return Roo.lib.Dom.getXY(this.iconNode);
35665 onRender : function(){
35669 render : function(bulkRender){
35670 var n = this.node, a = n.attributes;
35671 var targetNode = n.parentNode ?
35672 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35674 if(!this.rendered){
35675 this.rendered = true;
35677 this.renderElements(n, a, targetNode, bulkRender);
35680 if(this.textNode.setAttributeNS){
35681 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35683 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35686 this.textNode.setAttribute("ext:qtip", a.qtip);
35688 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35691 }else if(a.qtipCfg){
35692 a.qtipCfg.target = Roo.id(this.textNode);
35693 Roo.QuickTips.register(a.qtipCfg);
35696 if(!this.node.expanded){
35697 this.updateExpandIcon();
35700 if(bulkRender === true) {
35701 targetNode.appendChild(this.wrap);
35706 renderElements : function(n, a, targetNode, bulkRender)
35708 // add some indent caching, this helps performance when rendering a large tree
35709 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35710 var t = n.getOwnerTree();
35711 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35712 if (typeof(n.attributes.html) != 'undefined') {
35713 txt = n.attributes.html;
35715 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35716 var cb = typeof a.checked == 'boolean';
35717 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35718 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35719 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35720 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35721 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35722 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35723 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35724 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35725 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35726 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35729 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35730 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35731 n.nextSibling.ui.getEl(), buf.join(""));
35733 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35736 this.elNode = this.wrap.childNodes[0];
35737 this.ctNode = this.wrap.childNodes[1];
35738 var cs = this.elNode.childNodes;
35739 this.indentNode = cs[0];
35740 this.ecNode = cs[1];
35741 this.iconNode = cs[2];
35744 this.checkbox = cs[3];
35747 this.anchor = cs[index];
35748 this.textNode = cs[index].firstChild;
35751 getAnchor : function(){
35752 return this.anchor;
35755 getTextEl : function(){
35756 return this.textNode;
35759 getIconEl : function(){
35760 return this.iconNode;
35763 isChecked : function(){
35764 return this.checkbox ? this.checkbox.checked : false;
35767 updateExpandIcon : function(){
35769 var n = this.node, c1, c2;
35770 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35771 var hasChild = n.hasChildNodes();
35775 c1 = "x-tree-node-collapsed";
35776 c2 = "x-tree-node-expanded";
35779 c1 = "x-tree-node-expanded";
35780 c2 = "x-tree-node-collapsed";
35783 this.removeClass("x-tree-node-leaf");
35784 this.wasLeaf = false;
35786 if(this.c1 != c1 || this.c2 != c2){
35787 Roo.fly(this.elNode).replaceClass(c1, c2);
35788 this.c1 = c1; this.c2 = c2;
35791 // this changes non-leafs into leafs if they have no children.
35792 // it's not very rational behaviour..
35794 if(!this.wasLeaf && this.node.leaf){
35795 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35798 this.wasLeaf = true;
35801 var ecc = "x-tree-ec-icon "+cls;
35802 if(this.ecc != ecc){
35803 this.ecNode.className = ecc;
35809 getChildIndent : function(){
35810 if(!this.childIndent){
35814 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35816 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35818 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35823 this.childIndent = buf.join("");
35825 return this.childIndent;
35828 renderIndent : function(){
35831 var p = this.node.parentNode;
35833 indent = p.ui.getChildIndent();
35835 if(this.indentMarkup != indent){ // don't rerender if not required
35836 this.indentNode.innerHTML = indent;
35837 this.indentMarkup = indent;
35839 this.updateExpandIcon();
35844 Roo.tree.RootTreeNodeUI = function(){
35845 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35847 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35848 render : function(){
35849 if(!this.rendered){
35850 var targetNode = this.node.ownerTree.innerCt.dom;
35851 this.node.expanded = true;
35852 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35853 this.wrap = this.ctNode = targetNode.firstChild;
35856 collapse : function(){
35858 expand : function(){
35862 * Ext JS Library 1.1.1
35863 * Copyright(c) 2006-2007, Ext JS, LLC.
35865 * Originally Released Under LGPL - original licence link has changed is not relivant.
35868 * <script type="text/javascript">
35871 * @class Roo.tree.TreeLoader
35872 * @extends Roo.util.Observable
35873 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35874 * nodes from a specified URL. The response must be a javascript Array definition
35875 * who's elements are node definition objects. eg:
35880 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35881 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35888 * The old style respose with just an array is still supported, but not recommended.
35891 * A server request is sent, and child nodes are loaded only when a node is expanded.
35892 * The loading node's id is passed to the server under the parameter name "node" to
35893 * enable the server to produce the correct child nodes.
35895 * To pass extra parameters, an event handler may be attached to the "beforeload"
35896 * event, and the parameters specified in the TreeLoader's baseParams property:
35898 myTreeLoader.on("beforeload", function(treeLoader, node) {
35899 this.baseParams.category = node.attributes.category;
35902 * This would pass an HTTP parameter called "category" to the server containing
35903 * the value of the Node's "category" attribute.
35905 * Creates a new Treeloader.
35906 * @param {Object} config A config object containing config properties.
35908 Roo.tree.TreeLoader = function(config){
35909 this.baseParams = {};
35910 this.requestMethod = "POST";
35911 Roo.apply(this, config);
35916 * @event beforeload
35917 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35918 * @param {Object} This TreeLoader object.
35919 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35920 * @param {Object} callback The callback function specified in the {@link #load} call.
35925 * Fires when the node has been successfuly loaded.
35926 * @param {Object} This TreeLoader object.
35927 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35928 * @param {Object} response The response object containing the data from the server.
35932 * @event loadexception
35933 * Fires if the network request failed.
35934 * @param {Object} This TreeLoader object.
35935 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35936 * @param {Object} response The response object containing the data from the server.
35938 loadexception : true,
35941 * Fires before a node is created, enabling you to return custom Node types
35942 * @param {Object} This TreeLoader object.
35943 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35948 Roo.tree.TreeLoader.superclass.constructor.call(this);
35951 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35953 * @cfg {String} dataUrl The URL from which to request a Json string which
35954 * specifies an array of node definition object representing the child nodes
35958 * @cfg {String} requestMethod either GET or POST
35959 * defaults to POST (due to BC)
35963 * @cfg {Object} baseParams (optional) An object containing properties which
35964 * specify HTTP parameters to be passed to each request for child nodes.
35967 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35968 * created by this loader. If the attributes sent by the server have an attribute in this object,
35969 * they take priority.
35972 * @cfg {Object} uiProviders (optional) An object containing properties which
35974 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35975 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35976 * <i>uiProvider</i> attribute of a returned child node is a string rather
35977 * than a reference to a TreeNodeUI implementation, this that string value
35978 * is used as a property name in the uiProviders object. You can define the provider named
35979 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35984 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35985 * child nodes before loading.
35987 clearOnLoad : true,
35990 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35991 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35992 * Grid query { data : [ .....] }
35997 * @cfg {String} queryParam (optional)
35998 * Name of the query as it will be passed on the querystring (defaults to 'node')
35999 * eg. the request will be ?node=[id]
36006 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36007 * This is called automatically when a node is expanded, but may be used to reload
36008 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36009 * @param {Roo.tree.TreeNode} node
36010 * @param {Function} callback
36012 load : function(node, callback){
36013 if(this.clearOnLoad){
36014 while(node.firstChild){
36015 node.removeChild(node.firstChild);
36018 if(node.attributes.children){ // preloaded json children
36019 var cs = node.attributes.children;
36020 for(var i = 0, len = cs.length; i < len; i++){
36021 node.appendChild(this.createNode(cs[i]));
36023 if(typeof callback == "function"){
36026 }else if(this.dataUrl){
36027 this.requestData(node, callback);
36031 getParams: function(node){
36032 var buf = [], bp = this.baseParams;
36033 for(var key in bp){
36034 if(typeof bp[key] != "function"){
36035 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36038 var n = this.queryParam === false ? 'node' : this.queryParam;
36039 buf.push(n + "=", encodeURIComponent(node.id));
36040 return buf.join("");
36043 requestData : function(node, callback){
36044 if(this.fireEvent("beforeload", this, node, callback) !== false){
36045 this.transId = Roo.Ajax.request({
36046 method:this.requestMethod,
36047 url: this.dataUrl||this.url,
36048 success: this.handleResponse,
36049 failure: this.handleFailure,
36051 argument: {callback: callback, node: node},
36052 params: this.getParams(node)
36055 // if the load is cancelled, make sure we notify
36056 // the node that we are done
36057 if(typeof callback == "function"){
36063 isLoading : function(){
36064 return this.transId ? true : false;
36067 abort : function(){
36068 if(this.isLoading()){
36069 Roo.Ajax.abort(this.transId);
36074 createNode : function(attr)
36076 // apply baseAttrs, nice idea Corey!
36077 if(this.baseAttrs){
36078 Roo.applyIf(attr, this.baseAttrs);
36080 if(this.applyLoader !== false){
36081 attr.loader = this;
36083 // uiProvider = depreciated..
36085 if(typeof(attr.uiProvider) == 'string'){
36086 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36087 /** eval:var:attr */ eval(attr.uiProvider);
36089 if(typeof(this.uiProviders['default']) != 'undefined') {
36090 attr.uiProvider = this.uiProviders['default'];
36093 this.fireEvent('create', this, attr);
36095 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36097 new Roo.tree.TreeNode(attr) :
36098 new Roo.tree.AsyncTreeNode(attr));
36101 processResponse : function(response, node, callback)
36103 var json = response.responseText;
36106 var o = Roo.decode(json);
36108 if (this.root === false && typeof(o.success) != undefined) {
36109 this.root = 'data'; // the default behaviour for list like data..
36112 if (this.root !== false && !o.success) {
36113 // it's a failure condition.
36114 var a = response.argument;
36115 this.fireEvent("loadexception", this, a.node, response);
36116 Roo.log("Load failed - should have a handler really");
36122 if (this.root !== false) {
36126 for(var i = 0, len = o.length; i < len; i++){
36127 var n = this.createNode(o[i]);
36129 node.appendChild(n);
36132 if(typeof callback == "function"){
36133 callback(this, node);
36136 this.handleFailure(response);
36140 handleResponse : function(response){
36141 this.transId = false;
36142 var a = response.argument;
36143 this.processResponse(response, a.node, a.callback);
36144 this.fireEvent("load", this, a.node, response);
36147 handleFailure : function(response)
36149 // should handle failure better..
36150 this.transId = false;
36151 var a = response.argument;
36152 this.fireEvent("loadexception", this, a.node, response);
36153 if(typeof a.callback == "function"){
36154 a.callback(this, a.node);
36159 * Ext JS Library 1.1.1
36160 * Copyright(c) 2006-2007, Ext JS, LLC.
36162 * Originally Released Under LGPL - original licence link has changed is not relivant.
36165 * <script type="text/javascript">
36169 * @class Roo.tree.TreeFilter
36170 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36171 * @param {TreePanel} tree
36172 * @param {Object} config (optional)
36174 Roo.tree.TreeFilter = function(tree, config){
36176 this.filtered = {};
36177 Roo.apply(this, config);
36180 Roo.tree.TreeFilter.prototype = {
36187 * Filter the data by a specific attribute.
36188 * @param {String/RegExp} value Either string that the attribute value
36189 * should start with or a RegExp to test against the attribute
36190 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36191 * @param {TreeNode} startNode (optional) The node to start the filter at.
36193 filter : function(value, attr, startNode){
36194 attr = attr || "text";
36196 if(typeof value == "string"){
36197 var vlen = value.length;
36198 // auto clear empty filter
36199 if(vlen == 0 && this.clearBlank){
36203 value = value.toLowerCase();
36205 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36207 }else if(value.exec){ // regex?
36209 return value.test(n.attributes[attr]);
36212 throw 'Illegal filter type, must be string or regex';
36214 this.filterBy(f, null, startNode);
36218 * Filter by a function. The passed function will be called with each
36219 * node in the tree (or from the startNode). If the function returns true, the node is kept
36220 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36221 * @param {Function} fn The filter function
36222 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36224 filterBy : function(fn, scope, startNode){
36225 startNode = startNode || this.tree.root;
36226 if(this.autoClear){
36229 var af = this.filtered, rv = this.reverse;
36230 var f = function(n){
36231 if(n == startNode){
36237 var m = fn.call(scope || n, n);
36245 startNode.cascade(f);
36248 if(typeof id != "function"){
36250 if(n && n.parentNode){
36251 n.parentNode.removeChild(n);
36259 * Clears the current filter. Note: with the "remove" option
36260 * set a filter cannot be cleared.
36262 clear : function(){
36264 var af = this.filtered;
36266 if(typeof id != "function"){
36273 this.filtered = {};
36278 * Ext JS Library 1.1.1
36279 * Copyright(c) 2006-2007, Ext JS, LLC.
36281 * Originally Released Under LGPL - original licence link has changed is not relivant.
36284 * <script type="text/javascript">
36289 * @class Roo.tree.TreeSorter
36290 * Provides sorting of nodes in a TreePanel
36292 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36293 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36294 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36295 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36296 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36297 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36299 * @param {TreePanel} tree
36300 * @param {Object} config
36302 Roo.tree.TreeSorter = function(tree, config){
36303 Roo.apply(this, config);
36304 tree.on("beforechildrenrendered", this.doSort, this);
36305 tree.on("append", this.updateSort, this);
36306 tree.on("insert", this.updateSort, this);
36308 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36309 var p = this.property || "text";
36310 var sortType = this.sortType;
36311 var fs = this.folderSort;
36312 var cs = this.caseSensitive === true;
36313 var leafAttr = this.leafAttr || 'leaf';
36315 this.sortFn = function(n1, n2){
36317 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36320 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36324 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36325 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36327 return dsc ? +1 : -1;
36329 return dsc ? -1 : +1;
36336 Roo.tree.TreeSorter.prototype = {
36337 doSort : function(node){
36338 node.sort(this.sortFn);
36341 compareNodes : function(n1, n2){
36342 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36345 updateSort : function(tree, node){
36346 if(node.childrenRendered){
36347 this.doSort.defer(1, this, [node]);
36352 * Ext JS Library 1.1.1
36353 * Copyright(c) 2006-2007, Ext JS, LLC.
36355 * Originally Released Under LGPL - original licence link has changed is not relivant.
36358 * <script type="text/javascript">
36361 if(Roo.dd.DropZone){
36363 Roo.tree.TreeDropZone = function(tree, config){
36364 this.allowParentInsert = false;
36365 this.allowContainerDrop = false;
36366 this.appendOnly = false;
36367 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36369 this.lastInsertClass = "x-tree-no-status";
36370 this.dragOverData = {};
36373 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36374 ddGroup : "TreeDD",
36377 expandDelay : 1000,
36379 expandNode : function(node){
36380 if(node.hasChildNodes() && !node.isExpanded()){
36381 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36385 queueExpand : function(node){
36386 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36389 cancelExpand : function(){
36390 if(this.expandProcId){
36391 clearTimeout(this.expandProcId);
36392 this.expandProcId = false;
36396 isValidDropPoint : function(n, pt, dd, e, data){
36397 if(!n || !data){ return false; }
36398 var targetNode = n.node;
36399 var dropNode = data.node;
36400 // default drop rules
36401 if(!(targetNode && targetNode.isTarget && pt)){
36404 if(pt == "append" && targetNode.allowChildren === false){
36407 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36410 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36413 // reuse the object
36414 var overEvent = this.dragOverData;
36415 overEvent.tree = this.tree;
36416 overEvent.target = targetNode;
36417 overEvent.data = data;
36418 overEvent.point = pt;
36419 overEvent.source = dd;
36420 overEvent.rawEvent = e;
36421 overEvent.dropNode = dropNode;
36422 overEvent.cancel = false;
36423 var result = this.tree.fireEvent("nodedragover", overEvent);
36424 return overEvent.cancel === false && result !== false;
36427 getDropPoint : function(e, n, dd)
36431 return tn.allowChildren !== false ? "append" : false; // always append for root
36433 var dragEl = n.ddel;
36434 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36435 var y = Roo.lib.Event.getPageY(e);
36436 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36438 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36439 var noAppend = tn.allowChildren === false;
36440 if(this.appendOnly || tn.parentNode.allowChildren === false){
36441 return noAppend ? false : "append";
36443 var noBelow = false;
36444 if(!this.allowParentInsert){
36445 noBelow = tn.hasChildNodes() && tn.isExpanded();
36447 var q = (b - t) / (noAppend ? 2 : 3);
36448 if(y >= t && y < (t + q)){
36450 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36457 onNodeEnter : function(n, dd, e, data)
36459 this.cancelExpand();
36462 onNodeOver : function(n, dd, e, data)
36465 var pt = this.getDropPoint(e, n, dd);
36468 // auto node expand check
36469 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36470 this.queueExpand(node);
36471 }else if(pt != "append"){
36472 this.cancelExpand();
36475 // set the insert point style on the target node
36476 var returnCls = this.dropNotAllowed;
36477 if(this.isValidDropPoint(n, pt, dd, e, data)){
36482 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36483 cls = "x-tree-drag-insert-above";
36484 }else if(pt == "below"){
36485 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36486 cls = "x-tree-drag-insert-below";
36488 returnCls = "x-tree-drop-ok-append";
36489 cls = "x-tree-drag-append";
36491 if(this.lastInsertClass != cls){
36492 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36493 this.lastInsertClass = cls;
36500 onNodeOut : function(n, dd, e, data){
36502 this.cancelExpand();
36503 this.removeDropIndicators(n);
36506 onNodeDrop : function(n, dd, e, data){
36507 var point = this.getDropPoint(e, n, dd);
36508 var targetNode = n.node;
36509 targetNode.ui.startDrop();
36510 if(!this.isValidDropPoint(n, point, dd, e, data)){
36511 targetNode.ui.endDrop();
36514 // first try to find the drop node
36515 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36518 target: targetNode,
36523 dropNode: dropNode,
36526 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36527 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36528 targetNode.ui.endDrop();
36531 // allow target changing
36532 targetNode = dropEvent.target;
36533 if(point == "append" && !targetNode.isExpanded()){
36534 targetNode.expand(false, null, function(){
36535 this.completeDrop(dropEvent);
36536 }.createDelegate(this));
36538 this.completeDrop(dropEvent);
36543 completeDrop : function(de){
36544 var ns = de.dropNode, p = de.point, t = de.target;
36545 if(!(ns instanceof Array)){
36549 for(var i = 0, len = ns.length; i < len; i++){
36552 t.parentNode.insertBefore(n, t);
36553 }else if(p == "below"){
36554 t.parentNode.insertBefore(n, t.nextSibling);
36560 if(this.tree.hlDrop){
36564 this.tree.fireEvent("nodedrop", de);
36567 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36568 if(this.tree.hlDrop){
36569 dropNode.ui.focus();
36570 dropNode.ui.highlight();
36572 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36575 getTree : function(){
36579 removeDropIndicators : function(n){
36582 Roo.fly(el).removeClass([
36583 "x-tree-drag-insert-above",
36584 "x-tree-drag-insert-below",
36585 "x-tree-drag-append"]);
36586 this.lastInsertClass = "_noclass";
36590 beforeDragDrop : function(target, e, id){
36591 this.cancelExpand();
36595 afterRepair : function(data){
36596 if(data && Roo.enableFx){
36597 data.node.ui.highlight();
36607 * Ext JS Library 1.1.1
36608 * Copyright(c) 2006-2007, Ext JS, LLC.
36610 * Originally Released Under LGPL - original licence link has changed is not relivant.
36613 * <script type="text/javascript">
36617 if(Roo.dd.DragZone){
36618 Roo.tree.TreeDragZone = function(tree, config){
36619 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36623 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36624 ddGroup : "TreeDD",
36626 onBeforeDrag : function(data, e){
36628 return n && n.draggable && !n.disabled;
36632 onInitDrag : function(e){
36633 var data = this.dragData;
36634 this.tree.getSelectionModel().select(data.node);
36635 this.proxy.update("");
36636 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36637 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36640 getRepairXY : function(e, data){
36641 return data.node.ui.getDDRepairXY();
36644 onEndDrag : function(data, e){
36645 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36650 onValidDrop : function(dd, e, id){
36651 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36655 beforeInvalidDrop : function(e, id){
36656 // this scrolls the original position back into view
36657 var sm = this.tree.getSelectionModel();
36658 sm.clearSelections();
36659 sm.select(this.dragData.node);
36664 * Ext JS Library 1.1.1
36665 * Copyright(c) 2006-2007, Ext JS, LLC.
36667 * Originally Released Under LGPL - original licence link has changed is not relivant.
36670 * <script type="text/javascript">
36673 * @class Roo.tree.TreeEditor
36674 * @extends Roo.Editor
36675 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36676 * as the editor field.
36678 * @param {Object} config (used to be the tree panel.)
36679 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36681 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36682 * @cfg {Roo.form.TextField|Object} field The field configuration
36686 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36689 if (oldconfig) { // old style..
36690 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36693 tree = config.tree;
36694 config.field = config.field || {};
36695 config.field.xtype = 'TextField';
36696 field = Roo.factory(config.field, Roo.form);
36698 config = config || {};
36703 * @event beforenodeedit
36704 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36705 * false from the handler of this event.
36706 * @param {Editor} this
36707 * @param {Roo.tree.Node} node
36709 "beforenodeedit" : true
36713 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36717 tree.on('beforeclick', this.beforeNodeClick, this);
36718 tree.getTreeEl().on('mousedown', this.hide, this);
36719 this.on('complete', this.updateNode, this);
36720 this.on('beforestartedit', this.fitToTree, this);
36721 this.on('startedit', this.bindScroll, this, {delay:10});
36722 this.on('specialkey', this.onSpecialKey, this);
36725 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36727 * @cfg {String} alignment
36728 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36734 * @cfg {Boolean} hideEl
36735 * True to hide the bound element while the editor is displayed (defaults to false)
36739 * @cfg {String} cls
36740 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36742 cls: "x-small-editor x-tree-editor",
36744 * @cfg {Boolean} shim
36745 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36751 * @cfg {Number} maxWidth
36752 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36753 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36754 * scroll and client offsets into account prior to each edit.
36761 fitToTree : function(ed, el){
36762 var td = this.tree.getTreeEl().dom, nd = el.dom;
36763 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36764 td.scrollLeft = nd.offsetLeft;
36768 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36769 this.setSize(w, '');
36771 return this.fireEvent('beforenodeedit', this, this.editNode);
36776 triggerEdit : function(node){
36777 this.completeEdit();
36778 this.editNode = node;
36779 this.startEdit(node.ui.textNode, node.text);
36783 bindScroll : function(){
36784 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36788 beforeNodeClick : function(node, e){
36789 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36790 this.lastClick = new Date();
36791 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36793 this.triggerEdit(node);
36800 updateNode : function(ed, value){
36801 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36802 this.editNode.setText(value);
36806 onHide : function(){
36807 Roo.tree.TreeEditor.superclass.onHide.call(this);
36809 this.editNode.ui.focus();
36814 onSpecialKey : function(field, e){
36815 var k = e.getKey();
36819 }else if(k == e.ENTER && !e.hasModifier()){
36821 this.completeEdit();
36824 });//<Script type="text/javascript">
36827 * Ext JS Library 1.1.1
36828 * Copyright(c) 2006-2007, Ext JS, LLC.
36830 * Originally Released Under LGPL - original licence link has changed is not relivant.
36833 * <script type="text/javascript">
36837 * Not documented??? - probably should be...
36840 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36841 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36843 renderElements : function(n, a, targetNode, bulkRender){
36844 //consel.log("renderElements?");
36845 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36847 var t = n.getOwnerTree();
36848 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36850 var cols = t.columns;
36851 var bw = t.borderWidth;
36853 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36854 var cb = typeof a.checked == "boolean";
36855 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36856 var colcls = 'x-t-' + tid + '-c0';
36858 '<li class="x-tree-node">',
36861 '<div class="x-tree-node-el ', a.cls,'">',
36863 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36866 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36867 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36868 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36869 (a.icon ? ' x-tree-node-inline-icon' : ''),
36870 (a.iconCls ? ' '+a.iconCls : ''),
36871 '" unselectable="on" />',
36872 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36873 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36875 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36876 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36877 '<span unselectable="on" qtip="' + tx + '">',
36881 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36882 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36884 for(var i = 1, len = cols.length; i < len; i++){
36886 colcls = 'x-t-' + tid + '-c' +i;
36887 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36888 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36889 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36895 '<div class="x-clear"></div></div>',
36896 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36899 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36900 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36901 n.nextSibling.ui.getEl(), buf.join(""));
36903 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36905 var el = this.wrap.firstChild;
36907 this.elNode = el.firstChild;
36908 this.ranchor = el.childNodes[1];
36909 this.ctNode = this.wrap.childNodes[1];
36910 var cs = el.firstChild.childNodes;
36911 this.indentNode = cs[0];
36912 this.ecNode = cs[1];
36913 this.iconNode = cs[2];
36916 this.checkbox = cs[3];
36919 this.anchor = cs[index];
36921 this.textNode = cs[index].firstChild;
36923 //el.on("click", this.onClick, this);
36924 //el.on("dblclick", this.onDblClick, this);
36927 // console.log(this);
36929 initEvents : function(){
36930 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36933 var a = this.ranchor;
36935 var el = Roo.get(a);
36937 if(Roo.isOpera){ // opera render bug ignores the CSS
36938 el.setStyle("text-decoration", "none");
36941 el.on("click", this.onClick, this);
36942 el.on("dblclick", this.onDblClick, this);
36943 el.on("contextmenu", this.onContextMenu, this);
36947 /*onSelectedChange : function(state){
36950 this.addClass("x-tree-selected");
36953 this.removeClass("x-tree-selected");
36956 addClass : function(cls){
36958 Roo.fly(this.elRow).addClass(cls);
36964 removeClass : function(cls){
36966 Roo.fly(this.elRow).removeClass(cls);
36972 });//<Script type="text/javascript">
36976 * Ext JS Library 1.1.1
36977 * Copyright(c) 2006-2007, Ext JS, LLC.
36979 * Originally Released Under LGPL - original licence link has changed is not relivant.
36982 * <script type="text/javascript">
36987 * @class Roo.tree.ColumnTree
36988 * @extends Roo.data.TreePanel
36989 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36990 * @cfg {int} borderWidth compined right/left border allowance
36992 * @param {String/HTMLElement/Element} el The container element
36993 * @param {Object} config
36995 Roo.tree.ColumnTree = function(el, config)
36997 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37001 * Fire this event on a container when it resizes
37002 * @param {int} w Width
37003 * @param {int} h Height
37007 this.on('resize', this.onResize, this);
37010 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37014 borderWidth: Roo.isBorderBox ? 0 : 2,
37017 render : function(){
37018 // add the header.....
37020 Roo.tree.ColumnTree.superclass.render.apply(this);
37022 this.el.addClass('x-column-tree');
37024 this.headers = this.el.createChild(
37025 {cls:'x-tree-headers'},this.innerCt.dom);
37027 var cols = this.columns, c;
37028 var totalWidth = 0;
37030 var len = cols.length;
37031 for(var i = 0; i < len; i++){
37033 totalWidth += c.width;
37034 this.headEls.push(this.headers.createChild({
37035 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37037 cls:'x-tree-hd-text',
37040 style:'width:'+(c.width-this.borderWidth)+'px;'
37043 this.headers.createChild({cls:'x-clear'});
37044 // prevent floats from wrapping when clipped
37045 this.headers.setWidth(totalWidth);
37046 //this.innerCt.setWidth(totalWidth);
37047 this.innerCt.setStyle({ overflow: 'auto' });
37048 this.onResize(this.width, this.height);
37052 onResize : function(w,h)
37057 this.innerCt.setWidth(this.width);
37058 this.innerCt.setHeight(this.height-20);
37061 var cols = this.columns, c;
37062 var totalWidth = 0;
37064 var len = cols.length;
37065 for(var i = 0; i < len; i++){
37067 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37068 // it's the expander..
37069 expEl = this.headEls[i];
37072 totalWidth += c.width;
37076 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37078 this.headers.setWidth(w-20);
37087 * Ext JS Library 1.1.1
37088 * Copyright(c) 2006-2007, Ext JS, LLC.
37090 * Originally Released Under LGPL - original licence link has changed is not relivant.
37093 * <script type="text/javascript">
37097 * @class Roo.menu.Menu
37098 * @extends Roo.util.Observable
37099 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37100 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37102 * Creates a new Menu
37103 * @param {Object} config Configuration options
37105 Roo.menu.Menu = function(config){
37106 Roo.apply(this, config);
37107 this.id = this.id || Roo.id();
37110 * @event beforeshow
37111 * Fires before this menu is displayed
37112 * @param {Roo.menu.Menu} this
37116 * @event beforehide
37117 * Fires before this menu is hidden
37118 * @param {Roo.menu.Menu} this
37123 * Fires after this menu is displayed
37124 * @param {Roo.menu.Menu} this
37129 * Fires after this menu is hidden
37130 * @param {Roo.menu.Menu} this
37135 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37136 * @param {Roo.menu.Menu} this
37137 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37138 * @param {Roo.EventObject} e
37143 * Fires when the mouse is hovering over this menu
37144 * @param {Roo.menu.Menu} this
37145 * @param {Roo.EventObject} e
37146 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37151 * Fires when the mouse exits this menu
37152 * @param {Roo.menu.Menu} this
37153 * @param {Roo.EventObject} e
37154 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37159 * Fires when a menu item contained in this menu is clicked
37160 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37161 * @param {Roo.EventObject} e
37165 if (this.registerMenu) {
37166 Roo.menu.MenuMgr.register(this);
37169 var mis = this.items;
37170 this.items = new Roo.util.MixedCollection();
37172 this.add.apply(this, mis);
37176 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37178 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37182 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37183 * for bottom-right shadow (defaults to "sides")
37187 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37188 * this menu (defaults to "tl-tr?")
37190 subMenuAlign : "tl-tr?",
37192 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37193 * relative to its element of origin (defaults to "tl-bl?")
37195 defaultAlign : "tl-bl?",
37197 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37199 allowOtherMenus : false,
37201 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37203 registerMenu : true,
37208 render : function(){
37212 var el = this.el = new Roo.Layer({
37214 shadow:this.shadow,
37216 parentEl: this.parentEl || document.body,
37220 this.keyNav = new Roo.menu.MenuNav(this);
37223 el.addClass("x-menu-plain");
37226 el.addClass(this.cls);
37228 // generic focus element
37229 this.focusEl = el.createChild({
37230 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37232 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37233 //disabling touch- as it's causing issues ..
37234 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37235 ul.on('click' , this.onClick, this);
37238 ul.on("mouseover", this.onMouseOver, this);
37239 ul.on("mouseout", this.onMouseOut, this);
37240 this.items.each(function(item){
37245 var li = document.createElement("li");
37246 li.className = "x-menu-list-item";
37247 ul.dom.appendChild(li);
37248 item.render(li, this);
37255 autoWidth : function(){
37256 var el = this.el, ul = this.ul;
37260 var w = this.width;
37263 }else if(Roo.isIE){
37264 el.setWidth(this.minWidth);
37265 var t = el.dom.offsetWidth; // force recalc
37266 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37271 delayAutoWidth : function(){
37274 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37276 this.awTask.delay(20);
37281 findTargetItem : function(e){
37282 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37283 if(t && t.menuItemId){
37284 return this.items.get(t.menuItemId);
37289 onClick : function(e){
37290 Roo.log("menu.onClick");
37291 var t = this.findTargetItem(e);
37296 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37297 if(t == this.activeItem && t.shouldDeactivate(e)){
37298 this.activeItem.deactivate();
37299 delete this.activeItem;
37303 this.setActiveItem(t, true);
37311 this.fireEvent("click", this, t, e);
37315 setActiveItem : function(item, autoExpand){
37316 if(item != this.activeItem){
37317 if(this.activeItem){
37318 this.activeItem.deactivate();
37320 this.activeItem = item;
37321 item.activate(autoExpand);
37322 }else if(autoExpand){
37328 tryActivate : function(start, step){
37329 var items = this.items;
37330 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37331 var item = items.get(i);
37332 if(!item.disabled && item.canActivate){
37333 this.setActiveItem(item, false);
37341 onMouseOver : function(e){
37343 if(t = this.findTargetItem(e)){
37344 if(t.canActivate && !t.disabled){
37345 this.setActiveItem(t, true);
37348 this.fireEvent("mouseover", this, e, t);
37352 onMouseOut : function(e){
37354 if(t = this.findTargetItem(e)){
37355 if(t == this.activeItem && t.shouldDeactivate(e)){
37356 this.activeItem.deactivate();
37357 delete this.activeItem;
37360 this.fireEvent("mouseout", this, e, t);
37364 * Read-only. Returns true if the menu is currently displayed, else false.
37367 isVisible : function(){
37368 return this.el && !this.hidden;
37372 * Displays this menu relative to another element
37373 * @param {String/HTMLElement/Roo.Element} element The element to align to
37374 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37375 * the element (defaults to this.defaultAlign)
37376 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37378 show : function(el, pos, parentMenu){
37379 this.parentMenu = parentMenu;
37383 this.fireEvent("beforeshow", this);
37384 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37388 * Displays this menu at a specific xy position
37389 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37390 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37392 showAt : function(xy, parentMenu, /* private: */_e){
37393 this.parentMenu = parentMenu;
37398 this.fireEvent("beforeshow", this);
37399 xy = this.el.adjustForConstraints(xy);
37403 this.hidden = false;
37405 this.fireEvent("show", this);
37408 focus : function(){
37410 this.doFocus.defer(50, this);
37414 doFocus : function(){
37416 this.focusEl.focus();
37421 * Hides this menu and optionally all parent menus
37422 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37424 hide : function(deep){
37425 if(this.el && this.isVisible()){
37426 this.fireEvent("beforehide", this);
37427 if(this.activeItem){
37428 this.activeItem.deactivate();
37429 this.activeItem = null;
37432 this.hidden = true;
37433 this.fireEvent("hide", this);
37435 if(deep === true && this.parentMenu){
37436 this.parentMenu.hide(true);
37441 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37442 * Any of the following are valid:
37444 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37445 * <li>An HTMLElement object which will be converted to a menu item</li>
37446 * <li>A menu item config object that will be created as a new menu item</li>
37447 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37448 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37453 var menu = new Roo.menu.Menu();
37455 // Create a menu item to add by reference
37456 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37458 // Add a bunch of items at once using different methods.
37459 // Only the last item added will be returned.
37460 var item = menu.add(
37461 menuItem, // add existing item by ref
37462 'Dynamic Item', // new TextItem
37463 '-', // new separator
37464 { text: 'Config Item' } // new item by config
37467 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37468 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37471 var a = arguments, l = a.length, item;
37472 for(var i = 0; i < l; i++){
37474 if ((typeof(el) == "object") && el.xtype && el.xns) {
37475 el = Roo.factory(el, Roo.menu);
37478 if(el.render){ // some kind of Item
37479 item = this.addItem(el);
37480 }else if(typeof el == "string"){ // string
37481 if(el == "separator" || el == "-"){
37482 item = this.addSeparator();
37484 item = this.addText(el);
37486 }else if(el.tagName || el.el){ // element
37487 item = this.addElement(el);
37488 }else if(typeof el == "object"){ // must be menu item config?
37489 item = this.addMenuItem(el);
37496 * Returns this menu's underlying {@link Roo.Element} object
37497 * @return {Roo.Element} The element
37499 getEl : function(){
37507 * Adds a separator bar to the menu
37508 * @return {Roo.menu.Item} The menu item that was added
37510 addSeparator : function(){
37511 return this.addItem(new Roo.menu.Separator());
37515 * Adds an {@link Roo.Element} object to the menu
37516 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37517 * @return {Roo.menu.Item} The menu item that was added
37519 addElement : function(el){
37520 return this.addItem(new Roo.menu.BaseItem(el));
37524 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37525 * @param {Roo.menu.Item} item The menu item to add
37526 * @return {Roo.menu.Item} The menu item that was added
37528 addItem : function(item){
37529 this.items.add(item);
37531 var li = document.createElement("li");
37532 li.className = "x-menu-list-item";
37533 this.ul.dom.appendChild(li);
37534 item.render(li, this);
37535 this.delayAutoWidth();
37541 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37542 * @param {Object} config A MenuItem config object
37543 * @return {Roo.menu.Item} The menu item that was added
37545 addMenuItem : function(config){
37546 if(!(config instanceof Roo.menu.Item)){
37547 if(typeof config.checked == "boolean"){ // must be check menu item config?
37548 config = new Roo.menu.CheckItem(config);
37550 config = new Roo.menu.Item(config);
37553 return this.addItem(config);
37557 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37558 * @param {String} text The text to display in the menu item
37559 * @return {Roo.menu.Item} The menu item that was added
37561 addText : function(text){
37562 return this.addItem(new Roo.menu.TextItem({ text : text }));
37566 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37567 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37568 * @param {Roo.menu.Item} item The menu item to add
37569 * @return {Roo.menu.Item} The menu item that was added
37571 insert : function(index, item){
37572 this.items.insert(index, item);
37574 var li = document.createElement("li");
37575 li.className = "x-menu-list-item";
37576 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37577 item.render(li, this);
37578 this.delayAutoWidth();
37584 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37585 * @param {Roo.menu.Item} item The menu item to remove
37587 remove : function(item){
37588 this.items.removeKey(item.id);
37593 * Removes and destroys all items in the menu
37595 removeAll : function(){
37597 while(f = this.items.first()){
37603 // MenuNav is a private utility class used internally by the Menu
37604 Roo.menu.MenuNav = function(menu){
37605 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37606 this.scope = this.menu = menu;
37609 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37610 doRelay : function(e, h){
37611 var k = e.getKey();
37612 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37613 this.menu.tryActivate(0, 1);
37616 return h.call(this.scope || this, e, this.menu);
37619 up : function(e, m){
37620 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37621 m.tryActivate(m.items.length-1, -1);
37625 down : function(e, m){
37626 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37627 m.tryActivate(0, 1);
37631 right : function(e, m){
37633 m.activeItem.expandMenu(true);
37637 left : function(e, m){
37639 if(m.parentMenu && m.parentMenu.activeItem){
37640 m.parentMenu.activeItem.activate();
37644 enter : function(e, m){
37646 e.stopPropagation();
37647 m.activeItem.onClick(e);
37648 m.fireEvent("click", this, m.activeItem);
37654 * Ext JS Library 1.1.1
37655 * Copyright(c) 2006-2007, Ext JS, LLC.
37657 * Originally Released Under LGPL - original licence link has changed is not relivant.
37660 * <script type="text/javascript">
37664 * @class Roo.menu.MenuMgr
37665 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37668 Roo.menu.MenuMgr = function(){
37669 var menus, active, groups = {}, attached = false, lastShow = new Date();
37671 // private - called when first menu is created
37674 active = new Roo.util.MixedCollection();
37675 Roo.get(document).addKeyListener(27, function(){
37676 if(active.length > 0){
37683 function hideAll(){
37684 if(active && active.length > 0){
37685 var c = active.clone();
37686 c.each(function(m){
37693 function onHide(m){
37695 if(active.length < 1){
37696 Roo.get(document).un("mousedown", onMouseDown);
37702 function onShow(m){
37703 var last = active.last();
37704 lastShow = new Date();
37707 Roo.get(document).on("mousedown", onMouseDown);
37711 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37712 m.parentMenu.activeChild = m;
37713 }else if(last && last.isVisible()){
37714 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37719 function onBeforeHide(m){
37721 m.activeChild.hide();
37723 if(m.autoHideTimer){
37724 clearTimeout(m.autoHideTimer);
37725 delete m.autoHideTimer;
37730 function onBeforeShow(m){
37731 var pm = m.parentMenu;
37732 if(!pm && !m.allowOtherMenus){
37734 }else if(pm && pm.activeChild && active != m){
37735 pm.activeChild.hide();
37740 function onMouseDown(e){
37741 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37747 function onBeforeCheck(mi, state){
37749 var g = groups[mi.group];
37750 for(var i = 0, l = g.length; i < l; i++){
37752 g[i].setChecked(false);
37761 * Hides all menus that are currently visible
37763 hideAll : function(){
37768 register : function(menu){
37772 menus[menu.id] = menu;
37773 menu.on("beforehide", onBeforeHide);
37774 menu.on("hide", onHide);
37775 menu.on("beforeshow", onBeforeShow);
37776 menu.on("show", onShow);
37777 var g = menu.group;
37778 if(g && menu.events["checkchange"]){
37782 groups[g].push(menu);
37783 menu.on("checkchange", onCheck);
37788 * Returns a {@link Roo.menu.Menu} object
37789 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37790 * be used to generate and return a new Menu instance.
37792 get : function(menu){
37793 if(typeof menu == "string"){ // menu id
37794 return menus[menu];
37795 }else if(menu.events){ // menu instance
37797 }else if(typeof menu.length == 'number'){ // array of menu items?
37798 return new Roo.menu.Menu({items:menu});
37799 }else{ // otherwise, must be a config
37800 return new Roo.menu.Menu(menu);
37805 unregister : function(menu){
37806 delete menus[menu.id];
37807 menu.un("beforehide", onBeforeHide);
37808 menu.un("hide", onHide);
37809 menu.un("beforeshow", onBeforeShow);
37810 menu.un("show", onShow);
37811 var g = menu.group;
37812 if(g && menu.events["checkchange"]){
37813 groups[g].remove(menu);
37814 menu.un("checkchange", onCheck);
37819 registerCheckable : function(menuItem){
37820 var g = menuItem.group;
37825 groups[g].push(menuItem);
37826 menuItem.on("beforecheckchange", onBeforeCheck);
37831 unregisterCheckable : function(menuItem){
37832 var g = menuItem.group;
37834 groups[g].remove(menuItem);
37835 menuItem.un("beforecheckchange", onBeforeCheck);
37841 * Ext JS Library 1.1.1
37842 * Copyright(c) 2006-2007, Ext JS, LLC.
37844 * Originally Released Under LGPL - original licence link has changed is not relivant.
37847 * <script type="text/javascript">
37852 * @class Roo.menu.BaseItem
37853 * @extends Roo.Component
37854 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37855 * management and base configuration options shared by all menu components.
37857 * Creates a new BaseItem
37858 * @param {Object} config Configuration options
37860 Roo.menu.BaseItem = function(config){
37861 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37866 * Fires when this item is clicked
37867 * @param {Roo.menu.BaseItem} this
37868 * @param {Roo.EventObject} e
37873 * Fires when this item is activated
37874 * @param {Roo.menu.BaseItem} this
37878 * @event deactivate
37879 * Fires when this item is deactivated
37880 * @param {Roo.menu.BaseItem} this
37886 this.on("click", this.handler, this.scope, true);
37890 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37892 * @cfg {Function} handler
37893 * A function that will handle the click event of this menu item (defaults to undefined)
37896 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37898 canActivate : false,
37901 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37906 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37908 activeClass : "x-menu-item-active",
37910 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37912 hideOnClick : true,
37914 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37919 ctype: "Roo.menu.BaseItem",
37922 actionMode : "container",
37925 render : function(container, parentMenu){
37926 this.parentMenu = parentMenu;
37927 Roo.menu.BaseItem.superclass.render.call(this, container);
37928 this.container.menuItemId = this.id;
37932 onRender : function(container, position){
37933 this.el = Roo.get(this.el);
37934 container.dom.appendChild(this.el.dom);
37938 onClick : function(e){
37939 if(!this.disabled && this.fireEvent("click", this, e) !== false
37940 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37941 this.handleClick(e);
37948 activate : function(){
37952 var li = this.container;
37953 li.addClass(this.activeClass);
37954 this.region = li.getRegion().adjust(2, 2, -2, -2);
37955 this.fireEvent("activate", this);
37960 deactivate : function(){
37961 this.container.removeClass(this.activeClass);
37962 this.fireEvent("deactivate", this);
37966 shouldDeactivate : function(e){
37967 return !this.region || !this.region.contains(e.getPoint());
37971 handleClick : function(e){
37972 if(this.hideOnClick){
37973 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37978 expandMenu : function(autoActivate){
37983 hideMenu : function(){
37988 * Ext JS Library 1.1.1
37989 * Copyright(c) 2006-2007, Ext JS, LLC.
37991 * Originally Released Under LGPL - original licence link has changed is not relivant.
37994 * <script type="text/javascript">
37998 * @class Roo.menu.Adapter
37999 * @extends Roo.menu.BaseItem
38000 * 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.
38001 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38003 * Creates a new Adapter
38004 * @param {Object} config Configuration options
38006 Roo.menu.Adapter = function(component, config){
38007 Roo.menu.Adapter.superclass.constructor.call(this, config);
38008 this.component = component;
38010 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38012 canActivate : true,
38015 onRender : function(container, position){
38016 this.component.render(container);
38017 this.el = this.component.getEl();
38021 activate : function(){
38025 this.component.focus();
38026 this.fireEvent("activate", this);
38031 deactivate : function(){
38032 this.fireEvent("deactivate", this);
38036 disable : function(){
38037 this.component.disable();
38038 Roo.menu.Adapter.superclass.disable.call(this);
38042 enable : function(){
38043 this.component.enable();
38044 Roo.menu.Adapter.superclass.enable.call(this);
38048 * Ext JS Library 1.1.1
38049 * Copyright(c) 2006-2007, Ext JS, LLC.
38051 * Originally Released Under LGPL - original licence link has changed is not relivant.
38054 * <script type="text/javascript">
38058 * @class Roo.menu.TextItem
38059 * @extends Roo.menu.BaseItem
38060 * Adds a static text string to a menu, usually used as either a heading or group separator.
38061 * Note: old style constructor with text is still supported.
38064 * Creates a new TextItem
38065 * @param {Object} cfg Configuration
38067 Roo.menu.TextItem = function(cfg){
38068 if (typeof(cfg) == 'string') {
38071 Roo.apply(this,cfg);
38074 Roo.menu.TextItem.superclass.constructor.call(this);
38077 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38079 * @cfg {Boolean} text Text to show on item.
38084 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38086 hideOnClick : false,
38088 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38090 itemCls : "x-menu-text",
38093 onRender : function(){
38094 var s = document.createElement("span");
38095 s.className = this.itemCls;
38096 s.innerHTML = this.text;
38098 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38102 * Ext JS Library 1.1.1
38103 * Copyright(c) 2006-2007, Ext JS, LLC.
38105 * Originally Released Under LGPL - original licence link has changed is not relivant.
38108 * <script type="text/javascript">
38112 * @class Roo.menu.Separator
38113 * @extends Roo.menu.BaseItem
38114 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38115 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38117 * @param {Object} config Configuration options
38119 Roo.menu.Separator = function(config){
38120 Roo.menu.Separator.superclass.constructor.call(this, config);
38123 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38125 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38127 itemCls : "x-menu-sep",
38129 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38131 hideOnClick : false,
38134 onRender : function(li){
38135 var s = document.createElement("span");
38136 s.className = this.itemCls;
38137 s.innerHTML = " ";
38139 li.addClass("x-menu-sep-li");
38140 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38144 * Ext JS Library 1.1.1
38145 * Copyright(c) 2006-2007, Ext JS, LLC.
38147 * Originally Released Under LGPL - original licence link has changed is not relivant.
38150 * <script type="text/javascript">
38153 * @class Roo.menu.Item
38154 * @extends Roo.menu.BaseItem
38155 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38156 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38157 * activation and click handling.
38159 * Creates a new Item
38160 * @param {Object} config Configuration options
38162 Roo.menu.Item = function(config){
38163 Roo.menu.Item.superclass.constructor.call(this, config);
38165 this.menu = Roo.menu.MenuMgr.get(this.menu);
38168 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38171 * @cfg {String} text
38172 * The text to show on the menu item.
38176 * @cfg {String} HTML to render in menu
38177 * The text to show on the menu item (HTML version).
38181 * @cfg {String} icon
38182 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38186 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38188 itemCls : "x-menu-item",
38190 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38192 canActivate : true,
38194 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38197 // doc'd in BaseItem
38201 ctype: "Roo.menu.Item",
38204 onRender : function(container, position){
38205 var el = document.createElement("a");
38206 el.hideFocus = true;
38207 el.unselectable = "on";
38208 el.href = this.href || "#";
38209 if(this.hrefTarget){
38210 el.target = this.hrefTarget;
38212 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38214 var html = this.html.length ? this.html : String.format('{0}',this.text);
38216 el.innerHTML = String.format(
38217 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38218 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38220 Roo.menu.Item.superclass.onRender.call(this, container, position);
38224 * Sets the text to display in this menu item
38225 * @param {String} text The text to display
38226 * @param {Boolean} isHTML true to indicate text is pure html.
38228 setText : function(text, isHTML){
38236 var html = this.html.length ? this.html : String.format('{0}',this.text);
38238 this.el.update(String.format(
38239 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38240 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38241 this.parentMenu.autoWidth();
38246 handleClick : function(e){
38247 if(!this.href){ // if no link defined, stop the event automatically
38250 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38254 activate : function(autoExpand){
38255 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38265 shouldDeactivate : function(e){
38266 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38267 if(this.menu && this.menu.isVisible()){
38268 return !this.menu.getEl().getRegion().contains(e.getPoint());
38276 deactivate : function(){
38277 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38282 expandMenu : function(autoActivate){
38283 if(!this.disabled && this.menu){
38284 clearTimeout(this.hideTimer);
38285 delete this.hideTimer;
38286 if(!this.menu.isVisible() && !this.showTimer){
38287 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38288 }else if (this.menu.isVisible() && autoActivate){
38289 this.menu.tryActivate(0, 1);
38295 deferExpand : function(autoActivate){
38296 delete this.showTimer;
38297 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38299 this.menu.tryActivate(0, 1);
38304 hideMenu : function(){
38305 clearTimeout(this.showTimer);
38306 delete this.showTimer;
38307 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38308 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38313 deferHide : function(){
38314 delete this.hideTimer;
38319 * Ext JS Library 1.1.1
38320 * Copyright(c) 2006-2007, Ext JS, LLC.
38322 * Originally Released Under LGPL - original licence link has changed is not relivant.
38325 * <script type="text/javascript">
38329 * @class Roo.menu.CheckItem
38330 * @extends Roo.menu.Item
38331 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38333 * Creates a new CheckItem
38334 * @param {Object} config Configuration options
38336 Roo.menu.CheckItem = function(config){
38337 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38340 * @event beforecheckchange
38341 * Fires before the checked value is set, providing an opportunity to cancel if needed
38342 * @param {Roo.menu.CheckItem} this
38343 * @param {Boolean} checked The new checked value that will be set
38345 "beforecheckchange" : true,
38347 * @event checkchange
38348 * Fires after the checked value has been set
38349 * @param {Roo.menu.CheckItem} this
38350 * @param {Boolean} checked The checked value that was set
38352 "checkchange" : true
38354 if(this.checkHandler){
38355 this.on('checkchange', this.checkHandler, this.scope);
38358 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38360 * @cfg {String} group
38361 * All check items with the same group name will automatically be grouped into a single-select
38362 * radio button group (defaults to '')
38365 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38367 itemCls : "x-menu-item x-menu-check-item",
38369 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38371 groupClass : "x-menu-group-item",
38374 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38375 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38376 * initialized with checked = true will be rendered as checked.
38381 ctype: "Roo.menu.CheckItem",
38384 onRender : function(c){
38385 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38387 this.el.addClass(this.groupClass);
38389 Roo.menu.MenuMgr.registerCheckable(this);
38391 this.checked = false;
38392 this.setChecked(true, true);
38397 destroy : function(){
38399 Roo.menu.MenuMgr.unregisterCheckable(this);
38401 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38405 * Set the checked state of this item
38406 * @param {Boolean} checked The new checked value
38407 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38409 setChecked : function(state, suppressEvent){
38410 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38411 if(this.container){
38412 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38414 this.checked = state;
38415 if(suppressEvent !== true){
38416 this.fireEvent("checkchange", this, state);
38422 handleClick : function(e){
38423 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38424 this.setChecked(!this.checked);
38426 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38430 * Ext JS Library 1.1.1
38431 * Copyright(c) 2006-2007, Ext JS, LLC.
38433 * Originally Released Under LGPL - original licence link has changed is not relivant.
38436 * <script type="text/javascript">
38440 * @class Roo.menu.DateItem
38441 * @extends Roo.menu.Adapter
38442 * A menu item that wraps the {@link Roo.DatPicker} component.
38444 * Creates a new DateItem
38445 * @param {Object} config Configuration options
38447 Roo.menu.DateItem = function(config){
38448 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38449 /** The Roo.DatePicker object @type Roo.DatePicker */
38450 this.picker = this.component;
38451 this.addEvents({select: true});
38453 this.picker.on("render", function(picker){
38454 picker.getEl().swallowEvent("click");
38455 picker.container.addClass("x-menu-date-item");
38458 this.picker.on("select", this.onSelect, this);
38461 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38463 onSelect : function(picker, date){
38464 this.fireEvent("select", this, date, picker);
38465 Roo.menu.DateItem.superclass.handleClick.call(this);
38469 * Ext JS Library 1.1.1
38470 * Copyright(c) 2006-2007, Ext JS, LLC.
38472 * Originally Released Under LGPL - original licence link has changed is not relivant.
38475 * <script type="text/javascript">
38479 * @class Roo.menu.ColorItem
38480 * @extends Roo.menu.Adapter
38481 * A menu item that wraps the {@link Roo.ColorPalette} component.
38483 * Creates a new ColorItem
38484 * @param {Object} config Configuration options
38486 Roo.menu.ColorItem = function(config){
38487 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38488 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38489 this.palette = this.component;
38490 this.relayEvents(this.palette, ["select"]);
38491 if(this.selectHandler){
38492 this.on('select', this.selectHandler, this.scope);
38495 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38497 * Ext JS Library 1.1.1
38498 * Copyright(c) 2006-2007, Ext JS, LLC.
38500 * Originally Released Under LGPL - original licence link has changed is not relivant.
38503 * <script type="text/javascript">
38508 * @class Roo.menu.DateMenu
38509 * @extends Roo.menu.Menu
38510 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38512 * Creates a new DateMenu
38513 * @param {Object} config Configuration options
38515 Roo.menu.DateMenu = function(config){
38516 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38518 var di = new Roo.menu.DateItem(config);
38521 * The {@link Roo.DatePicker} instance for this DateMenu
38524 this.picker = di.picker;
38527 * @param {DatePicker} picker
38528 * @param {Date} date
38530 this.relayEvents(di, ["select"]);
38531 this.on('beforeshow', function(){
38533 this.picker.hideMonthPicker(false);
38537 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38541 * Ext JS Library 1.1.1
38542 * Copyright(c) 2006-2007, Ext JS, LLC.
38544 * Originally Released Under LGPL - original licence link has changed is not relivant.
38547 * <script type="text/javascript">
38552 * @class Roo.menu.ColorMenu
38553 * @extends Roo.menu.Menu
38554 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38556 * Creates a new ColorMenu
38557 * @param {Object} config Configuration options
38559 Roo.menu.ColorMenu = function(config){
38560 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38562 var ci = new Roo.menu.ColorItem(config);
38565 * The {@link Roo.ColorPalette} instance for this ColorMenu
38566 * @type ColorPalette
38568 this.palette = ci.palette;
38571 * @param {ColorPalette} palette
38572 * @param {String} color
38574 this.relayEvents(ci, ["select"]);
38576 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38578 * Ext JS Library 1.1.1
38579 * Copyright(c) 2006-2007, Ext JS, LLC.
38581 * Originally Released Under LGPL - original licence link has changed is not relivant.
38584 * <script type="text/javascript">
38588 * @class Roo.form.Field
38589 * @extends Roo.BoxComponent
38590 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38592 * Creates a new Field
38593 * @param {Object} config Configuration options
38595 Roo.form.Field = function(config){
38596 Roo.form.Field.superclass.constructor.call(this, config);
38599 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38601 * @cfg {String} fieldLabel Label to use when rendering a form.
38604 * @cfg {String} qtip Mouse over tip
38608 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38610 invalidClass : "x-form-invalid",
38612 * @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")
38614 invalidText : "The value in this field is invalid",
38616 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38618 focusClass : "x-form-focus",
38620 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38621 automatic validation (defaults to "keyup").
38623 validationEvent : "keyup",
38625 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38627 validateOnBlur : true,
38629 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38631 validationDelay : 250,
38633 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38634 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38636 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38638 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38640 fieldClass : "x-form-field",
38642 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38645 ----------- ----------------------------------------------------------------------
38646 qtip Display a quick tip when the user hovers over the field
38647 title Display a default browser title attribute popup
38648 under Add a block div beneath the field containing the error text
38649 side Add an error icon to the right of the field with a popup on hover
38650 [element id] Add the error text directly to the innerHTML of the specified element
38653 msgTarget : 'qtip',
38655 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38660 * @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.
38665 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38670 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38672 inputType : undefined,
38675 * @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).
38677 tabIndex : undefined,
38680 isFormField : true,
38685 * @property {Roo.Element} fieldEl
38686 * Element Containing the rendered Field (with label etc.)
38689 * @cfg {Mixed} value A value to initialize this field with.
38694 * @cfg {String} name The field's HTML name attribute.
38697 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38700 loadedValue : false,
38704 initComponent : function(){
38705 Roo.form.Field.superclass.initComponent.call(this);
38709 * Fires when this field receives input focus.
38710 * @param {Roo.form.Field} this
38715 * Fires when this field loses input focus.
38716 * @param {Roo.form.Field} this
38720 * @event specialkey
38721 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38722 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38723 * @param {Roo.form.Field} this
38724 * @param {Roo.EventObject} e The event object
38729 * Fires just before the field blurs if the field value has changed.
38730 * @param {Roo.form.Field} this
38731 * @param {Mixed} newValue The new value
38732 * @param {Mixed} oldValue The original value
38737 * Fires after the field has been marked as invalid.
38738 * @param {Roo.form.Field} this
38739 * @param {String} msg The validation message
38744 * Fires after the field has been validated with no errors.
38745 * @param {Roo.form.Field} this
38750 * Fires after the key up
38751 * @param {Roo.form.Field} this
38752 * @param {Roo.EventObject} e The event Object
38759 * Returns the name attribute of the field if available
38760 * @return {String} name The field name
38762 getName: function(){
38763 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38767 onRender : function(ct, position){
38768 Roo.form.Field.superclass.onRender.call(this, ct, position);
38770 var cfg = this.getAutoCreate();
38772 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38774 if (!cfg.name.length) {
38777 if(this.inputType){
38778 cfg.type = this.inputType;
38780 this.el = ct.createChild(cfg, position);
38782 var type = this.el.dom.type;
38784 if(type == 'password'){
38787 this.el.addClass('x-form-'+type);
38790 this.el.dom.readOnly = true;
38792 if(this.tabIndex !== undefined){
38793 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38796 this.el.addClass([this.fieldClass, this.cls]);
38801 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38802 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38803 * @return {Roo.form.Field} this
38805 applyTo : function(target){
38806 this.allowDomMove = false;
38807 this.el = Roo.get(target);
38808 this.render(this.el.dom.parentNode);
38813 initValue : function(){
38814 if(this.value !== undefined){
38815 this.setValue(this.value);
38816 }else if(this.el.dom.value.length > 0){
38817 this.setValue(this.el.dom.value);
38822 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38823 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38825 isDirty : function() {
38826 if(this.disabled) {
38829 return String(this.getValue()) !== String(this.originalValue);
38833 * stores the current value in loadedValue
38835 resetHasChanged : function()
38837 this.loadedValue = String(this.getValue());
38840 * checks the current value against the 'loaded' value.
38841 * Note - will return false if 'resetHasChanged' has not been called first.
38843 hasChanged : function()
38845 if(this.disabled || this.readOnly) {
38848 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38854 afterRender : function(){
38855 Roo.form.Field.superclass.afterRender.call(this);
38860 fireKey : function(e){
38861 //Roo.log('field ' + e.getKey());
38862 if(e.isNavKeyPress()){
38863 this.fireEvent("specialkey", this, e);
38868 * Resets the current field value to the originally loaded value and clears any validation messages
38870 reset : function(){
38871 this.setValue(this.resetValue);
38872 this.clearInvalid();
38876 initEvents : function(){
38877 // safari killled keypress - so keydown is now used..
38878 this.el.on("keydown" , this.fireKey, this);
38879 this.el.on("focus", this.onFocus, this);
38880 this.el.on("blur", this.onBlur, this);
38881 this.el.relayEvent('keyup', this);
38883 // reference to original value for reset
38884 this.originalValue = this.getValue();
38885 this.resetValue = this.getValue();
38889 onFocus : function(){
38890 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38891 this.el.addClass(this.focusClass);
38893 if(!this.hasFocus){
38894 this.hasFocus = true;
38895 this.startValue = this.getValue();
38896 this.fireEvent("focus", this);
38900 beforeBlur : Roo.emptyFn,
38903 onBlur : function(){
38905 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38906 this.el.removeClass(this.focusClass);
38908 this.hasFocus = false;
38909 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38912 var v = this.getValue();
38913 if(String(v) !== String(this.startValue)){
38914 this.fireEvent('change', this, v, this.startValue);
38916 this.fireEvent("blur", this);
38920 * Returns whether or not the field value is currently valid
38921 * @param {Boolean} preventMark True to disable marking the field invalid
38922 * @return {Boolean} True if the value is valid, else false
38924 isValid : function(preventMark){
38928 var restore = this.preventMark;
38929 this.preventMark = preventMark === true;
38930 var v = this.validateValue(this.processValue(this.getRawValue()));
38931 this.preventMark = restore;
38936 * Validates the field value
38937 * @return {Boolean} True if the value is valid, else false
38939 validate : function(){
38940 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38941 this.clearInvalid();
38947 processValue : function(value){
38952 // Subclasses should provide the validation implementation by overriding this
38953 validateValue : function(value){
38958 * Mark this field as invalid
38959 * @param {String} msg The validation message
38961 markInvalid : function(msg){
38962 if(!this.rendered || this.preventMark){ // not rendered
38966 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38968 obj.el.addClass(this.invalidClass);
38969 msg = msg || this.invalidText;
38970 switch(this.msgTarget){
38972 obj.el.dom.qtip = msg;
38973 obj.el.dom.qclass = 'x-form-invalid-tip';
38974 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38975 Roo.QuickTips.enable();
38979 this.el.dom.title = msg;
38983 var elp = this.el.findParent('.x-form-element', 5, true);
38984 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38985 this.errorEl.setWidth(elp.getWidth(true)-20);
38987 this.errorEl.update(msg);
38988 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38991 if(!this.errorIcon){
38992 var elp = this.el.findParent('.x-form-element', 5, true);
38993 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38995 this.alignErrorIcon();
38996 this.errorIcon.dom.qtip = msg;
38997 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38998 this.errorIcon.show();
38999 this.on('resize', this.alignErrorIcon, this);
39002 var t = Roo.getDom(this.msgTarget);
39004 t.style.display = this.msgDisplay;
39007 this.fireEvent('invalid', this, msg);
39011 alignErrorIcon : function(){
39012 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39016 * Clear any invalid styles/messages for this field
39018 clearInvalid : function(){
39019 if(!this.rendered || this.preventMark){ // not rendered
39022 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39024 obj.el.removeClass(this.invalidClass);
39025 switch(this.msgTarget){
39027 obj.el.dom.qtip = '';
39030 this.el.dom.title = '';
39034 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39038 if(this.errorIcon){
39039 this.errorIcon.dom.qtip = '';
39040 this.errorIcon.hide();
39041 this.un('resize', this.alignErrorIcon, this);
39045 var t = Roo.getDom(this.msgTarget);
39047 t.style.display = 'none';
39050 this.fireEvent('valid', this);
39054 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39055 * @return {Mixed} value The field value
39057 getRawValue : function(){
39058 var v = this.el.getValue();
39064 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39065 * @return {Mixed} value The field value
39067 getValue : function(){
39068 var v = this.el.getValue();
39074 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39075 * @param {Mixed} value The value to set
39077 setRawValue : function(v){
39078 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39082 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39083 * @param {Mixed} value The value to set
39085 setValue : function(v){
39088 this.el.dom.value = (v === null || v === undefined ? '' : v);
39093 adjustSize : function(w, h){
39094 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39095 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39099 adjustWidth : function(tag, w){
39100 tag = tag.toLowerCase();
39101 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39102 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39103 if(tag == 'input'){
39106 if(tag == 'textarea'){
39109 }else if(Roo.isOpera){
39110 if(tag == 'input'){
39113 if(tag == 'textarea'){
39123 // anything other than normal should be considered experimental
39124 Roo.form.Field.msgFx = {
39126 show: function(msgEl, f){
39127 msgEl.setDisplayed('block');
39130 hide : function(msgEl, f){
39131 msgEl.setDisplayed(false).update('');
39136 show: function(msgEl, f){
39137 msgEl.slideIn('t', {stopFx:true});
39140 hide : function(msgEl, f){
39141 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39146 show: function(msgEl, f){
39147 msgEl.fixDisplay();
39148 msgEl.alignTo(f.el, 'tl-tr');
39149 msgEl.slideIn('l', {stopFx:true});
39152 hide : function(msgEl, f){
39153 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39158 * Ext JS Library 1.1.1
39159 * Copyright(c) 2006-2007, Ext JS, LLC.
39161 * Originally Released Under LGPL - original licence link has changed is not relivant.
39164 * <script type="text/javascript">
39169 * @class Roo.form.TextField
39170 * @extends Roo.form.Field
39171 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39172 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39174 * Creates a new TextField
39175 * @param {Object} config Configuration options
39177 Roo.form.TextField = function(config){
39178 Roo.form.TextField.superclass.constructor.call(this, config);
39182 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39183 * according to the default logic, but this event provides a hook for the developer to apply additional
39184 * logic at runtime to resize the field if needed.
39185 * @param {Roo.form.Field} this This text field
39186 * @param {Number} width The new field width
39192 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39194 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39198 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39202 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39206 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39210 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39214 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39216 disableKeyFilter : false,
39218 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39222 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39226 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39228 maxLength : Number.MAX_VALUE,
39230 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39232 minLengthText : "The minimum length for this field is {0}",
39234 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39236 maxLengthText : "The maximum length for this field is {0}",
39238 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39240 selectOnFocus : false,
39242 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39244 blankText : "This field is required",
39246 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39247 * If available, this function will be called only after the basic validators all return true, and will be passed the
39248 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39252 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39253 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39254 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39258 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39262 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39268 initEvents : function()
39270 if (this.emptyText) {
39271 this.el.attr('placeholder', this.emptyText);
39274 Roo.form.TextField.superclass.initEvents.call(this);
39275 if(this.validationEvent == 'keyup'){
39276 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39277 this.el.on('keyup', this.filterValidation, this);
39279 else if(this.validationEvent !== false){
39280 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39283 if(this.selectOnFocus){
39284 this.on("focus", this.preFocus, this);
39287 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39288 this.el.on("keypress", this.filterKeys, this);
39291 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39292 this.el.on("click", this.autoSize, this);
39294 if(this.el.is('input[type=password]') && Roo.isSafari){
39295 this.el.on('keydown', this.SafariOnKeyDown, this);
39299 processValue : function(value){
39300 if(this.stripCharsRe){
39301 var newValue = value.replace(this.stripCharsRe, '');
39302 if(newValue !== value){
39303 this.setRawValue(newValue);
39310 filterValidation : function(e){
39311 if(!e.isNavKeyPress()){
39312 this.validationTask.delay(this.validationDelay);
39317 onKeyUp : function(e){
39318 if(!e.isNavKeyPress()){
39324 * Resets the current field value to the originally-loaded value and clears any validation messages.
39327 reset : function(){
39328 Roo.form.TextField.superclass.reset.call(this);
39334 preFocus : function(){
39336 if(this.selectOnFocus){
39337 this.el.dom.select();
39343 filterKeys : function(e){
39344 var k = e.getKey();
39345 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39348 var c = e.getCharCode(), cc = String.fromCharCode(c);
39349 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39352 if(!this.maskRe.test(cc)){
39357 setValue : function(v){
39359 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39365 * Validates a value according to the field's validation rules and marks the field as invalid
39366 * if the validation fails
39367 * @param {Mixed} value The value to validate
39368 * @return {Boolean} True if the value is valid, else false
39370 validateValue : function(value){
39371 if(value.length < 1) { // if it's blank
39372 if(this.allowBlank){
39373 this.clearInvalid();
39376 this.markInvalid(this.blankText);
39380 if(value.length < this.minLength){
39381 this.markInvalid(String.format(this.minLengthText, this.minLength));
39384 if(value.length > this.maxLength){
39385 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39389 var vt = Roo.form.VTypes;
39390 if(!vt[this.vtype](value, this)){
39391 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39395 if(typeof this.validator == "function"){
39396 var msg = this.validator(value);
39398 this.markInvalid(msg);
39402 if(this.regex && !this.regex.test(value)){
39403 this.markInvalid(this.regexText);
39410 * Selects text in this field
39411 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39412 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39414 selectText : function(start, end){
39415 var v = this.getRawValue();
39417 start = start === undefined ? 0 : start;
39418 end = end === undefined ? v.length : end;
39419 var d = this.el.dom;
39420 if(d.setSelectionRange){
39421 d.setSelectionRange(start, end);
39422 }else if(d.createTextRange){
39423 var range = d.createTextRange();
39424 range.moveStart("character", start);
39425 range.moveEnd("character", v.length-end);
39432 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39433 * This only takes effect if grow = true, and fires the autosize event.
39435 autoSize : function(){
39436 if(!this.grow || !this.rendered){
39440 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39443 var v = el.dom.value;
39444 var d = document.createElement('div');
39445 d.appendChild(document.createTextNode(v));
39449 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39450 this.el.setWidth(w);
39451 this.fireEvent("autosize", this, w);
39455 SafariOnKeyDown : function(event)
39457 // this is a workaround for a password hang bug on chrome/ webkit.
39459 var isSelectAll = false;
39461 if(this.el.dom.selectionEnd > 0){
39462 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39464 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39465 event.preventDefault();
39470 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39472 event.preventDefault();
39473 // this is very hacky as keydown always get's upper case.
39475 var cc = String.fromCharCode(event.getCharCode());
39478 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39486 * Ext JS Library 1.1.1
39487 * Copyright(c) 2006-2007, Ext JS, LLC.
39489 * Originally Released Under LGPL - original licence link has changed is not relivant.
39492 * <script type="text/javascript">
39496 * @class Roo.form.Hidden
39497 * @extends Roo.form.TextField
39498 * Simple Hidden element used on forms
39500 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39503 * Creates a new Hidden form element.
39504 * @param {Object} config Configuration options
39509 // easy hidden field...
39510 Roo.form.Hidden = function(config){
39511 Roo.form.Hidden.superclass.constructor.call(this, config);
39514 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39516 inputType: 'hidden',
39519 labelSeparator: '',
39521 itemCls : 'x-form-item-display-none'
39529 * Ext JS Library 1.1.1
39530 * Copyright(c) 2006-2007, Ext JS, LLC.
39532 * Originally Released Under LGPL - original licence link has changed is not relivant.
39535 * <script type="text/javascript">
39539 * @class Roo.form.TriggerField
39540 * @extends Roo.form.TextField
39541 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39542 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39543 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39544 * for which you can provide a custom implementation. For example:
39546 var trigger = new Roo.form.TriggerField();
39547 trigger.onTriggerClick = myTriggerFn;
39548 trigger.applyTo('my-field');
39551 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39552 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39553 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39554 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39556 * Create a new TriggerField.
39557 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39558 * to the base TextField)
39560 Roo.form.TriggerField = function(config){
39561 this.mimicing = false;
39562 Roo.form.TriggerField.superclass.constructor.call(this, config);
39565 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39567 * @cfg {String} triggerClass A CSS class to apply to the trigger
39570 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39571 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39573 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39575 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39579 /** @cfg {Boolean} grow @hide */
39580 /** @cfg {Number} growMin @hide */
39581 /** @cfg {Number} growMax @hide */
39587 autoSize: Roo.emptyFn,
39591 deferHeight : true,
39594 actionMode : 'wrap',
39596 onResize : function(w, h){
39597 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39598 if(typeof w == 'number'){
39599 var x = w - this.trigger.getWidth();
39600 this.el.setWidth(this.adjustWidth('input', x));
39601 this.trigger.setStyle('left', x+'px');
39606 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39609 getResizeEl : function(){
39614 getPositionEl : function(){
39619 alignErrorIcon : function(){
39620 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39624 onRender : function(ct, position){
39625 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39626 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39627 this.trigger = this.wrap.createChild(this.triggerConfig ||
39628 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39629 if(this.hideTrigger){
39630 this.trigger.setDisplayed(false);
39632 this.initTrigger();
39634 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39639 initTrigger : function(){
39640 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39641 this.trigger.addClassOnOver('x-form-trigger-over');
39642 this.trigger.addClassOnClick('x-form-trigger-click');
39646 onDestroy : function(){
39648 this.trigger.removeAllListeners();
39649 this.trigger.remove();
39652 this.wrap.remove();
39654 Roo.form.TriggerField.superclass.onDestroy.call(this);
39658 onFocus : function(){
39659 Roo.form.TriggerField.superclass.onFocus.call(this);
39660 if(!this.mimicing){
39661 this.wrap.addClass('x-trigger-wrap-focus');
39662 this.mimicing = true;
39663 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39664 if(this.monitorTab){
39665 this.el.on("keydown", this.checkTab, this);
39671 checkTab : function(e){
39672 if(e.getKey() == e.TAB){
39673 this.triggerBlur();
39678 onBlur : function(){
39683 mimicBlur : function(e, t){
39684 if(!this.wrap.contains(t) && this.validateBlur()){
39685 this.triggerBlur();
39690 triggerBlur : function(){
39691 this.mimicing = false;
39692 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39693 if(this.monitorTab){
39694 this.el.un("keydown", this.checkTab, this);
39696 this.wrap.removeClass('x-trigger-wrap-focus');
39697 Roo.form.TriggerField.superclass.onBlur.call(this);
39701 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39702 validateBlur : function(e, t){
39707 onDisable : function(){
39708 Roo.form.TriggerField.superclass.onDisable.call(this);
39710 this.wrap.addClass('x-item-disabled');
39715 onEnable : function(){
39716 Roo.form.TriggerField.superclass.onEnable.call(this);
39718 this.wrap.removeClass('x-item-disabled');
39723 onShow : function(){
39724 var ae = this.getActionEl();
39727 ae.dom.style.display = '';
39728 ae.dom.style.visibility = 'visible';
39734 onHide : function(){
39735 var ae = this.getActionEl();
39736 ae.dom.style.display = 'none';
39740 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39741 * by an implementing function.
39743 * @param {EventObject} e
39745 onTriggerClick : Roo.emptyFn
39748 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39749 // to be extended by an implementing class. For an example of implementing this class, see the custom
39750 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39751 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39752 initComponent : function(){
39753 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39755 this.triggerConfig = {
39756 tag:'span', cls:'x-form-twin-triggers', cn:[
39757 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39758 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39762 getTrigger : function(index){
39763 return this.triggers[index];
39766 initTrigger : function(){
39767 var ts = this.trigger.select('.x-form-trigger', true);
39768 this.wrap.setStyle('overflow', 'hidden');
39769 var triggerField = this;
39770 ts.each(function(t, all, index){
39771 t.hide = function(){
39772 var w = triggerField.wrap.getWidth();
39773 this.dom.style.display = 'none';
39774 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39776 t.show = function(){
39777 var w = triggerField.wrap.getWidth();
39778 this.dom.style.display = '';
39779 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39781 var triggerIndex = 'Trigger'+(index+1);
39783 if(this['hide'+triggerIndex]){
39784 t.dom.style.display = 'none';
39786 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39787 t.addClassOnOver('x-form-trigger-over');
39788 t.addClassOnClick('x-form-trigger-click');
39790 this.triggers = ts.elements;
39793 onTrigger1Click : Roo.emptyFn,
39794 onTrigger2Click : Roo.emptyFn
39797 * Ext JS Library 1.1.1
39798 * Copyright(c) 2006-2007, Ext JS, LLC.
39800 * Originally Released Under LGPL - original licence link has changed is not relivant.
39803 * <script type="text/javascript">
39807 * @class Roo.form.TextArea
39808 * @extends Roo.form.TextField
39809 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39810 * support for auto-sizing.
39812 * Creates a new TextArea
39813 * @param {Object} config Configuration options
39815 Roo.form.TextArea = function(config){
39816 Roo.form.TextArea.superclass.constructor.call(this, config);
39817 // these are provided exchanges for backwards compat
39818 // minHeight/maxHeight were replaced by growMin/growMax to be
39819 // compatible with TextField growing config values
39820 if(this.minHeight !== undefined){
39821 this.growMin = this.minHeight;
39823 if(this.maxHeight !== undefined){
39824 this.growMax = this.maxHeight;
39828 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39830 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39834 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39838 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39839 * in the field (equivalent to setting overflow: hidden, defaults to false)
39841 preventScrollbars: false,
39843 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39844 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39848 onRender : function(ct, position){
39850 this.defaultAutoCreate = {
39852 style:"width:300px;height:60px;",
39853 autocomplete: "new-password"
39856 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39858 this.textSizeEl = Roo.DomHelper.append(document.body, {
39859 tag: "pre", cls: "x-form-grow-sizer"
39861 if(this.preventScrollbars){
39862 this.el.setStyle("overflow", "hidden");
39864 this.el.setHeight(this.growMin);
39868 onDestroy : function(){
39869 if(this.textSizeEl){
39870 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39872 Roo.form.TextArea.superclass.onDestroy.call(this);
39876 onKeyUp : function(e){
39877 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39883 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39884 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39886 autoSize : function(){
39887 if(!this.grow || !this.textSizeEl){
39891 var v = el.dom.value;
39892 var ts = this.textSizeEl;
39895 ts.appendChild(document.createTextNode(v));
39898 Roo.fly(ts).setWidth(this.el.getWidth());
39900 v = "  ";
39903 v = v.replace(/\n/g, '<p> </p>');
39905 v += " \n ";
39908 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39909 if(h != this.lastHeight){
39910 this.lastHeight = h;
39911 this.el.setHeight(h);
39912 this.fireEvent("autosize", this, h);
39917 * Ext JS Library 1.1.1
39918 * Copyright(c) 2006-2007, Ext JS, LLC.
39920 * Originally Released Under LGPL - original licence link has changed is not relivant.
39923 * <script type="text/javascript">
39928 * @class Roo.form.NumberField
39929 * @extends Roo.form.TextField
39930 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39932 * Creates a new NumberField
39933 * @param {Object} config Configuration options
39935 Roo.form.NumberField = function(config){
39936 Roo.form.NumberField.superclass.constructor.call(this, config);
39939 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39941 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39943 fieldClass: "x-form-field x-form-num-field",
39945 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39947 allowDecimals : true,
39949 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39951 decimalSeparator : ".",
39953 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39955 decimalPrecision : 2,
39957 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39959 allowNegative : true,
39961 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39963 minValue : Number.NEGATIVE_INFINITY,
39965 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39967 maxValue : Number.MAX_VALUE,
39969 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39971 minText : "The minimum value for this field is {0}",
39973 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39975 maxText : "The maximum value for this field is {0}",
39977 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39978 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39980 nanText : "{0} is not a valid number",
39983 initEvents : function(){
39984 Roo.form.NumberField.superclass.initEvents.call(this);
39985 var allowed = "0123456789";
39986 if(this.allowDecimals){
39987 allowed += this.decimalSeparator;
39989 if(this.allowNegative){
39992 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39993 var keyPress = function(e){
39994 var k = e.getKey();
39995 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39998 var c = e.getCharCode();
39999 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40003 this.el.on("keypress", keyPress, this);
40007 validateValue : function(value){
40008 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40011 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40014 var num = this.parseValue(value);
40016 this.markInvalid(String.format(this.nanText, value));
40019 if(num < this.minValue){
40020 this.markInvalid(String.format(this.minText, this.minValue));
40023 if(num > this.maxValue){
40024 this.markInvalid(String.format(this.maxText, this.maxValue));
40030 getValue : function(){
40031 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40035 parseValue : function(value){
40036 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40037 return isNaN(value) ? '' : value;
40041 fixPrecision : function(value){
40042 var nan = isNaN(value);
40043 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40044 return nan ? '' : value;
40046 return parseFloat(value).toFixed(this.decimalPrecision);
40049 setValue : function(v){
40050 v = this.fixPrecision(v);
40051 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40055 decimalPrecisionFcn : function(v){
40056 return Math.floor(v);
40059 beforeBlur : function(){
40060 var v = this.parseValue(this.getRawValue());
40067 * Ext JS Library 1.1.1
40068 * Copyright(c) 2006-2007, Ext JS, LLC.
40070 * Originally Released Under LGPL - original licence link has changed is not relivant.
40073 * <script type="text/javascript">
40077 * @class Roo.form.DateField
40078 * @extends Roo.form.TriggerField
40079 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40081 * Create a new DateField
40082 * @param {Object} config
40084 Roo.form.DateField = function(config){
40085 Roo.form.DateField.superclass.constructor.call(this, config);
40091 * Fires when a date is selected
40092 * @param {Roo.form.DateField} combo This combo box
40093 * @param {Date} date The date selected
40100 if(typeof this.minValue == "string") {
40101 this.minValue = this.parseDate(this.minValue);
40103 if(typeof this.maxValue == "string") {
40104 this.maxValue = this.parseDate(this.maxValue);
40106 this.ddMatch = null;
40107 if(this.disabledDates){
40108 var dd = this.disabledDates;
40110 for(var i = 0; i < dd.length; i++){
40112 if(i != dd.length-1) {
40116 this.ddMatch = new RegExp(re + ")");
40120 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40122 * @cfg {String} format
40123 * The default date format string which can be overriden for localization support. The format must be
40124 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40128 * @cfg {String} altFormats
40129 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40130 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40132 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40134 * @cfg {Array} disabledDays
40135 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40137 disabledDays : null,
40139 * @cfg {String} disabledDaysText
40140 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40142 disabledDaysText : "Disabled",
40144 * @cfg {Array} disabledDates
40145 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40146 * expression so they are very powerful. Some examples:
40148 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40149 * <li>["03/08", "09/16"] would disable those days for every year</li>
40150 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40151 * <li>["03/../2006"] would disable every day in March 2006</li>
40152 * <li>["^03"] would disable every day in every March</li>
40154 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40155 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40157 disabledDates : null,
40159 * @cfg {String} disabledDatesText
40160 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40162 disabledDatesText : "Disabled",
40164 * @cfg {Date/String} minValue
40165 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40166 * valid format (defaults to null).
40170 * @cfg {Date/String} maxValue
40171 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40172 * valid format (defaults to null).
40176 * @cfg {String} minText
40177 * The error text to display when the date in the cell is before minValue (defaults to
40178 * 'The date in this field must be after {minValue}').
40180 minText : "The date in this field must be equal to or after {0}",
40182 * @cfg {String} maxText
40183 * The error text to display when the date in the cell is after maxValue (defaults to
40184 * 'The date in this field must be before {maxValue}').
40186 maxText : "The date in this field must be equal to or before {0}",
40188 * @cfg {String} invalidText
40189 * The error text to display when the date in the field is invalid (defaults to
40190 * '{value} is not a valid date - it must be in the format {format}').
40192 invalidText : "{0} is not a valid date - it must be in the format {1}",
40194 * @cfg {String} triggerClass
40195 * An additional CSS class used to style the trigger button. The trigger will always get the
40196 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40197 * which displays a calendar icon).
40199 triggerClass : 'x-form-date-trigger',
40203 * @cfg {Boolean} useIso
40204 * if enabled, then the date field will use a hidden field to store the
40205 * real value as iso formated date. default (false)
40209 * @cfg {String/Object} autoCreate
40210 * A DomHelper element spec, or true for a default element spec (defaults to
40211 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40214 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40217 hiddenField: false,
40219 onRender : function(ct, position)
40221 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40223 //this.el.dom.removeAttribute('name');
40224 Roo.log("Changing name?");
40225 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40226 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40228 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40229 // prevent input submission
40230 this.hiddenName = this.name;
40237 validateValue : function(value)
40239 value = this.formatDate(value);
40240 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40241 Roo.log('super failed');
40244 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40247 var svalue = value;
40248 value = this.parseDate(value);
40250 Roo.log('parse date failed' + svalue);
40251 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40254 var time = value.getTime();
40255 if(this.minValue && time < this.minValue.getTime()){
40256 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40259 if(this.maxValue && time > this.maxValue.getTime()){
40260 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40263 if(this.disabledDays){
40264 var day = value.getDay();
40265 for(var i = 0; i < this.disabledDays.length; i++) {
40266 if(day === this.disabledDays[i]){
40267 this.markInvalid(this.disabledDaysText);
40272 var fvalue = this.formatDate(value);
40273 if(this.ddMatch && this.ddMatch.test(fvalue)){
40274 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40281 // Provides logic to override the default TriggerField.validateBlur which just returns true
40282 validateBlur : function(){
40283 return !this.menu || !this.menu.isVisible();
40286 getName: function()
40288 // returns hidden if it's set..
40289 if (!this.rendered) {return ''};
40290 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40295 * Returns the current date value of the date field.
40296 * @return {Date} The date value
40298 getValue : function(){
40300 return this.hiddenField ?
40301 this.hiddenField.value :
40302 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40306 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40307 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40308 * (the default format used is "m/d/y").
40311 //All of these calls set the same date value (May 4, 2006)
40313 //Pass a date object:
40314 var dt = new Date('5/4/06');
40315 dateField.setValue(dt);
40317 //Pass a date string (default format):
40318 dateField.setValue('5/4/06');
40320 //Pass a date string (custom format):
40321 dateField.format = 'Y-m-d';
40322 dateField.setValue('2006-5-4');
40324 * @param {String/Date} date The date or valid date string
40326 setValue : function(date){
40327 if (this.hiddenField) {
40328 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40330 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40331 // make sure the value field is always stored as a date..
40332 this.value = this.parseDate(date);
40338 parseDate : function(value){
40339 if(!value || value instanceof Date){
40342 var v = Date.parseDate(value, this.format);
40343 if (!v && this.useIso) {
40344 v = Date.parseDate(value, 'Y-m-d');
40346 if(!v && this.altFormats){
40347 if(!this.altFormatsArray){
40348 this.altFormatsArray = this.altFormats.split("|");
40350 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40351 v = Date.parseDate(value, this.altFormatsArray[i]);
40358 formatDate : function(date, fmt){
40359 return (!date || !(date instanceof Date)) ?
40360 date : date.dateFormat(fmt || this.format);
40365 select: function(m, d){
40368 this.fireEvent('select', this, d);
40370 show : function(){ // retain focus styling
40374 this.focus.defer(10, this);
40375 var ml = this.menuListeners;
40376 this.menu.un("select", ml.select, this);
40377 this.menu.un("show", ml.show, this);
40378 this.menu.un("hide", ml.hide, this);
40383 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40384 onTriggerClick : function(){
40388 if(this.menu == null){
40389 this.menu = new Roo.menu.DateMenu();
40391 Roo.apply(this.menu.picker, {
40392 showClear: this.allowBlank,
40393 minDate : this.minValue,
40394 maxDate : this.maxValue,
40395 disabledDatesRE : this.ddMatch,
40396 disabledDatesText : this.disabledDatesText,
40397 disabledDays : this.disabledDays,
40398 disabledDaysText : this.disabledDaysText,
40399 format : this.useIso ? 'Y-m-d' : this.format,
40400 minText : String.format(this.minText, this.formatDate(this.minValue)),
40401 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40403 this.menu.on(Roo.apply({}, this.menuListeners, {
40406 this.menu.picker.setValue(this.getValue() || new Date());
40407 this.menu.show(this.el, "tl-bl?");
40410 beforeBlur : function(){
40411 var v = this.parseDate(this.getRawValue());
40421 isDirty : function() {
40422 if(this.disabled) {
40426 if(typeof(this.startValue) === 'undefined'){
40430 return String(this.getValue()) !== String(this.startValue);
40435 * Ext JS Library 1.1.1
40436 * Copyright(c) 2006-2007, Ext JS, LLC.
40438 * Originally Released Under LGPL - original licence link has changed is not relivant.
40441 * <script type="text/javascript">
40445 * @class Roo.form.MonthField
40446 * @extends Roo.form.TriggerField
40447 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40449 * Create a new MonthField
40450 * @param {Object} config
40452 Roo.form.MonthField = function(config){
40454 Roo.form.MonthField.superclass.constructor.call(this, config);
40460 * Fires when a date is selected
40461 * @param {Roo.form.MonthFieeld} combo This combo box
40462 * @param {Date} date The date selected
40469 if(typeof this.minValue == "string") {
40470 this.minValue = this.parseDate(this.minValue);
40472 if(typeof this.maxValue == "string") {
40473 this.maxValue = this.parseDate(this.maxValue);
40475 this.ddMatch = null;
40476 if(this.disabledDates){
40477 var dd = this.disabledDates;
40479 for(var i = 0; i < dd.length; i++){
40481 if(i != dd.length-1) {
40485 this.ddMatch = new RegExp(re + ")");
40489 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40491 * @cfg {String} format
40492 * The default date format string which can be overriden for localization support. The format must be
40493 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40497 * @cfg {String} altFormats
40498 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40499 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40501 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40503 * @cfg {Array} disabledDays
40504 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40506 disabledDays : [0,1,2,3,4,5,6],
40508 * @cfg {String} disabledDaysText
40509 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40511 disabledDaysText : "Disabled",
40513 * @cfg {Array} disabledDates
40514 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40515 * expression so they are very powerful. Some examples:
40517 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40518 * <li>["03/08", "09/16"] would disable those days for every year</li>
40519 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40520 * <li>["03/../2006"] would disable every day in March 2006</li>
40521 * <li>["^03"] would disable every day in every March</li>
40523 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40524 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40526 disabledDates : null,
40528 * @cfg {String} disabledDatesText
40529 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40531 disabledDatesText : "Disabled",
40533 * @cfg {Date/String} minValue
40534 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40535 * valid format (defaults to null).
40539 * @cfg {Date/String} maxValue
40540 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40541 * valid format (defaults to null).
40545 * @cfg {String} minText
40546 * The error text to display when the date in the cell is before minValue (defaults to
40547 * 'The date in this field must be after {minValue}').
40549 minText : "The date in this field must be equal to or after {0}",
40551 * @cfg {String} maxTextf
40552 * The error text to display when the date in the cell is after maxValue (defaults to
40553 * 'The date in this field must be before {maxValue}').
40555 maxText : "The date in this field must be equal to or before {0}",
40557 * @cfg {String} invalidText
40558 * The error text to display when the date in the field is invalid (defaults to
40559 * '{value} is not a valid date - it must be in the format {format}').
40561 invalidText : "{0} is not a valid date - it must be in the format {1}",
40563 * @cfg {String} triggerClass
40564 * An additional CSS class used to style the trigger button. The trigger will always get the
40565 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40566 * which displays a calendar icon).
40568 triggerClass : 'x-form-date-trigger',
40572 * @cfg {Boolean} useIso
40573 * if enabled, then the date field will use a hidden field to store the
40574 * real value as iso formated date. default (true)
40578 * @cfg {String/Object} autoCreate
40579 * A DomHelper element spec, or true for a default element spec (defaults to
40580 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40583 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40586 hiddenField: false,
40588 hideMonthPicker : false,
40590 onRender : function(ct, position)
40592 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40594 this.el.dom.removeAttribute('name');
40595 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40597 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40598 // prevent input submission
40599 this.hiddenName = this.name;
40606 validateValue : function(value)
40608 value = this.formatDate(value);
40609 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40612 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40615 var svalue = value;
40616 value = this.parseDate(value);
40618 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40621 var time = value.getTime();
40622 if(this.minValue && time < this.minValue.getTime()){
40623 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40626 if(this.maxValue && time > this.maxValue.getTime()){
40627 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40630 /*if(this.disabledDays){
40631 var day = value.getDay();
40632 for(var i = 0; i < this.disabledDays.length; i++) {
40633 if(day === this.disabledDays[i]){
40634 this.markInvalid(this.disabledDaysText);
40640 var fvalue = this.formatDate(value);
40641 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40642 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40650 // Provides logic to override the default TriggerField.validateBlur which just returns true
40651 validateBlur : function(){
40652 return !this.menu || !this.menu.isVisible();
40656 * Returns the current date value of the date field.
40657 * @return {Date} The date value
40659 getValue : function(){
40663 return this.hiddenField ?
40664 this.hiddenField.value :
40665 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40669 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40670 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40671 * (the default format used is "m/d/y").
40674 //All of these calls set the same date value (May 4, 2006)
40676 //Pass a date object:
40677 var dt = new Date('5/4/06');
40678 monthField.setValue(dt);
40680 //Pass a date string (default format):
40681 monthField.setValue('5/4/06');
40683 //Pass a date string (custom format):
40684 monthField.format = 'Y-m-d';
40685 monthField.setValue('2006-5-4');
40687 * @param {String/Date} date The date or valid date string
40689 setValue : function(date){
40690 Roo.log('month setValue' + date);
40691 // can only be first of month..
40693 var val = this.parseDate(date);
40695 if (this.hiddenField) {
40696 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40698 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40699 this.value = this.parseDate(date);
40703 parseDate : function(value){
40704 if(!value || value instanceof Date){
40705 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40708 var v = Date.parseDate(value, this.format);
40709 if (!v && this.useIso) {
40710 v = Date.parseDate(value, 'Y-m-d');
40714 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40718 if(!v && this.altFormats){
40719 if(!this.altFormatsArray){
40720 this.altFormatsArray = this.altFormats.split("|");
40722 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40723 v = Date.parseDate(value, this.altFormatsArray[i]);
40730 formatDate : function(date, fmt){
40731 return (!date || !(date instanceof Date)) ?
40732 date : date.dateFormat(fmt || this.format);
40737 select: function(m, d){
40739 this.fireEvent('select', this, d);
40741 show : function(){ // retain focus styling
40745 this.focus.defer(10, this);
40746 var ml = this.menuListeners;
40747 this.menu.un("select", ml.select, this);
40748 this.menu.un("show", ml.show, this);
40749 this.menu.un("hide", ml.hide, this);
40753 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40754 onTriggerClick : function(){
40758 if(this.menu == null){
40759 this.menu = new Roo.menu.DateMenu();
40763 Roo.apply(this.menu.picker, {
40765 showClear: this.allowBlank,
40766 minDate : this.minValue,
40767 maxDate : this.maxValue,
40768 disabledDatesRE : this.ddMatch,
40769 disabledDatesText : this.disabledDatesText,
40771 format : this.useIso ? 'Y-m-d' : this.format,
40772 minText : String.format(this.minText, this.formatDate(this.minValue)),
40773 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40776 this.menu.on(Roo.apply({}, this.menuListeners, {
40784 // hide month picker get's called when we called by 'before hide';
40786 var ignorehide = true;
40787 p.hideMonthPicker = function(disableAnim){
40791 if(this.monthPicker){
40792 Roo.log("hideMonthPicker called");
40793 if(disableAnim === true){
40794 this.monthPicker.hide();
40796 this.monthPicker.slideOut('t', {duration:.2});
40797 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40798 p.fireEvent("select", this, this.value);
40804 Roo.log('picker set value');
40805 Roo.log(this.getValue());
40806 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40807 m.show(this.el, 'tl-bl?');
40808 ignorehide = false;
40809 // this will trigger hideMonthPicker..
40812 // hidden the day picker
40813 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40819 p.showMonthPicker.defer(100, p);
40825 beforeBlur : function(){
40826 var v = this.parseDate(this.getRawValue());
40832 /** @cfg {Boolean} grow @hide */
40833 /** @cfg {Number} growMin @hide */
40834 /** @cfg {Number} growMax @hide */
40841 * Ext JS Library 1.1.1
40842 * Copyright(c) 2006-2007, Ext JS, LLC.
40844 * Originally Released Under LGPL - original licence link has changed is not relivant.
40847 * <script type="text/javascript">
40852 * @class Roo.form.ComboBox
40853 * @extends Roo.form.TriggerField
40854 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40856 * Create a new ComboBox.
40857 * @param {Object} config Configuration options
40859 Roo.form.ComboBox = function(config){
40860 Roo.form.ComboBox.superclass.constructor.call(this, config);
40864 * Fires when the dropdown list is expanded
40865 * @param {Roo.form.ComboBox} combo This combo box
40870 * Fires when the dropdown list is collapsed
40871 * @param {Roo.form.ComboBox} combo This combo box
40875 * @event beforeselect
40876 * Fires before a list item is selected. Return false to cancel the selection.
40877 * @param {Roo.form.ComboBox} combo This combo box
40878 * @param {Roo.data.Record} record The data record returned from the underlying store
40879 * @param {Number} index The index of the selected item in the dropdown list
40881 'beforeselect' : true,
40884 * Fires when a list item is selected
40885 * @param {Roo.form.ComboBox} combo This combo box
40886 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40887 * @param {Number} index The index of the selected item in the dropdown list
40891 * @event beforequery
40892 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40893 * The event object passed has these properties:
40894 * @param {Roo.form.ComboBox} combo This combo box
40895 * @param {String} query The query
40896 * @param {Boolean} forceAll true to force "all" query
40897 * @param {Boolean} cancel true to cancel the query
40898 * @param {Object} e The query event object
40900 'beforequery': true,
40903 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40904 * @param {Roo.form.ComboBox} combo This combo box
40909 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40910 * @param {Roo.form.ComboBox} combo This combo box
40911 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40917 if(this.transform){
40918 this.allowDomMove = false;
40919 var s = Roo.getDom(this.transform);
40920 if(!this.hiddenName){
40921 this.hiddenName = s.name;
40924 this.mode = 'local';
40925 var d = [], opts = s.options;
40926 for(var i = 0, len = opts.length;i < len; i++){
40928 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40930 this.value = value;
40932 d.push([value, o.text]);
40934 this.store = new Roo.data.SimpleStore({
40936 fields: ['value', 'text'],
40939 this.valueField = 'value';
40940 this.displayField = 'text';
40942 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40943 if(!this.lazyRender){
40944 this.target = true;
40945 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40946 s.parentNode.removeChild(s); // remove it
40947 this.render(this.el.parentNode);
40949 s.parentNode.removeChild(s); // remove it
40954 this.store = Roo.factory(this.store, Roo.data);
40957 this.selectedIndex = -1;
40958 if(this.mode == 'local'){
40959 if(config.queryDelay === undefined){
40960 this.queryDelay = 10;
40962 if(config.minChars === undefined){
40968 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40970 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40973 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40974 * rendering into an Roo.Editor, defaults to false)
40977 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40978 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40981 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40984 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40985 * the dropdown list (defaults to undefined, with no header element)
40989 * @cfg {String/Roo.Template} tpl The template to use to render the output
40993 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40995 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40997 listWidth: undefined,
40999 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41000 * mode = 'remote' or 'text' if mode = 'local')
41002 displayField: undefined,
41004 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41005 * mode = 'remote' or 'value' if mode = 'local').
41006 * Note: use of a valueField requires the user make a selection
41007 * in order for a value to be mapped.
41009 valueField: undefined,
41013 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41014 * field's data value (defaults to the underlying DOM element's name)
41016 hiddenName: undefined,
41018 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41022 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41024 selectedClass: 'x-combo-selected',
41026 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41027 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41028 * which displays a downward arrow icon).
41030 triggerClass : 'x-form-arrow-trigger',
41032 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41036 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41037 * anchor positions (defaults to 'tl-bl')
41039 listAlign: 'tl-bl?',
41041 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41045 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41046 * query specified by the allQuery config option (defaults to 'query')
41048 triggerAction: 'query',
41050 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41051 * (defaults to 4, does not apply if editable = false)
41055 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41056 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41060 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41061 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41065 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41066 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41070 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41071 * when editable = true (defaults to false)
41073 selectOnFocus:false,
41075 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41077 queryParam: 'query',
41079 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41080 * when mode = 'remote' (defaults to 'Loading...')
41082 loadingText: 'Loading...',
41084 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41088 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41092 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41093 * traditional select (defaults to true)
41097 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41101 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41105 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41106 * listWidth has a higher value)
41110 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41111 * allow the user to set arbitrary text into the field (defaults to false)
41113 forceSelection:false,
41115 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41116 * if typeAhead = true (defaults to 250)
41118 typeAheadDelay : 250,
41120 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41121 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41123 valueNotFoundText : undefined,
41125 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41127 blockFocus : false,
41130 * @cfg {Boolean} disableClear Disable showing of clear button.
41132 disableClear : false,
41134 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41136 alwaysQuery : false,
41142 // element that contains real text value.. (when hidden is used..)
41145 onRender : function(ct, position){
41146 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41147 if(this.hiddenName){
41148 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41150 this.hiddenField.value =
41151 this.hiddenValue !== undefined ? this.hiddenValue :
41152 this.value !== undefined ? this.value : '';
41154 // prevent input submission
41155 this.el.dom.removeAttribute('name');
41160 this.el.dom.setAttribute('autocomplete', 'off');
41163 var cls = 'x-combo-list';
41165 this.list = new Roo.Layer({
41166 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41169 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41170 this.list.setWidth(lw);
41171 this.list.swallowEvent('mousewheel');
41172 this.assetHeight = 0;
41175 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41176 this.assetHeight += this.header.getHeight();
41179 this.innerList = this.list.createChild({cls:cls+'-inner'});
41180 this.innerList.on('mouseover', this.onViewOver, this);
41181 this.innerList.on('mousemove', this.onViewMove, this);
41182 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41184 if(this.allowBlank && !this.pageSize && !this.disableClear){
41185 this.footer = this.list.createChild({cls:cls+'-ft'});
41186 this.pageTb = new Roo.Toolbar(this.footer);
41190 this.footer = this.list.createChild({cls:cls+'-ft'});
41191 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41192 {pageSize: this.pageSize});
41196 if (this.pageTb && this.allowBlank && !this.disableClear) {
41198 this.pageTb.add(new Roo.Toolbar.Fill(), {
41199 cls: 'x-btn-icon x-btn-clear',
41201 handler: function()
41204 _this.clearValue();
41205 _this.onSelect(false, -1);
41210 this.assetHeight += this.footer.getHeight();
41215 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41218 this.view = new Roo.View(this.innerList, this.tpl, {
41219 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41222 this.view.on('click', this.onViewClick, this);
41224 this.store.on('beforeload', this.onBeforeLoad, this);
41225 this.store.on('load', this.onLoad, this);
41226 this.store.on('loadexception', this.onLoadException, this);
41228 if(this.resizable){
41229 this.resizer = new Roo.Resizable(this.list, {
41230 pinned:true, handles:'se'
41232 this.resizer.on('resize', function(r, w, h){
41233 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41234 this.listWidth = w;
41235 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41236 this.restrictHeight();
41238 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41240 if(!this.editable){
41241 this.editable = true;
41242 this.setEditable(false);
41246 if (typeof(this.events.add.listeners) != 'undefined') {
41248 this.addicon = this.wrap.createChild(
41249 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41251 this.addicon.on('click', function(e) {
41252 this.fireEvent('add', this);
41255 if (typeof(this.events.edit.listeners) != 'undefined') {
41257 this.editicon = this.wrap.createChild(
41258 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41259 if (this.addicon) {
41260 this.editicon.setStyle('margin-left', '40px');
41262 this.editicon.on('click', function(e) {
41264 // we fire even if inothing is selected..
41265 this.fireEvent('edit', this, this.lastData );
41275 initEvents : function(){
41276 Roo.form.ComboBox.superclass.initEvents.call(this);
41278 this.keyNav = new Roo.KeyNav(this.el, {
41279 "up" : function(e){
41280 this.inKeyMode = true;
41284 "down" : function(e){
41285 if(!this.isExpanded()){
41286 this.onTriggerClick();
41288 this.inKeyMode = true;
41293 "enter" : function(e){
41294 this.onViewClick();
41298 "esc" : function(e){
41302 "tab" : function(e){
41303 this.onViewClick(false);
41304 this.fireEvent("specialkey", this, e);
41310 doRelay : function(foo, bar, hname){
41311 if(hname == 'down' || this.scope.isExpanded()){
41312 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41319 this.queryDelay = Math.max(this.queryDelay || 10,
41320 this.mode == 'local' ? 10 : 250);
41321 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41322 if(this.typeAhead){
41323 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41325 if(this.editable !== false){
41326 this.el.on("keyup", this.onKeyUp, this);
41328 if(this.forceSelection){
41329 this.on('blur', this.doForce, this);
41333 onDestroy : function(){
41335 this.view.setStore(null);
41336 this.view.el.removeAllListeners();
41337 this.view.el.remove();
41338 this.view.purgeListeners();
41341 this.list.destroy();
41344 this.store.un('beforeload', this.onBeforeLoad, this);
41345 this.store.un('load', this.onLoad, this);
41346 this.store.un('loadexception', this.onLoadException, this);
41348 Roo.form.ComboBox.superclass.onDestroy.call(this);
41352 fireKey : function(e){
41353 if(e.isNavKeyPress() && !this.list.isVisible()){
41354 this.fireEvent("specialkey", this, e);
41359 onResize: function(w, h){
41360 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41362 if(typeof w != 'number'){
41363 // we do not handle it!?!?
41366 var tw = this.trigger.getWidth();
41367 tw += this.addicon ? this.addicon.getWidth() : 0;
41368 tw += this.editicon ? this.editicon.getWidth() : 0;
41370 this.el.setWidth( this.adjustWidth('input', x));
41372 this.trigger.setStyle('left', x+'px');
41374 if(this.list && this.listWidth === undefined){
41375 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41376 this.list.setWidth(lw);
41377 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41385 * Allow or prevent the user from directly editing the field text. If false is passed,
41386 * the user will only be able to select from the items defined in the dropdown list. This method
41387 * is the runtime equivalent of setting the 'editable' config option at config time.
41388 * @param {Boolean} value True to allow the user to directly edit the field text
41390 setEditable : function(value){
41391 if(value == this.editable){
41394 this.editable = value;
41396 this.el.dom.setAttribute('readOnly', true);
41397 this.el.on('mousedown', this.onTriggerClick, this);
41398 this.el.addClass('x-combo-noedit');
41400 this.el.dom.setAttribute('readOnly', false);
41401 this.el.un('mousedown', this.onTriggerClick, this);
41402 this.el.removeClass('x-combo-noedit');
41407 onBeforeLoad : function(){
41408 if(!this.hasFocus){
41411 this.innerList.update(this.loadingText ?
41412 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41413 this.restrictHeight();
41414 this.selectedIndex = -1;
41418 onLoad : function(){
41419 if(!this.hasFocus){
41422 if(this.store.getCount() > 0){
41424 this.restrictHeight();
41425 if(this.lastQuery == this.allQuery){
41427 this.el.dom.select();
41429 if(!this.selectByValue(this.value, true)){
41430 this.select(0, true);
41434 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41435 this.taTask.delay(this.typeAheadDelay);
41439 this.onEmptyResults();
41444 onLoadException : function()
41447 Roo.log(this.store.reader.jsonData);
41448 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41449 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41455 onTypeAhead : function(){
41456 if(this.store.getCount() > 0){
41457 var r = this.store.getAt(0);
41458 var newValue = r.data[this.displayField];
41459 var len = newValue.length;
41460 var selStart = this.getRawValue().length;
41461 if(selStart != len){
41462 this.setRawValue(newValue);
41463 this.selectText(selStart, newValue.length);
41469 onSelect : function(record, index){
41470 if(this.fireEvent('beforeselect', this, record, index) !== false){
41471 this.setFromData(index > -1 ? record.data : false);
41473 this.fireEvent('select', this, record, index);
41478 * Returns the currently selected field value or empty string if no value is set.
41479 * @return {String} value The selected value
41481 getValue : function(){
41482 if(this.valueField){
41483 return typeof this.value != 'undefined' ? this.value : '';
41485 return Roo.form.ComboBox.superclass.getValue.call(this);
41489 * Clears any text/value currently set in the field
41491 clearValue : function(){
41492 if(this.hiddenField){
41493 this.hiddenField.value = '';
41496 this.setRawValue('');
41497 this.lastSelectionText = '';
41502 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41503 * will be displayed in the field. If the value does not match the data value of an existing item,
41504 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41505 * Otherwise the field will be blank (although the value will still be set).
41506 * @param {String} value The value to match
41508 setValue : function(v){
41510 if(this.valueField){
41511 var r = this.findRecord(this.valueField, v);
41513 text = r.data[this.displayField];
41514 }else if(this.valueNotFoundText !== undefined){
41515 text = this.valueNotFoundText;
41518 this.lastSelectionText = text;
41519 if(this.hiddenField){
41520 this.hiddenField.value = v;
41522 Roo.form.ComboBox.superclass.setValue.call(this, text);
41526 * @property {Object} the last set data for the element
41531 * Sets the value of the field based on a object which is related to the record format for the store.
41532 * @param {Object} value the value to set as. or false on reset?
41534 setFromData : function(o){
41535 var dv = ''; // display value
41536 var vv = ''; // value value..
41538 if (this.displayField) {
41539 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41541 // this is an error condition!!!
41542 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41545 if(this.valueField){
41546 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41548 if(this.hiddenField){
41549 this.hiddenField.value = vv;
41551 this.lastSelectionText = dv;
41552 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41556 // no hidden field.. - we store the value in 'value', but still display
41557 // display field!!!!
41558 this.lastSelectionText = dv;
41559 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41565 reset : function(){
41566 // overridden so that last data is reset..
41567 this.setValue(this.resetValue);
41568 this.clearInvalid();
41569 this.lastData = false;
41571 this.view.clearSelections();
41575 findRecord : function(prop, value){
41577 if(this.store.getCount() > 0){
41578 this.store.each(function(r){
41579 if(r.data[prop] == value){
41589 getName: function()
41591 // returns hidden if it's set..
41592 if (!this.rendered) {return ''};
41593 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41597 onViewMove : function(e, t){
41598 this.inKeyMode = false;
41602 onViewOver : function(e, t){
41603 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41606 var item = this.view.findItemFromChild(t);
41608 var index = this.view.indexOf(item);
41609 this.select(index, false);
41614 onViewClick : function(doFocus)
41616 var index = this.view.getSelectedIndexes()[0];
41617 var r = this.store.getAt(index);
41619 this.onSelect(r, index);
41621 if(doFocus !== false && !this.blockFocus){
41627 restrictHeight : function(){
41628 this.innerList.dom.style.height = '';
41629 var inner = this.innerList.dom;
41630 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41631 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41632 this.list.beginUpdate();
41633 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41634 this.list.alignTo(this.el, this.listAlign);
41635 this.list.endUpdate();
41639 onEmptyResults : function(){
41644 * Returns true if the dropdown list is expanded, else false.
41646 isExpanded : function(){
41647 return this.list.isVisible();
41651 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41652 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41653 * @param {String} value The data value of the item to select
41654 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41655 * selected item if it is not currently in view (defaults to true)
41656 * @return {Boolean} True if the value matched an item in the list, else false
41658 selectByValue : function(v, scrollIntoView){
41659 if(v !== undefined && v !== null){
41660 var r = this.findRecord(this.valueField || this.displayField, v);
41662 this.select(this.store.indexOf(r), scrollIntoView);
41670 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41671 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41672 * @param {Number} index The zero-based index of the list item to select
41673 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41674 * selected item if it is not currently in view (defaults to true)
41676 select : function(index, scrollIntoView){
41677 this.selectedIndex = index;
41678 this.view.select(index);
41679 if(scrollIntoView !== false){
41680 var el = this.view.getNode(index);
41682 this.innerList.scrollChildIntoView(el, false);
41688 selectNext : function(){
41689 var ct = this.store.getCount();
41691 if(this.selectedIndex == -1){
41693 }else if(this.selectedIndex < ct-1){
41694 this.select(this.selectedIndex+1);
41700 selectPrev : function(){
41701 var ct = this.store.getCount();
41703 if(this.selectedIndex == -1){
41705 }else if(this.selectedIndex != 0){
41706 this.select(this.selectedIndex-1);
41712 onKeyUp : function(e){
41713 if(this.editable !== false && !e.isSpecialKey()){
41714 this.lastKey = e.getKey();
41715 this.dqTask.delay(this.queryDelay);
41720 validateBlur : function(){
41721 return !this.list || !this.list.isVisible();
41725 initQuery : function(){
41726 this.doQuery(this.getRawValue());
41730 doForce : function(){
41731 if(this.el.dom.value.length > 0){
41732 this.el.dom.value =
41733 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41739 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41740 * query allowing the query action to be canceled if needed.
41741 * @param {String} query The SQL query to execute
41742 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41743 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41744 * saved in the current store (defaults to false)
41746 doQuery : function(q, forceAll){
41747 if(q === undefined || q === null){
41752 forceAll: forceAll,
41756 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41760 forceAll = qe.forceAll;
41761 if(forceAll === true || (q.length >= this.minChars)){
41762 if(this.lastQuery != q || this.alwaysQuery){
41763 this.lastQuery = q;
41764 if(this.mode == 'local'){
41765 this.selectedIndex = -1;
41767 this.store.clearFilter();
41769 this.store.filter(this.displayField, q);
41773 this.store.baseParams[this.queryParam] = q;
41775 params: this.getParams(q)
41780 this.selectedIndex = -1;
41787 getParams : function(q){
41789 //p[this.queryParam] = q;
41792 p.limit = this.pageSize;
41798 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41800 collapse : function(){
41801 if(!this.isExpanded()){
41805 Roo.get(document).un('mousedown', this.collapseIf, this);
41806 Roo.get(document).un('mousewheel', this.collapseIf, this);
41807 if (!this.editable) {
41808 Roo.get(document).un('keydown', this.listKeyPress, this);
41810 this.fireEvent('collapse', this);
41814 collapseIf : function(e){
41815 if(!e.within(this.wrap) && !e.within(this.list)){
41821 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41823 expand : function(){
41824 if(this.isExpanded() || !this.hasFocus){
41827 this.list.alignTo(this.el, this.listAlign);
41829 Roo.get(document).on('mousedown', this.collapseIf, this);
41830 Roo.get(document).on('mousewheel', this.collapseIf, this);
41831 if (!this.editable) {
41832 Roo.get(document).on('keydown', this.listKeyPress, this);
41835 this.fireEvent('expand', this);
41839 // Implements the default empty TriggerField.onTriggerClick function
41840 onTriggerClick : function(){
41844 if(this.isExpanded()){
41846 if (!this.blockFocus) {
41851 this.hasFocus = true;
41852 if(this.triggerAction == 'all') {
41853 this.doQuery(this.allQuery, true);
41855 this.doQuery(this.getRawValue());
41857 if (!this.blockFocus) {
41862 listKeyPress : function(e)
41864 //Roo.log('listkeypress');
41865 // scroll to first matching element based on key pres..
41866 if (e.isSpecialKey()) {
41869 var k = String.fromCharCode(e.getKey()).toUpperCase();
41872 var csel = this.view.getSelectedNodes();
41873 var cselitem = false;
41875 var ix = this.view.indexOf(csel[0]);
41876 cselitem = this.store.getAt(ix);
41877 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41883 this.store.each(function(v) {
41885 // start at existing selection.
41886 if (cselitem.id == v.id) {
41892 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41893 match = this.store.indexOf(v);
41898 if (match === false) {
41899 return true; // no more action?
41902 this.view.select(match);
41903 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41904 sn.scrollIntoView(sn.dom.parentNode, false);
41908 * @cfg {Boolean} grow
41912 * @cfg {Number} growMin
41916 * @cfg {Number} growMax
41924 * Copyright(c) 2010-2012, Roo J Solutions Limited
41931 * @class Roo.form.ComboBoxArray
41932 * @extends Roo.form.TextField
41933 * A facebook style adder... for lists of email / people / countries etc...
41934 * pick multiple items from a combo box, and shows each one.
41936 * Fred [x] Brian [x] [Pick another |v]
41939 * For this to work: it needs various extra information
41940 * - normal combo problay has
41942 * + displayField, valueField
41944 * For our purpose...
41947 * If we change from 'extends' to wrapping...
41954 * Create a new ComboBoxArray.
41955 * @param {Object} config Configuration options
41959 Roo.form.ComboBoxArray = function(config)
41963 * @event beforeremove
41964 * Fires before remove the value from the list
41965 * @param {Roo.form.ComboBoxArray} _self This combo box array
41966 * @param {Roo.form.ComboBoxArray.Item} item removed item
41968 'beforeremove' : true,
41971 * Fires when remove the value from the list
41972 * @param {Roo.form.ComboBoxArray} _self This combo box array
41973 * @param {Roo.form.ComboBoxArray.Item} item removed item
41980 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41982 this.items = new Roo.util.MixedCollection(false);
41984 // construct the child combo...
41994 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41997 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42002 // behavies liek a hiddne field
42003 inputType: 'hidden',
42005 * @cfg {Number} width The width of the box that displays the selected element
42012 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42016 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42018 hiddenName : false,
42021 // private the array of items that are displayed..
42023 // private - the hidden field el.
42025 // private - the filed el..
42028 //validateValue : function() { return true; }, // all values are ok!
42029 //onAddClick: function() { },
42031 onRender : function(ct, position)
42034 // create the standard hidden element
42035 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42038 // give fake names to child combo;
42039 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42040 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42042 this.combo = Roo.factory(this.combo, Roo.form);
42043 this.combo.onRender(ct, position);
42044 if (typeof(this.combo.width) != 'undefined') {
42045 this.combo.onResize(this.combo.width,0);
42048 this.combo.initEvents();
42050 // assigned so form know we need to do this..
42051 this.store = this.combo.store;
42052 this.valueField = this.combo.valueField;
42053 this.displayField = this.combo.displayField ;
42056 this.combo.wrap.addClass('x-cbarray-grp');
42058 var cbwrap = this.combo.wrap.createChild(
42059 {tag: 'div', cls: 'x-cbarray-cb'},
42064 this.hiddenEl = this.combo.wrap.createChild({
42065 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42067 this.el = this.combo.wrap.createChild({
42068 tag: 'input', type:'hidden' , name: this.name, value : ''
42070 // this.el.dom.removeAttribute("name");
42073 this.outerWrap = this.combo.wrap;
42074 this.wrap = cbwrap;
42076 this.outerWrap.setWidth(this.width);
42077 this.outerWrap.dom.removeChild(this.el.dom);
42079 this.wrap.dom.appendChild(this.el.dom);
42080 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42081 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42083 this.combo.trigger.setStyle('position','relative');
42084 this.combo.trigger.setStyle('left', '0px');
42085 this.combo.trigger.setStyle('top', '2px');
42087 this.combo.el.setStyle('vertical-align', 'text-bottom');
42089 //this.trigger.setStyle('vertical-align', 'top');
42091 // this should use the code from combo really... on('add' ....)
42095 this.adder = this.outerWrap.createChild(
42096 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42098 this.adder.on('click', function(e) {
42099 _t.fireEvent('adderclick', this, e);
42103 //this.adder.on('click', this.onAddClick, _t);
42106 this.combo.on('select', function(cb, rec, ix) {
42107 this.addItem(rec.data);
42110 cb.el.dom.value = '';
42111 //cb.lastData = rec.data;
42120 getName: function()
42122 // returns hidden if it's set..
42123 if (!this.rendered) {return ''};
42124 return this.hiddenName ? this.hiddenName : this.name;
42129 onResize: function(w, h){
42132 // not sure if this is needed..
42133 //this.combo.onResize(w,h);
42135 if(typeof w != 'number'){
42136 // we do not handle it!?!?
42139 var tw = this.combo.trigger.getWidth();
42140 tw += this.addicon ? this.addicon.getWidth() : 0;
42141 tw += this.editicon ? this.editicon.getWidth() : 0;
42143 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42145 this.combo.trigger.setStyle('left', '0px');
42147 if(this.list && this.listWidth === undefined){
42148 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42149 this.list.setWidth(lw);
42150 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42157 addItem: function(rec)
42159 var valueField = this.combo.valueField;
42160 var displayField = this.combo.displayField;
42161 if (this.items.indexOfKey(rec[valueField]) > -1) {
42162 //console.log("GOT " + rec.data.id);
42166 var x = new Roo.form.ComboBoxArray.Item({
42167 //id : rec[this.idField],
42169 displayField : displayField ,
42170 tipField : displayField ,
42174 this.items.add(rec[valueField],x);
42175 // add it before the element..
42176 this.updateHiddenEl();
42177 x.render(this.outerWrap, this.wrap.dom);
42178 // add the image handler..
42181 updateHiddenEl : function()
42184 if (!this.hiddenEl) {
42188 var idField = this.combo.valueField;
42190 this.items.each(function(f) {
42191 ar.push(f.data[idField]);
42194 this.hiddenEl.dom.value = ar.join(',');
42200 this.items.clear();
42202 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42206 this.el.dom.value = '';
42207 if (this.hiddenEl) {
42208 this.hiddenEl.dom.value = '';
42212 getValue: function()
42214 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42216 setValue: function(v) // not a valid action - must use addItems..
42223 if (this.store.isLocal && (typeof(v) == 'string')) {
42224 // then we can use the store to find the values..
42225 // comma seperated at present.. this needs to allow JSON based encoding..
42226 this.hiddenEl.value = v;
42228 Roo.each(v.split(','), function(k) {
42229 Roo.log("CHECK " + this.valueField + ',' + k);
42230 var li = this.store.query(this.valueField, k);
42235 add[this.valueField] = k;
42236 add[this.displayField] = li.item(0).data[this.displayField];
42242 if (typeof(v) == 'object' ) {
42243 // then let's assume it's an array of objects..
42244 Roo.each(v, function(l) {
42252 setFromData: function(v)
42254 // this recieves an object, if setValues is called.
42256 this.el.dom.value = v[this.displayField];
42257 this.hiddenEl.dom.value = v[this.valueField];
42258 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42261 var kv = v[this.valueField];
42262 var dv = v[this.displayField];
42263 kv = typeof(kv) != 'string' ? '' : kv;
42264 dv = typeof(dv) != 'string' ? '' : dv;
42267 var keys = kv.split(',');
42268 var display = dv.split(',');
42269 for (var i = 0 ; i < keys.length; i++) {
42272 add[this.valueField] = keys[i];
42273 add[this.displayField] = display[i];
42281 * Validates the combox array value
42282 * @return {Boolean} True if the value is valid, else false
42284 validate : function(){
42285 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42286 this.clearInvalid();
42292 validateValue : function(value){
42293 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42301 isDirty : function() {
42302 if(this.disabled) {
42307 var d = Roo.decode(String(this.originalValue));
42309 return String(this.getValue()) !== String(this.originalValue);
42312 var originalValue = [];
42314 for (var i = 0; i < d.length; i++){
42315 originalValue.push(d[i][this.valueField]);
42318 return String(this.getValue()) !== String(originalValue.join(','));
42327 * @class Roo.form.ComboBoxArray.Item
42328 * @extends Roo.BoxComponent
42329 * A selected item in the list
42330 * Fred [x] Brian [x] [Pick another |v]
42333 * Create a new item.
42334 * @param {Object} config Configuration options
42337 Roo.form.ComboBoxArray.Item = function(config) {
42338 config.id = Roo.id();
42339 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42342 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42345 displayField : false,
42349 defaultAutoCreate : {
42351 cls: 'x-cbarray-item',
42358 src : Roo.BLANK_IMAGE_URL ,
42366 onRender : function(ct, position)
42368 Roo.form.Field.superclass.onRender.call(this, ct, position);
42371 var cfg = this.getAutoCreate();
42372 this.el = ct.createChild(cfg, position);
42375 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42377 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42378 this.cb.renderer(this.data) :
42379 String.format('{0}',this.data[this.displayField]);
42382 this.el.child('div').dom.setAttribute('qtip',
42383 String.format('{0}',this.data[this.tipField])
42386 this.el.child('img').on('click', this.remove, this);
42390 remove : function()
42392 if(this.cb.disabled){
42396 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42397 this.cb.items.remove(this);
42398 this.el.child('img').un('click', this.remove, this);
42400 this.cb.updateHiddenEl();
42402 this.cb.fireEvent('remove', this.cb, this);
42408 * Ext JS Library 1.1.1
42409 * Copyright(c) 2006-2007, Ext JS, LLC.
42411 * Originally Released Under LGPL - original licence link has changed is not relivant.
42414 * <script type="text/javascript">
42417 * @class Roo.form.Checkbox
42418 * @extends Roo.form.Field
42419 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42421 * Creates a new Checkbox
42422 * @param {Object} config Configuration options
42424 Roo.form.Checkbox = function(config){
42425 Roo.form.Checkbox.superclass.constructor.call(this, config);
42429 * Fires when the checkbox is checked or unchecked.
42430 * @param {Roo.form.Checkbox} this This checkbox
42431 * @param {Boolean} checked The new checked value
42437 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42439 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42441 focusClass : undefined,
42443 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42445 fieldClass: "x-form-field",
42447 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42451 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42452 * {tag: "input", type: "checkbox", autocomplete: "off"})
42454 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42456 * @cfg {String} boxLabel The text that appears beside the checkbox
42460 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42464 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42466 valueOff: '0', // value when not checked..
42468 actionMode : 'viewEl',
42471 itemCls : 'x-menu-check-item x-form-item',
42472 groupClass : 'x-menu-group-item',
42473 inputType : 'hidden',
42476 inSetChecked: false, // check that we are not calling self...
42478 inputElement: false, // real input element?
42479 basedOn: false, // ????
42481 isFormField: true, // not sure where this is needed!!!!
42483 onResize : function(){
42484 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42485 if(!this.boxLabel){
42486 this.el.alignTo(this.wrap, 'c-c');
42490 initEvents : function(){
42491 Roo.form.Checkbox.superclass.initEvents.call(this);
42492 this.el.on("click", this.onClick, this);
42493 this.el.on("change", this.onClick, this);
42497 getResizeEl : function(){
42501 getPositionEl : function(){
42506 onRender : function(ct, position){
42507 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42509 if(this.inputValue !== undefined){
42510 this.el.dom.value = this.inputValue;
42513 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42514 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42515 var viewEl = this.wrap.createChild({
42516 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42517 this.viewEl = viewEl;
42518 this.wrap.on('click', this.onClick, this);
42520 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42521 this.el.on('propertychange', this.setFromHidden, this); //ie
42526 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42527 // viewEl.on('click', this.onClick, this);
42529 //if(this.checked){
42530 this.setChecked(this.checked);
42532 //this.checked = this.el.dom;
42538 initValue : Roo.emptyFn,
42541 * Returns the checked state of the checkbox.
42542 * @return {Boolean} True if checked, else false
42544 getValue : function(){
42546 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42548 return this.valueOff;
42553 onClick : function(){
42554 if (this.disabled) {
42557 this.setChecked(!this.checked);
42559 //if(this.el.dom.checked != this.checked){
42560 // this.setValue(this.el.dom.checked);
42565 * Sets the checked state of the checkbox.
42566 * On is always based on a string comparison between inputValue and the param.
42567 * @param {Boolean/String} value - the value to set
42568 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42570 setValue : function(v,suppressEvent){
42573 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42574 //if(this.el && this.el.dom){
42575 // this.el.dom.checked = this.checked;
42576 // this.el.dom.defaultChecked = this.checked;
42578 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42579 //this.fireEvent("check", this, this.checked);
42582 setChecked : function(state,suppressEvent)
42584 if (this.inSetChecked) {
42585 this.checked = state;
42591 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42593 this.checked = state;
42594 if(suppressEvent !== true){
42595 this.fireEvent('check', this, state);
42597 this.inSetChecked = true;
42598 this.el.dom.value = state ? this.inputValue : this.valueOff;
42599 this.inSetChecked = false;
42602 // handle setting of hidden value by some other method!!?!?
42603 setFromHidden: function()
42608 //console.log("SET FROM HIDDEN");
42609 //alert('setFrom hidden');
42610 this.setValue(this.el.dom.value);
42613 onDestroy : function()
42616 Roo.get(this.viewEl).remove();
42619 Roo.form.Checkbox.superclass.onDestroy.call(this);
42622 setBoxLabel : function(str)
42624 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42629 * Ext JS Library 1.1.1
42630 * Copyright(c) 2006-2007, Ext JS, LLC.
42632 * Originally Released Under LGPL - original licence link has changed is not relivant.
42635 * <script type="text/javascript">
42639 * @class Roo.form.Radio
42640 * @extends Roo.form.Checkbox
42641 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42642 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42644 * Creates a new Radio
42645 * @param {Object} config Configuration options
42647 Roo.form.Radio = function(){
42648 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42650 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42651 inputType: 'radio',
42654 * If this radio is part of a group, it will return the selected value
42657 getGroupValue : function(){
42658 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42662 onRender : function(ct, position){
42663 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42665 if(this.inputValue !== undefined){
42666 this.el.dom.value = this.inputValue;
42669 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42670 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42671 //var viewEl = this.wrap.createChild({
42672 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42673 //this.viewEl = viewEl;
42674 //this.wrap.on('click', this.onClick, this);
42676 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42677 //this.el.on('propertychange', this.setFromHidden, this); //ie
42682 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42683 // viewEl.on('click', this.onClick, this);
42686 this.el.dom.checked = 'checked' ;
42692 });//<script type="text/javascript">
42695 * Based Ext JS Library 1.1.1
42696 * Copyright(c) 2006-2007, Ext JS, LLC.
42702 * @class Roo.HtmlEditorCore
42703 * @extends Roo.Component
42704 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42706 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42709 Roo.HtmlEditorCore = function(config){
42712 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42717 * @event initialize
42718 * Fires when the editor is fully initialized (including the iframe)
42719 * @param {Roo.HtmlEditorCore} this
42724 * Fires when the editor is first receives the focus. Any insertion must wait
42725 * until after this event.
42726 * @param {Roo.HtmlEditorCore} this
42730 * @event beforesync
42731 * Fires before the textarea is updated with content from the editor iframe. Return false
42732 * to cancel the sync.
42733 * @param {Roo.HtmlEditorCore} this
42734 * @param {String} html
42738 * @event beforepush
42739 * Fires before the iframe editor is updated with content from the textarea. Return false
42740 * to cancel the push.
42741 * @param {Roo.HtmlEditorCore} this
42742 * @param {String} html
42747 * Fires when the textarea is updated with content from the editor iframe.
42748 * @param {Roo.HtmlEditorCore} this
42749 * @param {String} html
42754 * Fires when the iframe editor is updated with content from the textarea.
42755 * @param {Roo.HtmlEditorCore} this
42756 * @param {String} html
42761 * @event editorevent
42762 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42763 * @param {Roo.HtmlEditorCore} this
42769 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42771 // defaults : white / black...
42772 this.applyBlacklists();
42779 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42783 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42789 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42794 * @cfg {Number} height (in pixels)
42798 * @cfg {Number} width (in pixels)
42803 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42806 stylesheets: false,
42811 // private properties
42812 validationEvent : false,
42814 initialized : false,
42816 sourceEditMode : false,
42817 onFocus : Roo.emptyFn,
42819 hideMode:'offsets',
42823 // blacklist + whitelisted elements..
42830 * Protected method that will not generally be called directly. It
42831 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42832 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42834 getDocMarkup : function(){
42838 // inherit styels from page...??
42839 if (this.stylesheets === false) {
42841 Roo.get(document.head).select('style').each(function(node) {
42842 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42845 Roo.get(document.head).select('link').each(function(node) {
42846 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42849 } else if (!this.stylesheets.length) {
42851 st = '<style type="text/css">' +
42852 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42858 st += '<style type="text/css">' +
42859 'IMG { cursor: pointer } ' +
42863 return '<html><head>' + st +
42864 //<style type="text/css">' +
42865 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42867 ' </head><body class="roo-htmleditor-body"></body></html>';
42871 onRender : function(ct, position)
42874 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42875 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42878 this.el.dom.style.border = '0 none';
42879 this.el.dom.setAttribute('tabIndex', -1);
42880 this.el.addClass('x-hidden hide');
42884 if(Roo.isIE){ // fix IE 1px bogus margin
42885 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42889 this.frameId = Roo.id();
42893 var iframe = this.owner.wrap.createChild({
42895 cls: 'form-control', // bootstrap..
42897 name: this.frameId,
42898 frameBorder : 'no',
42899 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42904 this.iframe = iframe.dom;
42906 this.assignDocWin();
42908 this.doc.designMode = 'on';
42911 this.doc.write(this.getDocMarkup());
42915 var task = { // must defer to wait for browser to be ready
42917 //console.log("run task?" + this.doc.readyState);
42918 this.assignDocWin();
42919 if(this.doc.body || this.doc.readyState == 'complete'){
42921 this.doc.designMode="on";
42925 Roo.TaskMgr.stop(task);
42926 this.initEditor.defer(10, this);
42933 Roo.TaskMgr.start(task);
42938 onResize : function(w, h)
42940 Roo.log('resize: ' +w + ',' + h );
42941 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42945 if(typeof w == 'number'){
42947 this.iframe.style.width = w + 'px';
42949 if(typeof h == 'number'){
42951 this.iframe.style.height = h + 'px';
42953 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42960 * Toggles the editor between standard and source edit mode.
42961 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42963 toggleSourceEdit : function(sourceEditMode){
42965 this.sourceEditMode = sourceEditMode === true;
42967 if(this.sourceEditMode){
42969 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42972 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42973 //this.iframe.className = '';
42976 //this.setSize(this.owner.wrap.getSize());
42977 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42984 * Protected method that will not generally be called directly. If you need/want
42985 * custom HTML cleanup, this is the method you should override.
42986 * @param {String} html The HTML to be cleaned
42987 * return {String} The cleaned HTML
42989 cleanHtml : function(html){
42990 html = String(html);
42991 if(html.length > 5){
42992 if(Roo.isSafari){ // strip safari nonsense
42993 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42996 if(html == ' '){
43003 * HTML Editor -> Textarea
43004 * Protected method that will not generally be called directly. Syncs the contents
43005 * of the editor iframe with the textarea.
43007 syncValue : function(){
43008 if(this.initialized){
43009 var bd = (this.doc.body || this.doc.documentElement);
43010 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43011 var html = bd.innerHTML;
43013 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43014 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43016 html = '<div style="'+m[0]+'">' + html + '</div>';
43019 html = this.cleanHtml(html);
43020 // fix up the special chars.. normaly like back quotes in word...
43021 // however we do not want to do this with chinese..
43022 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43023 var cc = b.charCodeAt();
43025 (cc >= 0x4E00 && cc < 0xA000 ) ||
43026 (cc >= 0x3400 && cc < 0x4E00 ) ||
43027 (cc >= 0xf900 && cc < 0xfb00 )
43033 if(this.owner.fireEvent('beforesync', this, html) !== false){
43034 this.el.dom.value = html;
43035 this.owner.fireEvent('sync', this, html);
43041 * Protected method that will not generally be called directly. Pushes the value of the textarea
43042 * into the iframe editor.
43044 pushValue : function(){
43045 if(this.initialized){
43046 var v = this.el.dom.value.trim();
43048 // if(v.length < 1){
43052 if(this.owner.fireEvent('beforepush', this, v) !== false){
43053 var d = (this.doc.body || this.doc.documentElement);
43055 this.cleanUpPaste();
43056 this.el.dom.value = d.innerHTML;
43057 this.owner.fireEvent('push', this, v);
43063 deferFocus : function(){
43064 this.focus.defer(10, this);
43068 focus : function(){
43069 if(this.win && !this.sourceEditMode){
43076 assignDocWin: function()
43078 var iframe = this.iframe;
43081 this.doc = iframe.contentWindow.document;
43082 this.win = iframe.contentWindow;
43084 // if (!Roo.get(this.frameId)) {
43087 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43088 // this.win = Roo.get(this.frameId).dom.contentWindow;
43090 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43094 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43095 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43100 initEditor : function(){
43101 //console.log("INIT EDITOR");
43102 this.assignDocWin();
43106 this.doc.designMode="on";
43108 this.doc.write(this.getDocMarkup());
43111 var dbody = (this.doc.body || this.doc.documentElement);
43112 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43113 // this copies styles from the containing element into thsi one..
43114 // not sure why we need all of this..
43115 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43117 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43118 //ss['background-attachment'] = 'fixed'; // w3c
43119 dbody.bgProperties = 'fixed'; // ie
43120 //Roo.DomHelper.applyStyles(dbody, ss);
43121 Roo.EventManager.on(this.doc, {
43122 //'mousedown': this.onEditorEvent,
43123 'mouseup': this.onEditorEvent,
43124 'dblclick': this.onEditorEvent,
43125 'click': this.onEditorEvent,
43126 'keyup': this.onEditorEvent,
43131 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43133 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43134 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43136 this.initialized = true;
43138 this.owner.fireEvent('initialize', this);
43143 onDestroy : function(){
43149 //for (var i =0; i < this.toolbars.length;i++) {
43150 // // fixme - ask toolbars for heights?
43151 // this.toolbars[i].onDestroy();
43154 //this.wrap.dom.innerHTML = '';
43155 //this.wrap.remove();
43160 onFirstFocus : function(){
43162 this.assignDocWin();
43165 this.activated = true;
43168 if(Roo.isGecko){ // prevent silly gecko errors
43170 var s = this.win.getSelection();
43171 if(!s.focusNode || s.focusNode.nodeType != 3){
43172 var r = s.getRangeAt(0);
43173 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43178 this.execCmd('useCSS', true);
43179 this.execCmd('styleWithCSS', false);
43182 this.owner.fireEvent('activate', this);
43186 adjustFont: function(btn){
43187 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43188 //if(Roo.isSafari){ // safari
43191 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43192 if(Roo.isSafari){ // safari
43193 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43194 v = (v < 10) ? 10 : v;
43195 v = (v > 48) ? 48 : v;
43196 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43201 v = Math.max(1, v+adjust);
43203 this.execCmd('FontSize', v );
43206 onEditorEvent : function(e)
43208 this.owner.fireEvent('editorevent', this, e);
43209 // this.updateToolbar();
43210 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43213 insertTag : function(tg)
43215 // could be a bit smarter... -> wrap the current selected tRoo..
43216 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43218 range = this.createRange(this.getSelection());
43219 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43220 wrappingNode.appendChild(range.extractContents());
43221 range.insertNode(wrappingNode);
43228 this.execCmd("formatblock", tg);
43232 insertText : function(txt)
43236 var range = this.createRange();
43237 range.deleteContents();
43238 //alert(Sender.getAttribute('label'));
43240 range.insertNode(this.doc.createTextNode(txt));
43246 * Executes a Midas editor command on the editor document and performs necessary focus and
43247 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43248 * @param {String} cmd The Midas command
43249 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43251 relayCmd : function(cmd, value){
43253 this.execCmd(cmd, value);
43254 this.owner.fireEvent('editorevent', this);
43255 //this.updateToolbar();
43256 this.owner.deferFocus();
43260 * Executes a Midas editor command directly on the editor document.
43261 * For visual commands, you should use {@link #relayCmd} instead.
43262 * <b>This should only be called after the editor is initialized.</b>
43263 * @param {String} cmd The Midas command
43264 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43266 execCmd : function(cmd, value){
43267 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43274 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43276 * @param {String} text | dom node..
43278 insertAtCursor : function(text)
43281 if(!this.activated){
43287 var r = this.doc.selection.createRange();
43298 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43302 // from jquery ui (MIT licenced)
43304 var win = this.win;
43306 if (win.getSelection && win.getSelection().getRangeAt) {
43307 range = win.getSelection().getRangeAt(0);
43308 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43309 range.insertNode(node);
43310 } else if (win.document.selection && win.document.selection.createRange) {
43311 // no firefox support
43312 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43313 win.document.selection.createRange().pasteHTML(txt);
43315 // no firefox support
43316 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43317 this.execCmd('InsertHTML', txt);
43326 mozKeyPress : function(e){
43328 var c = e.getCharCode(), cmd;
43331 c = String.fromCharCode(c).toLowerCase();
43345 this.cleanUpPaste.defer(100, this);
43353 e.preventDefault();
43361 fixKeys : function(){ // load time branching for fastest keydown performance
43363 return function(e){
43364 var k = e.getKey(), r;
43367 r = this.doc.selection.createRange();
43370 r.pasteHTML('    ');
43377 r = this.doc.selection.createRange();
43379 var target = r.parentElement();
43380 if(!target || target.tagName.toLowerCase() != 'li'){
43382 r.pasteHTML('<br />');
43388 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43389 this.cleanUpPaste.defer(100, this);
43395 }else if(Roo.isOpera){
43396 return function(e){
43397 var k = e.getKey();
43401 this.execCmd('InsertHTML','    ');
43404 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43405 this.cleanUpPaste.defer(100, this);
43410 }else if(Roo.isSafari){
43411 return function(e){
43412 var k = e.getKey();
43416 this.execCmd('InsertText','\t');
43420 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43421 this.cleanUpPaste.defer(100, this);
43429 getAllAncestors: function()
43431 var p = this.getSelectedNode();
43434 a.push(p); // push blank onto stack..
43435 p = this.getParentElement();
43439 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43443 a.push(this.doc.body);
43447 lastSelNode : false,
43450 getSelection : function()
43452 this.assignDocWin();
43453 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43456 getSelectedNode: function()
43458 // this may only work on Gecko!!!
43460 // should we cache this!!!!
43465 var range = this.createRange(this.getSelection()).cloneRange();
43468 var parent = range.parentElement();
43470 var testRange = range.duplicate();
43471 testRange.moveToElementText(parent);
43472 if (testRange.inRange(range)) {
43475 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43478 parent = parent.parentElement;
43483 // is ancestor a text element.
43484 var ac = range.commonAncestorContainer;
43485 if (ac.nodeType == 3) {
43486 ac = ac.parentNode;
43489 var ar = ac.childNodes;
43492 var other_nodes = [];
43493 var has_other_nodes = false;
43494 for (var i=0;i<ar.length;i++) {
43495 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43498 // fullly contained node.
43500 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43505 // probably selected..
43506 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43507 other_nodes.push(ar[i]);
43511 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43516 has_other_nodes = true;
43518 if (!nodes.length && other_nodes.length) {
43519 nodes= other_nodes;
43521 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43527 createRange: function(sel)
43529 // this has strange effects when using with
43530 // top toolbar - not sure if it's a great idea.
43531 //this.editor.contentWindow.focus();
43532 if (typeof sel != "undefined") {
43534 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43536 return this.doc.createRange();
43539 return this.doc.createRange();
43542 getParentElement: function()
43545 this.assignDocWin();
43546 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43548 var range = this.createRange(sel);
43551 var p = range.commonAncestorContainer;
43552 while (p.nodeType == 3) { // text node
43563 * Range intersection.. the hard stuff...
43567 * [ -- selected range --- ]
43571 * if end is before start or hits it. fail.
43572 * if start is after end or hits it fail.
43574 * if either hits (but other is outside. - then it's not
43580 // @see http://www.thismuchiknow.co.uk/?p=64.
43581 rangeIntersectsNode : function(range, node)
43583 var nodeRange = node.ownerDocument.createRange();
43585 nodeRange.selectNode(node);
43587 nodeRange.selectNodeContents(node);
43590 var rangeStartRange = range.cloneRange();
43591 rangeStartRange.collapse(true);
43593 var rangeEndRange = range.cloneRange();
43594 rangeEndRange.collapse(false);
43596 var nodeStartRange = nodeRange.cloneRange();
43597 nodeStartRange.collapse(true);
43599 var nodeEndRange = nodeRange.cloneRange();
43600 nodeEndRange.collapse(false);
43602 return rangeStartRange.compareBoundaryPoints(
43603 Range.START_TO_START, nodeEndRange) == -1 &&
43604 rangeEndRange.compareBoundaryPoints(
43605 Range.START_TO_START, nodeStartRange) == 1;
43609 rangeCompareNode : function(range, node)
43611 var nodeRange = node.ownerDocument.createRange();
43613 nodeRange.selectNode(node);
43615 nodeRange.selectNodeContents(node);
43619 range.collapse(true);
43621 nodeRange.collapse(true);
43623 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43624 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43626 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43628 var nodeIsBefore = ss == 1;
43629 var nodeIsAfter = ee == -1;
43631 if (nodeIsBefore && nodeIsAfter) {
43634 if (!nodeIsBefore && nodeIsAfter) {
43635 return 1; //right trailed.
43638 if (nodeIsBefore && !nodeIsAfter) {
43639 return 2; // left trailed.
43645 // private? - in a new class?
43646 cleanUpPaste : function()
43648 // cleans up the whole document..
43649 Roo.log('cleanuppaste');
43651 this.cleanUpChildren(this.doc.body);
43652 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43653 if (clean != this.doc.body.innerHTML) {
43654 this.doc.body.innerHTML = clean;
43659 cleanWordChars : function(input) {// change the chars to hex code
43660 var he = Roo.HtmlEditorCore;
43662 var output = input;
43663 Roo.each(he.swapCodes, function(sw) {
43664 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43666 output = output.replace(swapper, sw[1]);
43673 cleanUpChildren : function (n)
43675 if (!n.childNodes.length) {
43678 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43679 this.cleanUpChild(n.childNodes[i]);
43686 cleanUpChild : function (node)
43689 //console.log(node);
43690 if (node.nodeName == "#text") {
43691 // clean up silly Windows -- stuff?
43694 if (node.nodeName == "#comment") {
43695 node.parentNode.removeChild(node);
43696 // clean up silly Windows -- stuff?
43699 var lcname = node.tagName.toLowerCase();
43700 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43701 // whitelist of tags..
43703 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43705 node.parentNode.removeChild(node);
43710 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43712 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43713 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43715 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43716 // remove_keep_children = true;
43719 if (remove_keep_children) {
43720 this.cleanUpChildren(node);
43721 // inserts everything just before this node...
43722 while (node.childNodes.length) {
43723 var cn = node.childNodes[0];
43724 node.removeChild(cn);
43725 node.parentNode.insertBefore(cn, node);
43727 node.parentNode.removeChild(node);
43731 if (!node.attributes || !node.attributes.length) {
43732 this.cleanUpChildren(node);
43736 function cleanAttr(n,v)
43739 if (v.match(/^\./) || v.match(/^\//)) {
43742 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43745 if (v.match(/^#/)) {
43748 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43749 node.removeAttribute(n);
43753 var cwhite = this.cwhite;
43754 var cblack = this.cblack;
43756 function cleanStyle(n,v)
43758 if (v.match(/expression/)) { //XSS?? should we even bother..
43759 node.removeAttribute(n);
43763 var parts = v.split(/;/);
43766 Roo.each(parts, function(p) {
43767 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43771 var l = p.split(':').shift().replace(/\s+/g,'');
43772 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43774 if ( cwhite.length && cblack.indexOf(l) > -1) {
43775 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43776 //node.removeAttribute(n);
43780 // only allow 'c whitelisted system attributes'
43781 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43782 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43783 //node.removeAttribute(n);
43793 if (clean.length) {
43794 node.setAttribute(n, clean.join(';'));
43796 node.removeAttribute(n);
43802 for (var i = node.attributes.length-1; i > -1 ; i--) {
43803 var a = node.attributes[i];
43806 if (a.name.toLowerCase().substr(0,2)=='on') {
43807 node.removeAttribute(a.name);
43810 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43811 node.removeAttribute(a.name);
43814 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43815 cleanAttr(a.name,a.value); // fixme..
43818 if (a.name == 'style') {
43819 cleanStyle(a.name,a.value);
43822 /// clean up MS crap..
43823 // tecnically this should be a list of valid class'es..
43826 if (a.name == 'class') {
43827 if (a.value.match(/^Mso/)) {
43828 node.className = '';
43831 if (a.value.match(/^body$/)) {
43832 node.className = '';
43843 this.cleanUpChildren(node);
43849 * Clean up MS wordisms...
43851 cleanWord : function(node)
43856 this.cleanWord(this.doc.body);
43859 if (node.nodeName == "#text") {
43860 // clean up silly Windows -- stuff?
43863 if (node.nodeName == "#comment") {
43864 node.parentNode.removeChild(node);
43865 // clean up silly Windows -- stuff?
43869 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43870 node.parentNode.removeChild(node);
43874 // remove - but keep children..
43875 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43876 while (node.childNodes.length) {
43877 var cn = node.childNodes[0];
43878 node.removeChild(cn);
43879 node.parentNode.insertBefore(cn, node);
43881 node.parentNode.removeChild(node);
43882 this.iterateChildren(node, this.cleanWord);
43886 if (node.className.length) {
43888 var cn = node.className.split(/\W+/);
43890 Roo.each(cn, function(cls) {
43891 if (cls.match(/Mso[a-zA-Z]+/)) {
43896 node.className = cna.length ? cna.join(' ') : '';
43898 node.removeAttribute("class");
43902 if (node.hasAttribute("lang")) {
43903 node.removeAttribute("lang");
43906 if (node.hasAttribute("style")) {
43908 var styles = node.getAttribute("style").split(";");
43910 Roo.each(styles, function(s) {
43911 if (!s.match(/:/)) {
43914 var kv = s.split(":");
43915 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43918 // what ever is left... we allow.
43921 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43922 if (!nstyle.length) {
43923 node.removeAttribute('style');
43926 this.iterateChildren(node, this.cleanWord);
43932 * iterateChildren of a Node, calling fn each time, using this as the scole..
43933 * @param {DomNode} node node to iterate children of.
43934 * @param {Function} fn method of this class to call on each item.
43936 iterateChildren : function(node, fn)
43938 if (!node.childNodes.length) {
43941 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43942 fn.call(this, node.childNodes[i])
43948 * cleanTableWidths.
43950 * Quite often pasting from word etc.. results in tables with column and widths.
43951 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43954 cleanTableWidths : function(node)
43959 this.cleanTableWidths(this.doc.body);
43964 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43967 Roo.log(node.tagName);
43968 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43969 this.iterateChildren(node, this.cleanTableWidths);
43972 if (node.hasAttribute('width')) {
43973 node.removeAttribute('width');
43977 if (node.hasAttribute("style")) {
43980 var styles = node.getAttribute("style").split(";");
43982 Roo.each(styles, function(s) {
43983 if (!s.match(/:/)) {
43986 var kv = s.split(":");
43987 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43990 // what ever is left... we allow.
43993 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43994 if (!nstyle.length) {
43995 node.removeAttribute('style');
43999 this.iterateChildren(node, this.cleanTableWidths);
44007 domToHTML : function(currentElement, depth, nopadtext) {
44009 depth = depth || 0;
44010 nopadtext = nopadtext || false;
44012 if (!currentElement) {
44013 return this.domToHTML(this.doc.body);
44016 //Roo.log(currentElement);
44018 var allText = false;
44019 var nodeName = currentElement.nodeName;
44020 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44022 if (nodeName == '#text') {
44024 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44029 if (nodeName != 'BODY') {
44032 // Prints the node tagName, such as <A>, <IMG>, etc
44035 for(i = 0; i < currentElement.attributes.length;i++) {
44037 var aname = currentElement.attributes.item(i).name;
44038 if (!currentElement.attributes.item(i).value.length) {
44041 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44044 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44053 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44056 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44061 // Traverse the tree
44063 var currentElementChild = currentElement.childNodes.item(i);
44064 var allText = true;
44065 var innerHTML = '';
44067 while (currentElementChild) {
44068 // Formatting code (indent the tree so it looks nice on the screen)
44069 var nopad = nopadtext;
44070 if (lastnode == 'SPAN') {
44074 if (currentElementChild.nodeName == '#text') {
44075 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44076 toadd = nopadtext ? toadd : toadd.trim();
44077 if (!nopad && toadd.length > 80) {
44078 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44080 innerHTML += toadd;
44083 currentElementChild = currentElement.childNodes.item(i);
44089 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44091 // Recursively traverse the tree structure of the child node
44092 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44093 lastnode = currentElementChild.nodeName;
44095 currentElementChild=currentElement.childNodes.item(i);
44101 // The remaining code is mostly for formatting the tree
44102 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44107 ret+= "</"+tagName+">";
44113 applyBlacklists : function()
44115 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44116 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44120 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44121 if (b.indexOf(tag) > -1) {
44124 this.white.push(tag);
44128 Roo.each(w, function(tag) {
44129 if (b.indexOf(tag) > -1) {
44132 if (this.white.indexOf(tag) > -1) {
44135 this.white.push(tag);
44140 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44141 if (w.indexOf(tag) > -1) {
44144 this.black.push(tag);
44148 Roo.each(b, function(tag) {
44149 if (w.indexOf(tag) > -1) {
44152 if (this.black.indexOf(tag) > -1) {
44155 this.black.push(tag);
44160 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44161 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44165 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44166 if (b.indexOf(tag) > -1) {
44169 this.cwhite.push(tag);
44173 Roo.each(w, function(tag) {
44174 if (b.indexOf(tag) > -1) {
44177 if (this.cwhite.indexOf(tag) > -1) {
44180 this.cwhite.push(tag);
44185 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44186 if (w.indexOf(tag) > -1) {
44189 this.cblack.push(tag);
44193 Roo.each(b, function(tag) {
44194 if (w.indexOf(tag) > -1) {
44197 if (this.cblack.indexOf(tag) > -1) {
44200 this.cblack.push(tag);
44205 setStylesheets : function(stylesheets)
44207 if(typeof(stylesheets) == 'string'){
44208 Roo.get(this.iframe.contentDocument.head).createChild({
44210 rel : 'stylesheet',
44219 Roo.each(stylesheets, function(s) {
44224 Roo.get(_this.iframe.contentDocument.head).createChild({
44226 rel : 'stylesheet',
44235 removeStylesheets : function()
44239 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44244 // hide stuff that is not compatible
44258 * @event specialkey
44262 * @cfg {String} fieldClass @hide
44265 * @cfg {String} focusClass @hide
44268 * @cfg {String} autoCreate @hide
44271 * @cfg {String} inputType @hide
44274 * @cfg {String} invalidClass @hide
44277 * @cfg {String} invalidText @hide
44280 * @cfg {String} msgFx @hide
44283 * @cfg {String} validateOnBlur @hide
44287 Roo.HtmlEditorCore.white = [
44288 'area', 'br', 'img', 'input', 'hr', 'wbr',
44290 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44291 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44292 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44293 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44294 'table', 'ul', 'xmp',
44296 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44299 'dir', 'menu', 'ol', 'ul', 'dl',
44305 Roo.HtmlEditorCore.black = [
44306 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44308 'base', 'basefont', 'bgsound', 'blink', 'body',
44309 'frame', 'frameset', 'head', 'html', 'ilayer',
44310 'iframe', 'layer', 'link', 'meta', 'object',
44311 'script', 'style' ,'title', 'xml' // clean later..
44313 Roo.HtmlEditorCore.clean = [
44314 'script', 'style', 'title', 'xml'
44316 Roo.HtmlEditorCore.remove = [
44321 Roo.HtmlEditorCore.ablack = [
44325 Roo.HtmlEditorCore.aclean = [
44326 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44330 Roo.HtmlEditorCore.pwhite= [
44331 'http', 'https', 'mailto'
44334 // white listed style attributes.
44335 Roo.HtmlEditorCore.cwhite= [
44336 // 'text-align', /// default is to allow most things..
44342 // black listed style attributes.
44343 Roo.HtmlEditorCore.cblack= [
44344 // 'font-size' -- this can be set by the project
44348 Roo.HtmlEditorCore.swapCodes =[
44359 //<script type="text/javascript">
44362 * Ext JS Library 1.1.1
44363 * Copyright(c) 2006-2007, Ext JS, LLC.
44369 Roo.form.HtmlEditor = function(config){
44373 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44375 if (!this.toolbars) {
44376 this.toolbars = [];
44378 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44384 * @class Roo.form.HtmlEditor
44385 * @extends Roo.form.Field
44386 * Provides a lightweight HTML Editor component.
44388 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44390 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44391 * supported by this editor.</b><br/><br/>
44392 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44393 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44395 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44397 * @cfg {Boolean} clearUp
44401 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44406 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44411 * @cfg {Number} height (in pixels)
44415 * @cfg {Number} width (in pixels)
44420 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44423 stylesheets: false,
44427 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44432 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44438 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44443 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44451 // private properties
44452 validationEvent : false,
44454 initialized : false,
44457 onFocus : Roo.emptyFn,
44459 hideMode:'offsets',
44461 actionMode : 'container', // defaults to hiding it...
44463 defaultAutoCreate : { // modified by initCompnoent..
44465 style:"width:500px;height:300px;",
44466 autocomplete: "new-password"
44470 initComponent : function(){
44473 * @event initialize
44474 * Fires when the editor is fully initialized (including the iframe)
44475 * @param {HtmlEditor} this
44480 * Fires when the editor is first receives the focus. Any insertion must wait
44481 * until after this event.
44482 * @param {HtmlEditor} this
44486 * @event beforesync
44487 * Fires before the textarea is updated with content from the editor iframe. Return false
44488 * to cancel the sync.
44489 * @param {HtmlEditor} this
44490 * @param {String} html
44494 * @event beforepush
44495 * Fires before the iframe editor is updated with content from the textarea. Return false
44496 * to cancel the push.
44497 * @param {HtmlEditor} this
44498 * @param {String} html
44503 * Fires when the textarea is updated with content from the editor iframe.
44504 * @param {HtmlEditor} this
44505 * @param {String} html
44510 * Fires when the iframe editor is updated with content from the textarea.
44511 * @param {HtmlEditor} this
44512 * @param {String} html
44516 * @event editmodechange
44517 * Fires when the editor switches edit modes
44518 * @param {HtmlEditor} this
44519 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44521 editmodechange: true,
44523 * @event editorevent
44524 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44525 * @param {HtmlEditor} this
44529 * @event firstfocus
44530 * Fires when on first focus - needed by toolbars..
44531 * @param {HtmlEditor} this
44536 * Auto save the htmlEditor value as a file into Events
44537 * @param {HtmlEditor} this
44541 * @event savedpreview
44542 * preview the saved version of htmlEditor
44543 * @param {HtmlEditor} this
44545 savedpreview: true,
44548 * @event stylesheetsclick
44549 * Fires when press the Sytlesheets button
44550 * @param {Roo.HtmlEditorCore} this
44552 stylesheetsclick: true
44554 this.defaultAutoCreate = {
44556 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44557 autocomplete: "new-password"
44562 * Protected method that will not generally be called directly. It
44563 * is called when the editor creates its toolbar. Override this method if you need to
44564 * add custom toolbar buttons.
44565 * @param {HtmlEditor} editor
44567 createToolbar : function(editor){
44568 Roo.log("create toolbars");
44569 if (!editor.toolbars || !editor.toolbars.length) {
44570 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44573 for (var i =0 ; i < editor.toolbars.length;i++) {
44574 editor.toolbars[i] = Roo.factory(
44575 typeof(editor.toolbars[i]) == 'string' ?
44576 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44577 Roo.form.HtmlEditor);
44578 editor.toolbars[i].init(editor);
44586 onRender : function(ct, position)
44589 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44591 this.wrap = this.el.wrap({
44592 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44595 this.editorcore.onRender(ct, position);
44597 if (this.resizable) {
44598 this.resizeEl = new Roo.Resizable(this.wrap, {
44602 minHeight : this.height,
44603 height: this.height,
44604 handles : this.resizable,
44607 resize : function(r, w, h) {
44608 _t.onResize(w,h); // -something
44614 this.createToolbar(this);
44618 this.setSize(this.wrap.getSize());
44620 if (this.resizeEl) {
44621 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44622 // should trigger onReize..
44625 this.keyNav = new Roo.KeyNav(this.el, {
44627 "tab" : function(e){
44628 e.preventDefault();
44630 var value = this.getValue();
44632 var start = this.el.dom.selectionStart;
44633 var end = this.el.dom.selectionEnd;
44637 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44638 this.el.dom.setSelectionRange(end + 1, end + 1);
44642 var f = value.substring(0, start).split("\t");
44644 if(f.pop().length != 0){
44648 this.setValue(f.join("\t") + value.substring(end));
44649 this.el.dom.setSelectionRange(start - 1, start - 1);
44653 "home" : function(e){
44654 e.preventDefault();
44656 var curr = this.el.dom.selectionStart;
44657 var lines = this.getValue().split("\n");
44664 this.el.dom.setSelectionRange(0, 0);
44670 for (var i = 0; i < lines.length;i++) {
44671 pos += lines[i].length;
44681 pos -= lines[i].length;
44687 this.el.dom.setSelectionRange(pos, pos);
44691 this.el.dom.selectionStart = pos;
44692 this.el.dom.selectionEnd = curr;
44695 "end" : function(e){
44696 e.preventDefault();
44698 var curr = this.el.dom.selectionStart;
44699 var lines = this.getValue().split("\n");
44706 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44712 for (var i = 0; i < lines.length;i++) {
44714 pos += lines[i].length;
44728 this.el.dom.setSelectionRange(pos, pos);
44732 this.el.dom.selectionStart = curr;
44733 this.el.dom.selectionEnd = pos;
44738 doRelay : function(foo, bar, hname){
44739 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44745 // if(this.autosave && this.w){
44746 // this.autoSaveFn = setInterval(this.autosave, 1000);
44751 onResize : function(w, h)
44753 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44758 if(typeof w == 'number'){
44759 var aw = w - this.wrap.getFrameWidth('lr');
44760 this.el.setWidth(this.adjustWidth('textarea', aw));
44763 if(typeof h == 'number'){
44765 for (var i =0; i < this.toolbars.length;i++) {
44766 // fixme - ask toolbars for heights?
44767 tbh += this.toolbars[i].tb.el.getHeight();
44768 if (this.toolbars[i].footer) {
44769 tbh += this.toolbars[i].footer.el.getHeight();
44776 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44777 ah -= 5; // knock a few pixes off for look..
44779 this.el.setHeight(this.adjustWidth('textarea', ah));
44783 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44784 this.editorcore.onResize(ew,eh);
44789 * Toggles the editor between standard and source edit mode.
44790 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44792 toggleSourceEdit : function(sourceEditMode)
44794 this.editorcore.toggleSourceEdit(sourceEditMode);
44796 if(this.editorcore.sourceEditMode){
44797 Roo.log('editor - showing textarea');
44800 // Roo.log(this.syncValue());
44801 this.editorcore.syncValue();
44802 this.el.removeClass('x-hidden');
44803 this.el.dom.removeAttribute('tabIndex');
44806 for (var i = 0; i < this.toolbars.length; i++) {
44807 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44808 this.toolbars[i].tb.hide();
44809 this.toolbars[i].footer.hide();
44814 Roo.log('editor - hiding textarea');
44816 // Roo.log(this.pushValue());
44817 this.editorcore.pushValue();
44819 this.el.addClass('x-hidden');
44820 this.el.dom.setAttribute('tabIndex', -1);
44822 for (var i = 0; i < this.toolbars.length; i++) {
44823 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44824 this.toolbars[i].tb.show();
44825 this.toolbars[i].footer.show();
44829 //this.deferFocus();
44832 this.setSize(this.wrap.getSize());
44833 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44835 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44838 // private (for BoxComponent)
44839 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44841 // private (for BoxComponent)
44842 getResizeEl : function(){
44846 // private (for BoxComponent)
44847 getPositionEl : function(){
44852 initEvents : function(){
44853 this.originalValue = this.getValue();
44857 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44860 markInvalid : Roo.emptyFn,
44862 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44865 clearInvalid : Roo.emptyFn,
44867 setValue : function(v){
44868 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44869 this.editorcore.pushValue();
44874 deferFocus : function(){
44875 this.focus.defer(10, this);
44879 focus : function(){
44880 this.editorcore.focus();
44886 onDestroy : function(){
44892 for (var i =0; i < this.toolbars.length;i++) {
44893 // fixme - ask toolbars for heights?
44894 this.toolbars[i].onDestroy();
44897 this.wrap.dom.innerHTML = '';
44898 this.wrap.remove();
44903 onFirstFocus : function(){
44904 //Roo.log("onFirstFocus");
44905 this.editorcore.onFirstFocus();
44906 for (var i =0; i < this.toolbars.length;i++) {
44907 this.toolbars[i].onFirstFocus();
44913 syncValue : function()
44915 this.editorcore.syncValue();
44918 pushValue : function()
44920 this.editorcore.pushValue();
44923 setStylesheets : function(stylesheets)
44925 this.editorcore.setStylesheets(stylesheets);
44928 removeStylesheets : function()
44930 this.editorcore.removeStylesheets();
44934 // hide stuff that is not compatible
44948 * @event specialkey
44952 * @cfg {String} fieldClass @hide
44955 * @cfg {String} focusClass @hide
44958 * @cfg {String} autoCreate @hide
44961 * @cfg {String} inputType @hide
44964 * @cfg {String} invalidClass @hide
44967 * @cfg {String} invalidText @hide
44970 * @cfg {String} msgFx @hide
44973 * @cfg {String} validateOnBlur @hide
44977 // <script type="text/javascript">
44980 * Ext JS Library 1.1.1
44981 * Copyright(c) 2006-2007, Ext JS, LLC.
44987 * @class Roo.form.HtmlEditorToolbar1
44992 new Roo.form.HtmlEditor({
44995 new Roo.form.HtmlEditorToolbar1({
44996 disable : { fonts: 1 , format: 1, ..., ... , ...],
45002 * @cfg {Object} disable List of elements to disable..
45003 * @cfg {Array} btns List of additional buttons.
45007 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45010 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45013 Roo.apply(this, config);
45015 // default disabled, based on 'good practice'..
45016 this.disable = this.disable || {};
45017 Roo.applyIf(this.disable, {
45020 specialElements : true
45024 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45025 // dont call parent... till later.
45028 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45035 editorcore : false,
45037 * @cfg {Object} disable List of toolbar elements to disable
45044 * @cfg {String} createLinkText The default text for the create link prompt
45046 createLinkText : 'Please enter the URL for the link:',
45048 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45050 defaultLinkValue : 'http:/'+'/',
45054 * @cfg {Array} fontFamilies An array of available font families
45072 // "á" , ?? a acute?
45077 "°" // , // degrees
45079 // "é" , // e ecute
45080 // "ú" , // u ecute?
45083 specialElements : [
45085 text: "Insert Table",
45088 ihtml : '<table><tr><td>Cell</td></tr></table>'
45092 text: "Insert Image",
45095 ihtml : '<img src="about:blank"/>'
45104 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45105 "input:submit", "input:button", "select", "textarea", "label" ],
45108 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45110 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45118 * @cfg {String} defaultFont default font to use.
45120 defaultFont: 'tahoma',
45122 fontSelect : false,
45125 formatCombo : false,
45127 init : function(editor)
45129 this.editor = editor;
45130 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45131 var editorcore = this.editorcore;
45135 var fid = editorcore.frameId;
45137 function btn(id, toggle, handler){
45138 var xid = fid + '-'+ id ;
45142 cls : 'x-btn-icon x-edit-'+id,
45143 enableToggle:toggle !== false,
45144 scope: _t, // was editor...
45145 handler:handler||_t.relayBtnCmd,
45146 clickEvent:'mousedown',
45147 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45154 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45156 // stop form submits
45157 tb.el.on('click', function(e){
45158 e.preventDefault(); // what does this do?
45161 if(!this.disable.font) { // && !Roo.isSafari){
45162 /* why no safari for fonts
45163 editor.fontSelect = tb.el.createChild({
45166 cls:'x-font-select',
45167 html: this.createFontOptions()
45170 editor.fontSelect.on('change', function(){
45171 var font = editor.fontSelect.dom.value;
45172 editor.relayCmd('fontname', font);
45173 editor.deferFocus();
45177 editor.fontSelect.dom,
45183 if(!this.disable.formats){
45184 this.formatCombo = new Roo.form.ComboBox({
45185 store: new Roo.data.SimpleStore({
45188 data : this.formats // from states.js
45192 //autoCreate : {tag: "div", size: "20"},
45193 displayField:'tag',
45197 triggerAction: 'all',
45198 emptyText:'Add tag',
45199 selectOnFocus:true,
45202 'select': function(c, r, i) {
45203 editorcore.insertTag(r.get('tag'));
45209 tb.addField(this.formatCombo);
45213 if(!this.disable.format){
45218 btn('strikethrough')
45221 if(!this.disable.fontSize){
45226 btn('increasefontsize', false, editorcore.adjustFont),
45227 btn('decreasefontsize', false, editorcore.adjustFont)
45232 if(!this.disable.colors){
45235 id:editorcore.frameId +'-forecolor',
45236 cls:'x-btn-icon x-edit-forecolor',
45237 clickEvent:'mousedown',
45238 tooltip: this.buttonTips['forecolor'] || undefined,
45240 menu : new Roo.menu.ColorMenu({
45241 allowReselect: true,
45242 focus: Roo.emptyFn,
45245 selectHandler: function(cp, color){
45246 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45247 editor.deferFocus();
45250 clickEvent:'mousedown'
45253 id:editorcore.frameId +'backcolor',
45254 cls:'x-btn-icon x-edit-backcolor',
45255 clickEvent:'mousedown',
45256 tooltip: this.buttonTips['backcolor'] || undefined,
45258 menu : new Roo.menu.ColorMenu({
45259 focus: Roo.emptyFn,
45262 allowReselect: true,
45263 selectHandler: function(cp, color){
45265 editorcore.execCmd('useCSS', false);
45266 editorcore.execCmd('hilitecolor', color);
45267 editorcore.execCmd('useCSS', true);
45268 editor.deferFocus();
45270 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45271 Roo.isSafari || Roo.isIE ? '#'+color : color);
45272 editor.deferFocus();
45276 clickEvent:'mousedown'
45281 // now add all the items...
45284 if(!this.disable.alignments){
45287 btn('justifyleft'),
45288 btn('justifycenter'),
45289 btn('justifyright')
45293 //if(!Roo.isSafari){
45294 if(!this.disable.links){
45297 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45301 if(!this.disable.lists){
45304 btn('insertorderedlist'),
45305 btn('insertunorderedlist')
45308 if(!this.disable.sourceEdit){
45311 btn('sourceedit', true, function(btn){
45312 this.toggleSourceEdit(btn.pressed);
45319 // special menu.. - needs to be tidied up..
45320 if (!this.disable.special) {
45323 cls: 'x-edit-none',
45329 for (var i =0; i < this.specialChars.length; i++) {
45330 smenu.menu.items.push({
45332 html: this.specialChars[i],
45333 handler: function(a,b) {
45334 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45335 //editor.insertAtCursor(a.html);
45349 if (!this.disable.cleanStyles) {
45351 cls: 'x-btn-icon x-btn-clear',
45357 for (var i =0; i < this.cleanStyles.length; i++) {
45358 cmenu.menu.items.push({
45359 actiontype : this.cleanStyles[i],
45360 html: 'Remove ' + this.cleanStyles[i],
45361 handler: function(a,b) {
45364 var c = Roo.get(editorcore.doc.body);
45365 c.select('[style]').each(function(s) {
45366 s.dom.style.removeProperty(a.actiontype);
45368 editorcore.syncValue();
45373 cmenu.menu.items.push({
45374 actiontype : 'tablewidths',
45375 html: 'Remove Table Widths',
45376 handler: function(a,b) {
45377 editorcore.cleanTableWidths();
45378 editorcore.syncValue();
45382 cmenu.menu.items.push({
45383 actiontype : 'word',
45384 html: 'Remove MS Word Formating',
45385 handler: function(a,b) {
45386 editorcore.cleanWord();
45387 editorcore.syncValue();
45392 cmenu.menu.items.push({
45393 actiontype : 'all',
45394 html: 'Remove All Styles',
45395 handler: function(a,b) {
45397 var c = Roo.get(editorcore.doc.body);
45398 c.select('[style]').each(function(s) {
45399 s.dom.removeAttribute('style');
45401 editorcore.syncValue();
45406 cmenu.menu.items.push({
45407 actiontype : 'all',
45408 html: 'Remove All CSS Classes',
45409 handler: function(a,b) {
45411 var c = Roo.get(editorcore.doc.body);
45412 c.select('[class]').each(function(s) {
45413 s.dom.className = '';
45415 editorcore.syncValue();
45420 cmenu.menu.items.push({
45421 actiontype : 'tidy',
45422 html: 'Tidy HTML Source',
45423 handler: function(a,b) {
45424 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45425 editorcore.syncValue();
45434 if (!this.disable.specialElements) {
45437 cls: 'x-edit-none',
45442 for (var i =0; i < this.specialElements.length; i++) {
45443 semenu.menu.items.push(
45445 handler: function(a,b) {
45446 editor.insertAtCursor(this.ihtml);
45448 }, this.specialElements[i])
45460 for(var i =0; i< this.btns.length;i++) {
45461 var b = Roo.factory(this.btns[i],Roo.form);
45462 b.cls = 'x-edit-none';
45464 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45465 b.cls += ' x-init-enable';
45468 b.scope = editorcore;
45476 // disable everything...
45478 this.tb.items.each(function(item){
45481 item.id != editorcore.frameId+ '-sourceedit' &&
45482 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45488 this.rendered = true;
45490 // the all the btns;
45491 editor.on('editorevent', this.updateToolbar, this);
45492 // other toolbars need to implement this..
45493 //editor.on('editmodechange', this.updateToolbar, this);
45497 relayBtnCmd : function(btn) {
45498 this.editorcore.relayCmd(btn.cmd);
45500 // private used internally
45501 createLink : function(){
45502 Roo.log("create link?");
45503 var url = prompt(this.createLinkText, this.defaultLinkValue);
45504 if(url && url != 'http:/'+'/'){
45505 this.editorcore.relayCmd('createlink', url);
45511 * Protected method that will not generally be called directly. It triggers
45512 * a toolbar update by reading the markup state of the current selection in the editor.
45514 updateToolbar: function(){
45516 if(!this.editorcore.activated){
45517 this.editor.onFirstFocus();
45521 var btns = this.tb.items.map,
45522 doc = this.editorcore.doc,
45523 frameId = this.editorcore.frameId;
45525 if(!this.disable.font && !Roo.isSafari){
45527 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45528 if(name != this.fontSelect.dom.value){
45529 this.fontSelect.dom.value = name;
45533 if(!this.disable.format){
45534 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45535 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45536 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45537 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45539 if(!this.disable.alignments){
45540 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45541 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45542 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45544 if(!Roo.isSafari && !this.disable.lists){
45545 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45546 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45549 var ans = this.editorcore.getAllAncestors();
45550 if (this.formatCombo) {
45553 var store = this.formatCombo.store;
45554 this.formatCombo.setValue("");
45555 for (var i =0; i < ans.length;i++) {
45556 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45558 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45566 // hides menus... - so this cant be on a menu...
45567 Roo.menu.MenuMgr.hideAll();
45569 //this.editorsyncValue();
45573 createFontOptions : function(){
45574 var buf = [], fs = this.fontFamilies, ff, lc;
45578 for(var i = 0, len = fs.length; i< len; i++){
45580 lc = ff.toLowerCase();
45582 '<option value="',lc,'" style="font-family:',ff,';"',
45583 (this.defaultFont == lc ? ' selected="true">' : '>'),
45588 return buf.join('');
45591 toggleSourceEdit : function(sourceEditMode){
45593 Roo.log("toolbar toogle");
45594 if(sourceEditMode === undefined){
45595 sourceEditMode = !this.sourceEditMode;
45597 this.sourceEditMode = sourceEditMode === true;
45598 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45599 // just toggle the button?
45600 if(btn.pressed !== this.sourceEditMode){
45601 btn.toggle(this.sourceEditMode);
45605 if(sourceEditMode){
45606 Roo.log("disabling buttons");
45607 this.tb.items.each(function(item){
45608 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45614 Roo.log("enabling buttons");
45615 if(this.editorcore.initialized){
45616 this.tb.items.each(function(item){
45622 Roo.log("calling toggole on editor");
45623 // tell the editor that it's been pressed..
45624 this.editor.toggleSourceEdit(sourceEditMode);
45628 * Object collection of toolbar tooltips for the buttons in the editor. The key
45629 * is the command id associated with that button and the value is a valid QuickTips object.
45634 title: 'Bold (Ctrl+B)',
45635 text: 'Make the selected text bold.',
45636 cls: 'x-html-editor-tip'
45639 title: 'Italic (Ctrl+I)',
45640 text: 'Make the selected text italic.',
45641 cls: 'x-html-editor-tip'
45649 title: 'Bold (Ctrl+B)',
45650 text: 'Make the selected text bold.',
45651 cls: 'x-html-editor-tip'
45654 title: 'Italic (Ctrl+I)',
45655 text: 'Make the selected text italic.',
45656 cls: 'x-html-editor-tip'
45659 title: 'Underline (Ctrl+U)',
45660 text: 'Underline the selected text.',
45661 cls: 'x-html-editor-tip'
45664 title: 'Strikethrough',
45665 text: 'Strikethrough the selected text.',
45666 cls: 'x-html-editor-tip'
45668 increasefontsize : {
45669 title: 'Grow Text',
45670 text: 'Increase the font size.',
45671 cls: 'x-html-editor-tip'
45673 decreasefontsize : {
45674 title: 'Shrink Text',
45675 text: 'Decrease the font size.',
45676 cls: 'x-html-editor-tip'
45679 title: 'Text Highlight Color',
45680 text: 'Change the background color of the selected text.',
45681 cls: 'x-html-editor-tip'
45684 title: 'Font Color',
45685 text: 'Change the color of the selected text.',
45686 cls: 'x-html-editor-tip'
45689 title: 'Align Text Left',
45690 text: 'Align text to the left.',
45691 cls: 'x-html-editor-tip'
45694 title: 'Center Text',
45695 text: 'Center text in the editor.',
45696 cls: 'x-html-editor-tip'
45699 title: 'Align Text Right',
45700 text: 'Align text to the right.',
45701 cls: 'x-html-editor-tip'
45703 insertunorderedlist : {
45704 title: 'Bullet List',
45705 text: 'Start a bulleted list.',
45706 cls: 'x-html-editor-tip'
45708 insertorderedlist : {
45709 title: 'Numbered List',
45710 text: 'Start a numbered list.',
45711 cls: 'x-html-editor-tip'
45714 title: 'Hyperlink',
45715 text: 'Make the selected text a hyperlink.',
45716 cls: 'x-html-editor-tip'
45719 title: 'Source Edit',
45720 text: 'Switch to source editing mode.',
45721 cls: 'x-html-editor-tip'
45725 onDestroy : function(){
45728 this.tb.items.each(function(item){
45730 item.menu.removeAll();
45732 item.menu.el.destroy();
45740 onFirstFocus: function() {
45741 this.tb.items.each(function(item){
45750 // <script type="text/javascript">
45753 * Ext JS Library 1.1.1
45754 * Copyright(c) 2006-2007, Ext JS, LLC.
45761 * @class Roo.form.HtmlEditor.ToolbarContext
45766 new Roo.form.HtmlEditor({
45769 { xtype: 'ToolbarStandard', styles : {} }
45770 { xtype: 'ToolbarContext', disable : {} }
45776 * @config : {Object} disable List of elements to disable.. (not done yet.)
45777 * @config : {Object} styles Map of styles available.
45781 Roo.form.HtmlEditor.ToolbarContext = function(config)
45784 Roo.apply(this, config);
45785 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45786 // dont call parent... till later.
45787 this.styles = this.styles || {};
45792 Roo.form.HtmlEditor.ToolbarContext.types = {
45804 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45870 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45875 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45885 style : 'fontFamily',
45886 displayField: 'display',
45887 optname : 'font-family',
45936 // should we really allow this??
45937 // should this just be
45948 style : 'fontFamily',
45949 displayField: 'display',
45950 optname : 'font-family',
45957 style : 'fontFamily',
45958 displayField: 'display',
45959 optname : 'font-family',
45966 style : 'fontFamily',
45967 displayField: 'display',
45968 optname : 'font-family',
45979 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45980 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45982 Roo.form.HtmlEditor.ToolbarContext.options = {
45984 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45985 [ 'Courier New', 'Courier New'],
45986 [ 'Tahoma', 'Tahoma'],
45987 [ 'Times New Roman,serif', 'Times'],
45988 [ 'Verdana','Verdana' ]
45992 // fixme - these need to be configurable..
45995 //Roo.form.HtmlEditor.ToolbarContext.types
45998 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46005 editorcore : false,
46007 * @cfg {Object} disable List of toolbar elements to disable
46012 * @cfg {Object} styles List of styles
46013 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46015 * These must be defined in the page, so they get rendered correctly..
46026 init : function(editor)
46028 this.editor = editor;
46029 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46030 var editorcore = this.editorcore;
46032 var fid = editorcore.frameId;
46034 function btn(id, toggle, handler){
46035 var xid = fid + '-'+ id ;
46039 cls : 'x-btn-icon x-edit-'+id,
46040 enableToggle:toggle !== false,
46041 scope: editorcore, // was editor...
46042 handler:handler||editorcore.relayBtnCmd,
46043 clickEvent:'mousedown',
46044 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46048 // create a new element.
46049 var wdiv = editor.wrap.createChild({
46051 }, editor.wrap.dom.firstChild.nextSibling, true);
46053 // can we do this more than once??
46055 // stop form submits
46058 // disable everything...
46059 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46060 this.toolbars = {};
46062 for (var i in ty) {
46064 this.toolbars[i] = this.buildToolbar(ty[i],i);
46066 this.tb = this.toolbars.BODY;
46068 this.buildFooter();
46069 this.footer.show();
46070 editor.on('hide', function( ) { this.footer.hide() }, this);
46071 editor.on('show', function( ) { this.footer.show() }, this);
46074 this.rendered = true;
46076 // the all the btns;
46077 editor.on('editorevent', this.updateToolbar, this);
46078 // other toolbars need to implement this..
46079 //editor.on('editmodechange', this.updateToolbar, this);
46085 * Protected method that will not generally be called directly. It triggers
46086 * a toolbar update by reading the markup state of the current selection in the editor.
46088 * Note you can force an update by calling on('editorevent', scope, false)
46090 updateToolbar: function(editor,ev,sel){
46093 // capture mouse up - this is handy for selecting images..
46094 // perhaps should go somewhere else...
46095 if(!this.editorcore.activated){
46096 this.editor.onFirstFocus();
46102 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46103 // selectNode - might want to handle IE?
46105 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46106 ev.target && ev.target.tagName == 'IMG') {
46107 // they have click on an image...
46108 // let's see if we can change the selection...
46111 var nodeRange = sel.ownerDocument.createRange();
46113 nodeRange.selectNode(sel);
46115 nodeRange.selectNodeContents(sel);
46117 //nodeRange.collapse(true);
46118 var s = this.editorcore.win.getSelection();
46119 s.removeAllRanges();
46120 s.addRange(nodeRange);
46124 var updateFooter = sel ? false : true;
46127 var ans = this.editorcore.getAllAncestors();
46130 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46133 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46134 sel = sel ? sel : this.editorcore.doc.body;
46135 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46138 // pick a menu that exists..
46139 var tn = sel.tagName.toUpperCase();
46140 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46142 tn = sel.tagName.toUpperCase();
46144 var lastSel = this.tb.selectedNode;
46146 this.tb.selectedNode = sel;
46148 // if current menu does not match..
46150 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46153 ///console.log("show: " + tn);
46154 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46157 this.tb.items.first().el.innerHTML = tn + ': ';
46160 // update attributes
46161 if (this.tb.fields) {
46162 this.tb.fields.each(function(e) {
46164 e.setValue(sel.style[e.stylename]);
46167 e.setValue(sel.getAttribute(e.attrname));
46171 var hasStyles = false;
46172 for(var i in this.styles) {
46179 var st = this.tb.fields.item(0);
46181 st.store.removeAll();
46184 var cn = sel.className.split(/\s+/);
46187 if (this.styles['*']) {
46189 Roo.each(this.styles['*'], function(v) {
46190 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46193 if (this.styles[tn]) {
46194 Roo.each(this.styles[tn], function(v) {
46195 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46199 st.store.loadData(avs);
46203 // flag our selected Node.
46204 this.tb.selectedNode = sel;
46207 Roo.menu.MenuMgr.hideAll();
46211 if (!updateFooter) {
46212 //this.footDisp.dom.innerHTML = '';
46215 // update the footer
46219 this.footerEls = ans.reverse();
46220 Roo.each(this.footerEls, function(a,i) {
46221 if (!a) { return; }
46222 html += html.length ? ' > ' : '';
46224 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46229 var sz = this.footDisp.up('td').getSize();
46230 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46231 this.footDisp.dom.style.marginLeft = '5px';
46233 this.footDisp.dom.style.overflow = 'hidden';
46235 this.footDisp.dom.innerHTML = html;
46237 //this.editorsyncValue();
46244 onDestroy : function(){
46247 this.tb.items.each(function(item){
46249 item.menu.removeAll();
46251 item.menu.el.destroy();
46259 onFirstFocus: function() {
46260 // need to do this for all the toolbars..
46261 this.tb.items.each(function(item){
46265 buildToolbar: function(tlist, nm)
46267 var editor = this.editor;
46268 var editorcore = this.editorcore;
46269 // create a new element.
46270 var wdiv = editor.wrap.createChild({
46272 }, editor.wrap.dom.firstChild.nextSibling, true);
46275 var tb = new Roo.Toolbar(wdiv);
46278 tb.add(nm+ ": ");
46281 for(var i in this.styles) {
46286 if (styles && styles.length) {
46288 // this needs a multi-select checkbox...
46289 tb.addField( new Roo.form.ComboBox({
46290 store: new Roo.data.SimpleStore({
46292 fields: ['val', 'selected'],
46295 name : '-roo-edit-className',
46296 attrname : 'className',
46297 displayField: 'val',
46301 triggerAction: 'all',
46302 emptyText:'Select Style',
46303 selectOnFocus:true,
46306 'select': function(c, r, i) {
46307 // initial support only for on class per el..
46308 tb.selectedNode.className = r ? r.get('val') : '';
46309 editorcore.syncValue();
46316 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46317 var tbops = tbc.options;
46319 for (var i in tlist) {
46321 var item = tlist[i];
46322 tb.add(item.title + ": ");
46325 //optname == used so you can configure the options available..
46326 var opts = item.opts ? item.opts : false;
46327 if (item.optname) {
46328 opts = tbops[item.optname];
46333 // opts == pulldown..
46334 tb.addField( new Roo.form.ComboBox({
46335 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46337 fields: ['val', 'display'],
46340 name : '-roo-edit-' + i,
46342 stylename : item.style ? item.style : false,
46343 displayField: item.displayField ? item.displayField : 'val',
46344 valueField : 'val',
46346 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46348 triggerAction: 'all',
46349 emptyText:'Select',
46350 selectOnFocus:true,
46351 width: item.width ? item.width : 130,
46353 'select': function(c, r, i) {
46355 tb.selectedNode.style[c.stylename] = r.get('val');
46358 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46367 tb.addField( new Roo.form.TextField({
46370 //allowBlank:false,
46375 tb.addField( new Roo.form.TextField({
46376 name: '-roo-edit-' + i,
46383 'change' : function(f, nv, ov) {
46384 tb.selectedNode.setAttribute(f.attrname, nv);
46385 editorcore.syncValue();
46398 text: 'Stylesheets',
46401 click : function ()
46403 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46411 text: 'Remove Tag',
46414 click : function ()
46417 // undo does not work.
46419 var sn = tb.selectedNode;
46421 var pn = sn.parentNode;
46423 var stn = sn.childNodes[0];
46424 var en = sn.childNodes[sn.childNodes.length - 1 ];
46425 while (sn.childNodes.length) {
46426 var node = sn.childNodes[0];
46427 sn.removeChild(node);
46429 pn.insertBefore(node, sn);
46432 pn.removeChild(sn);
46433 var range = editorcore.createRange();
46435 range.setStart(stn,0);
46436 range.setEnd(en,0); //????
46437 //range.selectNode(sel);
46440 var selection = editorcore.getSelection();
46441 selection.removeAllRanges();
46442 selection.addRange(range);
46446 //_this.updateToolbar(null, null, pn);
46447 _this.updateToolbar(null, null, null);
46448 _this.footDisp.dom.innerHTML = '';
46458 tb.el.on('click', function(e){
46459 e.preventDefault(); // what does this do?
46461 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46464 // dont need to disable them... as they will get hidden
46469 buildFooter : function()
46472 var fel = this.editor.wrap.createChild();
46473 this.footer = new Roo.Toolbar(fel);
46474 // toolbar has scrolly on left / right?
46475 var footDisp= new Roo.Toolbar.Fill();
46481 handler : function() {
46482 _t.footDisp.scrollTo('left',0,true)
46486 this.footer.add( footDisp );
46491 handler : function() {
46493 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46497 var fel = Roo.get(footDisp.el);
46498 fel.addClass('x-editor-context');
46499 this.footDispWrap = fel;
46500 this.footDispWrap.overflow = 'hidden';
46502 this.footDisp = fel.createChild();
46503 this.footDispWrap.on('click', this.onContextClick, this)
46507 onContextClick : function (ev,dom)
46509 ev.preventDefault();
46510 var cn = dom.className;
46512 if (!cn.match(/x-ed-loc-/)) {
46515 var n = cn.split('-').pop();
46516 var ans = this.footerEls;
46520 var range = this.editorcore.createRange();
46522 range.selectNodeContents(sel);
46523 //range.selectNode(sel);
46526 var selection = this.editorcore.getSelection();
46527 selection.removeAllRanges();
46528 selection.addRange(range);
46532 this.updateToolbar(null, null, sel);
46549 * Ext JS Library 1.1.1
46550 * Copyright(c) 2006-2007, Ext JS, LLC.
46552 * Originally Released Under LGPL - original licence link has changed is not relivant.
46555 * <script type="text/javascript">
46559 * @class Roo.form.BasicForm
46560 * @extends Roo.util.Observable
46561 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46563 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46564 * @param {Object} config Configuration options
46566 Roo.form.BasicForm = function(el, config){
46567 this.allItems = [];
46568 this.childForms = [];
46569 Roo.apply(this, config);
46571 * The Roo.form.Field items in this form.
46572 * @type MixedCollection
46576 this.items = new Roo.util.MixedCollection(false, function(o){
46577 return o.id || (o.id = Roo.id());
46581 * @event beforeaction
46582 * Fires before any action is performed. Return false to cancel the action.
46583 * @param {Form} this
46584 * @param {Action} action The action to be performed
46586 beforeaction: true,
46588 * @event actionfailed
46589 * Fires when an action fails.
46590 * @param {Form} this
46591 * @param {Action} action The action that failed
46593 actionfailed : true,
46595 * @event actioncomplete
46596 * Fires when an action is completed.
46597 * @param {Form} this
46598 * @param {Action} action The action that completed
46600 actioncomplete : true
46605 Roo.form.BasicForm.superclass.constructor.call(this);
46608 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46610 * @cfg {String} method
46611 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46614 * @cfg {DataReader} reader
46615 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46616 * This is optional as there is built-in support for processing JSON.
46619 * @cfg {DataReader} errorReader
46620 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46621 * This is completely optional as there is built-in support for processing JSON.
46624 * @cfg {String} url
46625 * The URL to use for form actions if one isn't supplied in the action options.
46628 * @cfg {Boolean} fileUpload
46629 * Set to true if this form is a file upload.
46633 * @cfg {Object} baseParams
46634 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46639 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46644 activeAction : null,
46647 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46648 * or setValues() data instead of when the form was first created.
46650 trackResetOnLoad : false,
46654 * childForms - used for multi-tab forms
46657 childForms : false,
46660 * allItems - full list of fields.
46666 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46667 * element by passing it or its id or mask the form itself by passing in true.
46670 waitMsgTarget : false,
46673 initEl : function(el){
46674 this.el = Roo.get(el);
46675 this.id = this.el.id || Roo.id();
46676 this.el.on('submit', this.onSubmit, this);
46677 this.el.addClass('x-form');
46681 onSubmit : function(e){
46686 * Returns true if client-side validation on the form is successful.
46689 isValid : function(){
46691 this.items.each(function(f){
46700 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46703 isDirty : function(){
46705 this.items.each(function(f){
46715 * Returns true if any fields in this form have changed since their original load. (New version)
46719 hasChanged : function()
46722 this.items.each(function(f){
46723 if(f.hasChanged()){
46732 * Resets all hasChanged to 'false' -
46733 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46734 * So hasChanged storage is only to be used for this purpose
46737 resetHasChanged : function()
46739 this.items.each(function(f){
46740 f.resetHasChanged();
46747 * Performs a predefined action (submit or load) or custom actions you define on this form.
46748 * @param {String} actionName The name of the action type
46749 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46750 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46751 * accept other config options):
46753 Property Type Description
46754 ---------------- --------------- ----------------------------------------------------------------------------------
46755 url String The url for the action (defaults to the form's url)
46756 method String The form method to use (defaults to the form's method, or POST if not defined)
46757 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46758 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46759 validate the form on the client (defaults to false)
46761 * @return {BasicForm} this
46763 doAction : function(action, options){
46764 if(typeof action == 'string'){
46765 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46767 if(this.fireEvent('beforeaction', this, action) !== false){
46768 this.beforeAction(action);
46769 action.run.defer(100, action);
46775 * Shortcut to do a submit action.
46776 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46777 * @return {BasicForm} this
46779 submit : function(options){
46780 this.doAction('submit', options);
46785 * Shortcut to do a load action.
46786 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46787 * @return {BasicForm} this
46789 load : function(options){
46790 this.doAction('load', options);
46795 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46796 * @param {Record} record The record to edit
46797 * @return {BasicForm} this
46799 updateRecord : function(record){
46800 record.beginEdit();
46801 var fs = record.fields;
46802 fs.each(function(f){
46803 var field = this.findField(f.name);
46805 record.set(f.name, field.getValue());
46813 * Loads an Roo.data.Record into this form.
46814 * @param {Record} record The record to load
46815 * @return {BasicForm} this
46817 loadRecord : function(record){
46818 this.setValues(record.data);
46823 beforeAction : function(action){
46824 var o = action.options;
46827 if(this.waitMsgTarget === true){
46828 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46829 }else if(this.waitMsgTarget){
46830 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46831 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46833 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46839 afterAction : function(action, success){
46840 this.activeAction = null;
46841 var o = action.options;
46843 if(this.waitMsgTarget === true){
46845 }else if(this.waitMsgTarget){
46846 this.waitMsgTarget.unmask();
46848 Roo.MessageBox.updateProgress(1);
46849 Roo.MessageBox.hide();
46856 Roo.callback(o.success, o.scope, [this, action]);
46857 this.fireEvent('actioncomplete', this, action);
46861 // failure condition..
46862 // we have a scenario where updates need confirming.
46863 // eg. if a locking scenario exists..
46864 // we look for { errors : { needs_confirm : true }} in the response.
46866 (typeof(action.result) != 'undefined') &&
46867 (typeof(action.result.errors) != 'undefined') &&
46868 (typeof(action.result.errors.needs_confirm) != 'undefined')
46871 Roo.MessageBox.confirm(
46872 "Change requires confirmation",
46873 action.result.errorMsg,
46878 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46888 Roo.callback(o.failure, o.scope, [this, action]);
46889 // show an error message if no failed handler is set..
46890 if (!this.hasListener('actionfailed')) {
46891 Roo.MessageBox.alert("Error",
46892 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46893 action.result.errorMsg :
46894 "Saving Failed, please check your entries or try again"
46898 this.fireEvent('actionfailed', this, action);
46904 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46905 * @param {String} id The value to search for
46908 findField : function(id){
46909 var field = this.items.get(id);
46911 this.items.each(function(f){
46912 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46918 return field || null;
46922 * Add a secondary form to this one,
46923 * Used to provide tabbed forms. One form is primary, with hidden values
46924 * which mirror the elements from the other forms.
46926 * @param {Roo.form.Form} form to add.
46929 addForm : function(form)
46932 if (this.childForms.indexOf(form) > -1) {
46936 this.childForms.push(form);
46938 Roo.each(form.allItems, function (fe) {
46940 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46941 if (this.findField(n)) { // already added..
46944 var add = new Roo.form.Hidden({
46947 add.render(this.el);
46954 * Mark fields in this form invalid in bulk.
46955 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46956 * @return {BasicForm} this
46958 markInvalid : function(errors){
46959 if(errors instanceof Array){
46960 for(var i = 0, len = errors.length; i < len; i++){
46961 var fieldError = errors[i];
46962 var f = this.findField(fieldError.id);
46964 f.markInvalid(fieldError.msg);
46970 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46971 field.markInvalid(errors[id]);
46975 Roo.each(this.childForms || [], function (f) {
46976 f.markInvalid(errors);
46983 * Set values for fields in this form in bulk.
46984 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46985 * @return {BasicForm} this
46987 setValues : function(values){
46988 if(values instanceof Array){ // array of objects
46989 for(var i = 0, len = values.length; i < len; i++){
46991 var f = this.findField(v.id);
46993 f.setValue(v.value);
46994 if(this.trackResetOnLoad){
46995 f.originalValue = f.getValue();
46999 }else{ // object hash
47002 if(typeof values[id] != 'function' && (field = this.findField(id))){
47004 if (field.setFromData &&
47005 field.valueField &&
47006 field.displayField &&
47007 // combos' with local stores can
47008 // be queried via setValue()
47009 // to set their value..
47010 (field.store && !field.store.isLocal)
47014 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47015 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47016 field.setFromData(sd);
47019 field.setValue(values[id]);
47023 if(this.trackResetOnLoad){
47024 field.originalValue = field.getValue();
47029 this.resetHasChanged();
47032 Roo.each(this.childForms || [], function (f) {
47033 f.setValues(values);
47034 f.resetHasChanged();
47041 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47042 * they are returned as an array.
47043 * @param {Boolean} asString
47046 getValues : function(asString){
47047 if (this.childForms) {
47048 // copy values from the child forms
47049 Roo.each(this.childForms, function (f) {
47050 this.setValues(f.getValues());
47056 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47057 if(asString === true){
47060 return Roo.urlDecode(fs);
47064 * Returns the fields in this form as an object with key/value pairs.
47065 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47068 getFieldValues : function(with_hidden)
47070 if (this.childForms) {
47071 // copy values from the child forms
47072 // should this call getFieldValues - probably not as we do not currently copy
47073 // hidden fields when we generate..
47074 Roo.each(this.childForms, function (f) {
47075 this.setValues(f.getValues());
47080 this.items.each(function(f){
47081 if (!f.getName()) {
47084 var v = f.getValue();
47085 if (f.inputType =='radio') {
47086 if (typeof(ret[f.getName()]) == 'undefined') {
47087 ret[f.getName()] = ''; // empty..
47090 if (!f.el.dom.checked) {
47094 v = f.el.dom.value;
47098 // not sure if this supported any more..
47099 if ((typeof(v) == 'object') && f.getRawValue) {
47100 v = f.getRawValue() ; // dates..
47102 // combo boxes where name != hiddenName...
47103 if (f.name != f.getName()) {
47104 ret[f.name] = f.getRawValue();
47106 ret[f.getName()] = v;
47113 * Clears all invalid messages in this form.
47114 * @return {BasicForm} this
47116 clearInvalid : function(){
47117 this.items.each(function(f){
47121 Roo.each(this.childForms || [], function (f) {
47130 * Resets this form.
47131 * @return {BasicForm} this
47133 reset : function(){
47134 this.items.each(function(f){
47138 Roo.each(this.childForms || [], function (f) {
47141 this.resetHasChanged();
47147 * Add Roo.form components to this form.
47148 * @param {Field} field1
47149 * @param {Field} field2 (optional)
47150 * @param {Field} etc (optional)
47151 * @return {BasicForm} this
47154 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47160 * Removes a field from the items collection (does NOT remove its markup).
47161 * @param {Field} field
47162 * @return {BasicForm} this
47164 remove : function(field){
47165 this.items.remove(field);
47170 * Looks at the fields in this form, checks them for an id attribute,
47171 * and calls applyTo on the existing dom element with that id.
47172 * @return {BasicForm} this
47174 render : function(){
47175 this.items.each(function(f){
47176 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47184 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47185 * @param {Object} values
47186 * @return {BasicForm} this
47188 applyToFields : function(o){
47189 this.items.each(function(f){
47196 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47197 * @param {Object} values
47198 * @return {BasicForm} this
47200 applyIfToFields : function(o){
47201 this.items.each(function(f){
47209 Roo.BasicForm = Roo.form.BasicForm;/*
47211 * Ext JS Library 1.1.1
47212 * Copyright(c) 2006-2007, Ext JS, LLC.
47214 * Originally Released Under LGPL - original licence link has changed is not relivant.
47217 * <script type="text/javascript">
47221 * @class Roo.form.Form
47222 * @extends Roo.form.BasicForm
47223 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47225 * @param {Object} config Configuration options
47227 Roo.form.Form = function(config){
47229 if (config.items) {
47230 xitems = config.items;
47231 delete config.items;
47235 Roo.form.Form.superclass.constructor.call(this, null, config);
47236 this.url = this.url || this.action;
47238 this.root = new Roo.form.Layout(Roo.applyIf({
47242 this.active = this.root;
47244 * Array of all the buttons that have been added to this form via {@link addButton}
47248 this.allItems = [];
47251 * @event clientvalidation
47252 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47253 * @param {Form} this
47254 * @param {Boolean} valid true if the form has passed client-side validation
47256 clientvalidation: true,
47259 * Fires when the form is rendered
47260 * @param {Roo.form.Form} form
47265 if (this.progressUrl) {
47266 // push a hidden field onto the list of fields..
47270 name : 'UPLOAD_IDENTIFIER'
47275 Roo.each(xitems, this.addxtype, this);
47281 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47283 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47286 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47289 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47291 buttonAlign:'center',
47294 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47299 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47300 * This property cascades to child containers if not set.
47305 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47306 * fires a looping event with that state. This is required to bind buttons to the valid
47307 * state using the config value formBind:true on the button.
47309 monitorValid : false,
47312 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47317 * @cfg {String} progressUrl - Url to return progress data
47320 progressUrl : false,
47323 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47324 * fields are added and the column is closed. If no fields are passed the column remains open
47325 * until end() is called.
47326 * @param {Object} config The config to pass to the column
47327 * @param {Field} field1 (optional)
47328 * @param {Field} field2 (optional)
47329 * @param {Field} etc (optional)
47330 * @return Column The column container object
47332 column : function(c){
47333 var col = new Roo.form.Column(c);
47335 if(arguments.length > 1){ // duplicate code required because of Opera
47336 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47343 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47344 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47345 * until end() is called.
47346 * @param {Object} config The config to pass to the fieldset
47347 * @param {Field} field1 (optional)
47348 * @param {Field} field2 (optional)
47349 * @param {Field} etc (optional)
47350 * @return FieldSet The fieldset container object
47352 fieldset : function(c){
47353 var fs = new Roo.form.FieldSet(c);
47355 if(arguments.length > 1){ // duplicate code required because of Opera
47356 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47363 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47364 * fields are added and the container is closed. If no fields are passed the container remains open
47365 * until end() is called.
47366 * @param {Object} config The config to pass to the Layout
47367 * @param {Field} field1 (optional)
47368 * @param {Field} field2 (optional)
47369 * @param {Field} etc (optional)
47370 * @return Layout The container object
47372 container : function(c){
47373 var l = new Roo.form.Layout(c);
47375 if(arguments.length > 1){ // duplicate code required because of Opera
47376 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47383 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47384 * @param {Object} container A Roo.form.Layout or subclass of Layout
47385 * @return {Form} this
47387 start : function(c){
47388 // cascade label info
47389 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47390 this.active.stack.push(c);
47391 c.ownerCt = this.active;
47397 * Closes the current open container
47398 * @return {Form} this
47401 if(this.active == this.root){
47404 this.active = this.active.ownerCt;
47409 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47410 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47411 * as the label of the field.
47412 * @param {Field} field1
47413 * @param {Field} field2 (optional)
47414 * @param {Field} etc. (optional)
47415 * @return {Form} this
47418 this.active.stack.push.apply(this.active.stack, arguments);
47419 this.allItems.push.apply(this.allItems,arguments);
47421 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47422 if(a[i].isFormField){
47427 Roo.form.Form.superclass.add.apply(this, r);
47437 * Find any element that has been added to a form, using it's ID or name
47438 * This can include framesets, columns etc. along with regular fields..
47439 * @param {String} id - id or name to find.
47441 * @return {Element} e - or false if nothing found.
47443 findbyId : function(id)
47449 Roo.each(this.allItems, function(f){
47450 if (f.id == id || f.name == id ){
47461 * Render this form into the passed container. This should only be called once!
47462 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47463 * @return {Form} this
47465 render : function(ct)
47471 var o = this.autoCreate || {
47473 method : this.method || 'POST',
47474 id : this.id || Roo.id()
47476 this.initEl(ct.createChild(o));
47478 this.root.render(this.el);
47482 this.items.each(function(f){
47483 f.render('x-form-el-'+f.id);
47486 if(this.buttons.length > 0){
47487 // tables are required to maintain order and for correct IE layout
47488 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47489 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47490 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47492 var tr = tb.getElementsByTagName('tr')[0];
47493 for(var i = 0, len = this.buttons.length; i < len; i++) {
47494 var b = this.buttons[i];
47495 var td = document.createElement('td');
47496 td.className = 'x-form-btn-td';
47497 b.render(tr.appendChild(td));
47500 if(this.monitorValid){ // initialize after render
47501 this.startMonitoring();
47503 this.fireEvent('rendered', this);
47508 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47509 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47510 * object or a valid Roo.DomHelper element config
47511 * @param {Function} handler The function called when the button is clicked
47512 * @param {Object} scope (optional) The scope of the handler function
47513 * @return {Roo.Button}
47515 addButton : function(config, handler, scope){
47519 minWidth: this.minButtonWidth,
47522 if(typeof config == "string"){
47525 Roo.apply(bc, config);
47527 var btn = new Roo.Button(null, bc);
47528 this.buttons.push(btn);
47533 * Adds a series of form elements (using the xtype property as the factory method.
47534 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47535 * @param {Object} config
47538 addxtype : function()
47540 var ar = Array.prototype.slice.call(arguments, 0);
47542 for(var i = 0; i < ar.length; i++) {
47544 continue; // skip -- if this happends something invalid got sent, we
47545 // should ignore it, as basically that interface element will not show up
47546 // and that should be pretty obvious!!
47549 if (Roo.form[ar[i].xtype]) {
47551 var fe = Roo.factory(ar[i], Roo.form);
47557 fe.store.form = this;
47562 this.allItems.push(fe);
47563 if (fe.items && fe.addxtype) {
47564 fe.addxtype.apply(fe, fe.items);
47574 // console.log('adding ' + ar[i].xtype);
47576 if (ar[i].xtype == 'Button') {
47577 //console.log('adding button');
47578 //console.log(ar[i]);
47579 this.addButton(ar[i]);
47580 this.allItems.push(fe);
47584 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47585 alert('end is not supported on xtype any more, use items');
47587 // //console.log('adding end');
47595 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47596 * option "monitorValid"
47598 startMonitoring : function(){
47601 Roo.TaskMgr.start({
47602 run : this.bindHandler,
47603 interval : this.monitorPoll || 200,
47610 * Stops monitoring of the valid state of this form
47612 stopMonitoring : function(){
47613 this.bound = false;
47617 bindHandler : function(){
47619 return false; // stops binding
47622 this.items.each(function(f){
47623 if(!f.isValid(true)){
47628 for(var i = 0, len = this.buttons.length; i < len; i++){
47629 var btn = this.buttons[i];
47630 if(btn.formBind === true && btn.disabled === valid){
47631 btn.setDisabled(!valid);
47634 this.fireEvent('clientvalidation', this, valid);
47648 Roo.Form = Roo.form.Form;
47651 * Ext JS Library 1.1.1
47652 * Copyright(c) 2006-2007, Ext JS, LLC.
47654 * Originally Released Under LGPL - original licence link has changed is not relivant.
47657 * <script type="text/javascript">
47660 // as we use this in bootstrap.
47661 Roo.namespace('Roo.form');
47663 * @class Roo.form.Action
47664 * Internal Class used to handle form actions
47666 * @param {Roo.form.BasicForm} el The form element or its id
47667 * @param {Object} config Configuration options
47672 // define the action interface
47673 Roo.form.Action = function(form, options){
47675 this.options = options || {};
47678 * Client Validation Failed
47681 Roo.form.Action.CLIENT_INVALID = 'client';
47683 * Server Validation Failed
47686 Roo.form.Action.SERVER_INVALID = 'server';
47688 * Connect to Server Failed
47691 Roo.form.Action.CONNECT_FAILURE = 'connect';
47693 * Reading Data from Server Failed
47696 Roo.form.Action.LOAD_FAILURE = 'load';
47698 Roo.form.Action.prototype = {
47700 failureType : undefined,
47701 response : undefined,
47702 result : undefined,
47704 // interface method
47705 run : function(options){
47709 // interface method
47710 success : function(response){
47714 // interface method
47715 handleResponse : function(response){
47719 // default connection failure
47720 failure : function(response){
47722 this.response = response;
47723 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47724 this.form.afterAction(this, false);
47727 processResponse : function(response){
47728 this.response = response;
47729 if(!response.responseText){
47732 this.result = this.handleResponse(response);
47733 return this.result;
47736 // utility functions used internally
47737 getUrl : function(appendParams){
47738 var url = this.options.url || this.form.url || this.form.el.dom.action;
47740 var p = this.getParams();
47742 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47748 getMethod : function(){
47749 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47752 getParams : function(){
47753 var bp = this.form.baseParams;
47754 var p = this.options.params;
47756 if(typeof p == "object"){
47757 p = Roo.urlEncode(Roo.applyIf(p, bp));
47758 }else if(typeof p == 'string' && bp){
47759 p += '&' + Roo.urlEncode(bp);
47762 p = Roo.urlEncode(bp);
47767 createCallback : function(){
47769 success: this.success,
47770 failure: this.failure,
47772 timeout: (this.form.timeout*1000),
47773 upload: this.form.fileUpload ? this.success : undefined
47778 Roo.form.Action.Submit = function(form, options){
47779 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47782 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47785 haveProgress : false,
47786 uploadComplete : false,
47788 // uploadProgress indicator.
47789 uploadProgress : function()
47791 if (!this.form.progressUrl) {
47795 if (!this.haveProgress) {
47796 Roo.MessageBox.progress("Uploading", "Uploading");
47798 if (this.uploadComplete) {
47799 Roo.MessageBox.hide();
47803 this.haveProgress = true;
47805 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47807 var c = new Roo.data.Connection();
47809 url : this.form.progressUrl,
47814 success : function(req){
47815 //console.log(data);
47819 rdata = Roo.decode(req.responseText)
47821 Roo.log("Invalid data from server..");
47825 if (!rdata || !rdata.success) {
47827 Roo.MessageBox.alert(Roo.encode(rdata));
47830 var data = rdata.data;
47832 if (this.uploadComplete) {
47833 Roo.MessageBox.hide();
47838 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47839 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47842 this.uploadProgress.defer(2000,this);
47845 failure: function(data) {
47846 Roo.log('progress url failed ');
47857 // run get Values on the form, so it syncs any secondary forms.
47858 this.form.getValues();
47860 var o = this.options;
47861 var method = this.getMethod();
47862 var isPost = method == 'POST';
47863 if(o.clientValidation === false || this.form.isValid()){
47865 if (this.form.progressUrl) {
47866 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47867 (new Date() * 1) + '' + Math.random());
47872 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47873 form:this.form.el.dom,
47874 url:this.getUrl(!isPost),
47876 params:isPost ? this.getParams() : null,
47877 isUpload: this.form.fileUpload
47880 this.uploadProgress();
47882 }else if (o.clientValidation !== false){ // client validation failed
47883 this.failureType = Roo.form.Action.CLIENT_INVALID;
47884 this.form.afterAction(this, false);
47888 success : function(response)
47890 this.uploadComplete= true;
47891 if (this.haveProgress) {
47892 Roo.MessageBox.hide();
47896 var result = this.processResponse(response);
47897 if(result === true || result.success){
47898 this.form.afterAction(this, true);
47902 this.form.markInvalid(result.errors);
47903 this.failureType = Roo.form.Action.SERVER_INVALID;
47905 this.form.afterAction(this, false);
47907 failure : function(response)
47909 this.uploadComplete= true;
47910 if (this.haveProgress) {
47911 Roo.MessageBox.hide();
47914 this.response = response;
47915 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47916 this.form.afterAction(this, false);
47919 handleResponse : function(response){
47920 if(this.form.errorReader){
47921 var rs = this.form.errorReader.read(response);
47924 for(var i = 0, len = rs.records.length; i < len; i++) {
47925 var r = rs.records[i];
47926 errors[i] = r.data;
47929 if(errors.length < 1){
47933 success : rs.success,
47939 ret = Roo.decode(response.responseText);
47943 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47953 Roo.form.Action.Load = function(form, options){
47954 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47955 this.reader = this.form.reader;
47958 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47963 Roo.Ajax.request(Roo.apply(
47964 this.createCallback(), {
47965 method:this.getMethod(),
47966 url:this.getUrl(false),
47967 params:this.getParams()
47971 success : function(response){
47973 var result = this.processResponse(response);
47974 if(result === true || !result.success || !result.data){
47975 this.failureType = Roo.form.Action.LOAD_FAILURE;
47976 this.form.afterAction(this, false);
47979 this.form.clearInvalid();
47980 this.form.setValues(result.data);
47981 this.form.afterAction(this, true);
47984 handleResponse : function(response){
47985 if(this.form.reader){
47986 var rs = this.form.reader.read(response);
47987 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47989 success : rs.success,
47993 return Roo.decode(response.responseText);
47997 Roo.form.Action.ACTION_TYPES = {
47998 'load' : Roo.form.Action.Load,
47999 'submit' : Roo.form.Action.Submit
48002 * Ext JS Library 1.1.1
48003 * Copyright(c) 2006-2007, Ext JS, LLC.
48005 * Originally Released Under LGPL - original licence link has changed is not relivant.
48008 * <script type="text/javascript">
48012 * @class Roo.form.Layout
48013 * @extends Roo.Component
48014 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48016 * @param {Object} config Configuration options
48018 Roo.form.Layout = function(config){
48020 if (config.items) {
48021 xitems = config.items;
48022 delete config.items;
48024 Roo.form.Layout.superclass.constructor.call(this, config);
48026 Roo.each(xitems, this.addxtype, this);
48030 Roo.extend(Roo.form.Layout, Roo.Component, {
48032 * @cfg {String/Object} autoCreate
48033 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48036 * @cfg {String/Object/Function} style
48037 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48038 * a function which returns such a specification.
48041 * @cfg {String} labelAlign
48042 * Valid values are "left," "top" and "right" (defaults to "left")
48045 * @cfg {Number} labelWidth
48046 * Fixed width in pixels of all field labels (defaults to undefined)
48049 * @cfg {Boolean} clear
48050 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48054 * @cfg {String} labelSeparator
48055 * The separator to use after field labels (defaults to ':')
48057 labelSeparator : ':',
48059 * @cfg {Boolean} hideLabels
48060 * True to suppress the display of field labels in this layout (defaults to false)
48062 hideLabels : false,
48065 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48070 onRender : function(ct, position){
48071 if(this.el){ // from markup
48072 this.el = Roo.get(this.el);
48073 }else { // generate
48074 var cfg = this.getAutoCreate();
48075 this.el = ct.createChild(cfg, position);
48078 this.el.applyStyles(this.style);
48080 if(this.labelAlign){
48081 this.el.addClass('x-form-label-'+this.labelAlign);
48083 if(this.hideLabels){
48084 this.labelStyle = "display:none";
48085 this.elementStyle = "padding-left:0;";
48087 if(typeof this.labelWidth == 'number'){
48088 this.labelStyle = "width:"+this.labelWidth+"px;";
48089 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48091 if(this.labelAlign == 'top'){
48092 this.labelStyle = "width:auto;";
48093 this.elementStyle = "padding-left:0;";
48096 var stack = this.stack;
48097 var slen = stack.length;
48099 if(!this.fieldTpl){
48100 var t = new Roo.Template(
48101 '<div class="x-form-item {5}">',
48102 '<label for="{0}" style="{2}">{1}{4}</label>',
48103 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48105 '</div><div class="x-form-clear-left"></div>'
48107 t.disableFormats = true;
48109 Roo.form.Layout.prototype.fieldTpl = t;
48111 for(var i = 0; i < slen; i++) {
48112 if(stack[i].isFormField){
48113 this.renderField(stack[i]);
48115 this.renderComponent(stack[i]);
48120 this.el.createChild({cls:'x-form-clear'});
48125 renderField : function(f){
48126 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48129 f.labelStyle||this.labelStyle||'', //2
48130 this.elementStyle||'', //3
48131 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48132 f.itemCls||this.itemCls||'' //5
48133 ], true).getPrevSibling());
48137 renderComponent : function(c){
48138 c.render(c.isLayout ? this.el : this.el.createChild());
48141 * Adds a object form elements (using the xtype property as the factory method.)
48142 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48143 * @param {Object} config
48145 addxtype : function(o)
48147 // create the lement.
48148 o.form = this.form;
48149 var fe = Roo.factory(o, Roo.form);
48150 this.form.allItems.push(fe);
48151 this.stack.push(fe);
48153 if (fe.isFormField) {
48154 this.form.items.add(fe);
48162 * @class Roo.form.Column
48163 * @extends Roo.form.Layout
48164 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48166 * @param {Object} config Configuration options
48168 Roo.form.Column = function(config){
48169 Roo.form.Column.superclass.constructor.call(this, config);
48172 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48174 * @cfg {Number/String} width
48175 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48178 * @cfg {String/Object} autoCreate
48179 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48183 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48186 onRender : function(ct, position){
48187 Roo.form.Column.superclass.onRender.call(this, ct, position);
48189 this.el.setWidth(this.width);
48196 * @class Roo.form.Row
48197 * @extends Roo.form.Layout
48198 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48200 * @param {Object} config Configuration options
48204 Roo.form.Row = function(config){
48205 Roo.form.Row.superclass.constructor.call(this, config);
48208 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48210 * @cfg {Number/String} width
48211 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48214 * @cfg {Number/String} height
48215 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48217 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48221 onRender : function(ct, position){
48222 //console.log('row render');
48224 var t = new Roo.Template(
48225 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48226 '<label for="{0}" style="{2}">{1}{4}</label>',
48227 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48231 t.disableFormats = true;
48233 Roo.form.Layout.prototype.rowTpl = t;
48235 this.fieldTpl = this.rowTpl;
48237 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48238 var labelWidth = 100;
48240 if ((this.labelAlign != 'top')) {
48241 if (typeof this.labelWidth == 'number') {
48242 labelWidth = this.labelWidth
48244 this.padWidth = 20 + labelWidth;
48248 Roo.form.Column.superclass.onRender.call(this, ct, position);
48250 this.el.setWidth(this.width);
48253 this.el.setHeight(this.height);
48258 renderField : function(f){
48259 f.fieldEl = this.fieldTpl.append(this.el, [
48260 f.id, f.fieldLabel,
48261 f.labelStyle||this.labelStyle||'',
48262 this.elementStyle||'',
48263 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48264 f.itemCls||this.itemCls||'',
48265 f.width ? f.width + this.padWidth : 160 + this.padWidth
48272 * @class Roo.form.FieldSet
48273 * @extends Roo.form.Layout
48274 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48276 * @param {Object} config Configuration options
48278 Roo.form.FieldSet = function(config){
48279 Roo.form.FieldSet.superclass.constructor.call(this, config);
48282 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48284 * @cfg {String} legend
48285 * The text to display as the legend for the FieldSet (defaults to '')
48288 * @cfg {String/Object} autoCreate
48289 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48293 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48296 onRender : function(ct, position){
48297 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48299 this.setLegend(this.legend);
48304 setLegend : function(text){
48306 this.el.child('legend').update(text);
48311 * Ext JS Library 1.1.1
48312 * Copyright(c) 2006-2007, Ext JS, LLC.
48314 * Originally Released Under LGPL - original licence link has changed is not relivant.
48317 * <script type="text/javascript">
48320 * @class Roo.form.VTypes
48321 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48324 Roo.form.VTypes = function(){
48325 // closure these in so they are only created once.
48326 var alpha = /^[a-zA-Z_]+$/;
48327 var alphanum = /^[a-zA-Z0-9_]+$/;
48328 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48329 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48331 // All these messages and functions are configurable
48334 * The function used to validate email addresses
48335 * @param {String} value The email address
48337 'email' : function(v){
48338 return email.test(v);
48341 * The error text to display when the email validation function returns false
48344 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48346 * The keystroke filter mask to be applied on email input
48349 'emailMask' : /[a-z0-9_\.\-@]/i,
48352 * The function used to validate URLs
48353 * @param {String} value The URL
48355 'url' : function(v){
48356 return url.test(v);
48359 * The error text to display when the url validation function returns false
48362 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48365 * The function used to validate alpha values
48366 * @param {String} value The value
48368 'alpha' : function(v){
48369 return alpha.test(v);
48372 * The error text to display when the alpha validation function returns false
48375 'alphaText' : 'This field should only contain letters and _',
48377 * The keystroke filter mask to be applied on alpha input
48380 'alphaMask' : /[a-z_]/i,
48383 * The function used to validate alphanumeric values
48384 * @param {String} value The value
48386 'alphanum' : function(v){
48387 return alphanum.test(v);
48390 * The error text to display when the alphanumeric validation function returns false
48393 'alphanumText' : 'This field should only contain letters, numbers and _',
48395 * The keystroke filter mask to be applied on alphanumeric input
48398 'alphanumMask' : /[a-z0-9_]/i
48400 }();//<script type="text/javascript">
48403 * @class Roo.form.FCKeditor
48404 * @extends Roo.form.TextArea
48405 * Wrapper around the FCKEditor http://www.fckeditor.net
48407 * Creates a new FCKeditor
48408 * @param {Object} config Configuration options
48410 Roo.form.FCKeditor = function(config){
48411 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48414 * @event editorinit
48415 * Fired when the editor is initialized - you can add extra handlers here..
48416 * @param {FCKeditor} this
48417 * @param {Object} the FCK object.
48424 Roo.form.FCKeditor.editors = { };
48425 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48427 //defaultAutoCreate : {
48428 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48432 * @cfg {Object} fck options - see fck manual for details.
48437 * @cfg {Object} fck toolbar set (Basic or Default)
48439 toolbarSet : 'Basic',
48441 * @cfg {Object} fck BasePath
48443 basePath : '/fckeditor/',
48451 onRender : function(ct, position)
48454 this.defaultAutoCreate = {
48456 style:"width:300px;height:60px;",
48457 autocomplete: "new-password"
48460 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48463 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48464 if(this.preventScrollbars){
48465 this.el.setStyle("overflow", "hidden");
48467 this.el.setHeight(this.growMin);
48470 //console.log('onrender' + this.getId() );
48471 Roo.form.FCKeditor.editors[this.getId()] = this;
48474 this.replaceTextarea() ;
48478 getEditor : function() {
48479 return this.fckEditor;
48482 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48483 * @param {Mixed} value The value to set
48487 setValue : function(value)
48489 //console.log('setValue: ' + value);
48491 if(typeof(value) == 'undefined') { // not sure why this is happending...
48494 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48496 //if(!this.el || !this.getEditor()) {
48497 // this.value = value;
48498 //this.setValue.defer(100,this,[value]);
48502 if(!this.getEditor()) {
48506 this.getEditor().SetData(value);
48513 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48514 * @return {Mixed} value The field value
48516 getValue : function()
48519 if (this.frame && this.frame.dom.style.display == 'none') {
48520 return Roo.form.FCKeditor.superclass.getValue.call(this);
48523 if(!this.el || !this.getEditor()) {
48525 // this.getValue.defer(100,this);
48530 var value=this.getEditor().GetData();
48531 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48532 return Roo.form.FCKeditor.superclass.getValue.call(this);
48538 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48539 * @return {Mixed} value The field value
48541 getRawValue : function()
48543 if (this.frame && this.frame.dom.style.display == 'none') {
48544 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48547 if(!this.el || !this.getEditor()) {
48548 //this.getRawValue.defer(100,this);
48555 var value=this.getEditor().GetData();
48556 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48557 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48561 setSize : function(w,h) {
48565 //if (this.frame && this.frame.dom.style.display == 'none') {
48566 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48569 //if(!this.el || !this.getEditor()) {
48570 // this.setSize.defer(100,this, [w,h]);
48576 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48578 this.frame.dom.setAttribute('width', w);
48579 this.frame.dom.setAttribute('height', h);
48580 this.frame.setSize(w,h);
48584 toggleSourceEdit : function(value) {
48588 this.el.dom.style.display = value ? '' : 'none';
48589 this.frame.dom.style.display = value ? 'none' : '';
48594 focus: function(tag)
48596 if (this.frame.dom.style.display == 'none') {
48597 return Roo.form.FCKeditor.superclass.focus.call(this);
48599 if(!this.el || !this.getEditor()) {
48600 this.focus.defer(100,this, [tag]);
48607 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48608 this.getEditor().Focus();
48610 if (!this.getEditor().Selection.GetSelection()) {
48611 this.focus.defer(100,this, [tag]);
48616 var r = this.getEditor().EditorDocument.createRange();
48617 r.setStart(tgs[0],0);
48618 r.setEnd(tgs[0],0);
48619 this.getEditor().Selection.GetSelection().removeAllRanges();
48620 this.getEditor().Selection.GetSelection().addRange(r);
48621 this.getEditor().Focus();
48628 replaceTextarea : function()
48630 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48633 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48635 // We must check the elements firstly using the Id and then the name.
48636 var oTextarea = document.getElementById( this.getId() );
48638 var colElementsByName = document.getElementsByName( this.getId() ) ;
48640 oTextarea.style.display = 'none' ;
48642 if ( oTextarea.tabIndex ) {
48643 this.TabIndex = oTextarea.tabIndex ;
48646 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48647 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48648 this.frame = Roo.get(this.getId() + '___Frame')
48651 _getConfigHtml : function()
48655 for ( var o in this.fckconfig ) {
48656 sConfig += sConfig.length > 0 ? '&' : '';
48657 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48660 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48664 _getIFrameHtml : function()
48666 var sFile = 'fckeditor.html' ;
48667 /* no idea what this is about..
48670 if ( (/fcksource=true/i).test( window.top.location.search ) )
48671 sFile = 'fckeditor.original.html' ;
48676 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48677 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48680 var html = '<iframe id="' + this.getId() +
48681 '___Frame" src="' + sLink +
48682 '" width="' + this.width +
48683 '" height="' + this.height + '"' +
48684 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48685 ' frameborder="0" scrolling="no"></iframe>' ;
48690 _insertHtmlBefore : function( html, element )
48692 if ( element.insertAdjacentHTML ) {
48694 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48696 var oRange = document.createRange() ;
48697 oRange.setStartBefore( element ) ;
48698 var oFragment = oRange.createContextualFragment( html );
48699 element.parentNode.insertBefore( oFragment, element ) ;
48712 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48714 function FCKeditor_OnComplete(editorInstance){
48715 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48716 f.fckEditor = editorInstance;
48717 //console.log("loaded");
48718 f.fireEvent('editorinit', f, editorInstance);
48738 //<script type="text/javascript">
48740 * @class Roo.form.GridField
48741 * @extends Roo.form.Field
48742 * Embed a grid (or editable grid into a form)
48745 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48747 * xgrid.store = Roo.data.Store
48748 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48749 * xgrid.store.reader = Roo.data.JsonReader
48753 * Creates a new GridField
48754 * @param {Object} config Configuration options
48756 Roo.form.GridField = function(config){
48757 Roo.form.GridField.superclass.constructor.call(this, config);
48761 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48763 * @cfg {Number} width - used to restrict width of grid..
48767 * @cfg {Number} height - used to restrict height of grid..
48771 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48777 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48778 * {tag: "input", type: "checkbox", autocomplete: "off"})
48780 // defaultAutoCreate : { tag: 'div' },
48781 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48783 * @cfg {String} addTitle Text to include for adding a title.
48787 onResize : function(){
48788 Roo.form.Field.superclass.onResize.apply(this, arguments);
48791 initEvents : function(){
48792 // Roo.form.Checkbox.superclass.initEvents.call(this);
48793 // has no events...
48798 getResizeEl : function(){
48802 getPositionEl : function(){
48807 onRender : function(ct, position){
48809 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48810 var style = this.style;
48813 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48814 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48815 this.viewEl = this.wrap.createChild({ tag: 'div' });
48817 this.viewEl.applyStyles(style);
48820 this.viewEl.setWidth(this.width);
48823 this.viewEl.setHeight(this.height);
48825 //if(this.inputValue !== undefined){
48826 //this.setValue(this.value);
48829 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48832 this.grid.render();
48833 this.grid.getDataSource().on('remove', this.refreshValue, this);
48834 this.grid.getDataSource().on('update', this.refreshValue, this);
48835 this.grid.on('afteredit', this.refreshValue, this);
48841 * Sets the value of the item.
48842 * @param {String} either an object or a string..
48844 setValue : function(v){
48846 v = v || []; // empty set..
48847 // this does not seem smart - it really only affects memoryproxy grids..
48848 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48849 var ds = this.grid.getDataSource();
48850 // assumes a json reader..
48852 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48853 ds.loadData( data);
48855 // clear selection so it does not get stale.
48856 if (this.grid.sm) {
48857 this.grid.sm.clearSelections();
48860 Roo.form.GridField.superclass.setValue.call(this, v);
48861 this.refreshValue();
48862 // should load data in the grid really....
48866 refreshValue: function() {
48868 this.grid.getDataSource().each(function(r) {
48871 this.el.dom.value = Roo.encode(val);
48879 * Ext JS Library 1.1.1
48880 * Copyright(c) 2006-2007, Ext JS, LLC.
48882 * Originally Released Under LGPL - original licence link has changed is not relivant.
48885 * <script type="text/javascript">
48888 * @class Roo.form.DisplayField
48889 * @extends Roo.form.Field
48890 * A generic Field to display non-editable data.
48891 * @cfg {Boolean} closable (true|false) default false
48893 * Creates a new Display Field item.
48894 * @param {Object} config Configuration options
48896 Roo.form.DisplayField = function(config){
48897 Roo.form.DisplayField.superclass.constructor.call(this, config);
48902 * Fires after the click the close btn
48903 * @param {Roo.form.DisplayField} this
48909 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48910 inputType: 'hidden',
48916 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48918 focusClass : undefined,
48920 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48922 fieldClass: 'x-form-field',
48925 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48927 valueRenderer: undefined,
48931 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48932 * {tag: "input", type: "checkbox", autocomplete: "off"})
48935 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48939 onResize : function(){
48940 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48944 initEvents : function(){
48945 // Roo.form.Checkbox.superclass.initEvents.call(this);
48946 // has no events...
48949 this.closeEl.on('click', this.onClose, this);
48955 getResizeEl : function(){
48959 getPositionEl : function(){
48964 onRender : function(ct, position){
48966 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48967 //if(this.inputValue !== undefined){
48968 this.wrap = this.el.wrap();
48970 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48973 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48976 if (this.bodyStyle) {
48977 this.viewEl.applyStyles(this.bodyStyle);
48979 //this.viewEl.setStyle('padding', '2px');
48981 this.setValue(this.value);
48986 initValue : Roo.emptyFn,
48991 onClick : function(){
48996 * Sets the checked state of the checkbox.
48997 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
48999 setValue : function(v){
49001 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49002 // this might be called before we have a dom element..
49003 if (!this.viewEl) {
49006 this.viewEl.dom.innerHTML = html;
49007 Roo.form.DisplayField.superclass.setValue.call(this, v);
49011 onClose : function(e)
49013 e.preventDefault();
49015 this.fireEvent('close', this);
49024 * @class Roo.form.DayPicker
49025 * @extends Roo.form.Field
49026 * A Day picker show [M] [T] [W] ....
49028 * Creates a new Day Picker
49029 * @param {Object} config Configuration options
49031 Roo.form.DayPicker= function(config){
49032 Roo.form.DayPicker.superclass.constructor.call(this, config);
49036 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49038 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49040 focusClass : undefined,
49042 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49044 fieldClass: "x-form-field",
49047 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49048 * {tag: "input", type: "checkbox", autocomplete: "off"})
49050 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49053 actionMode : 'viewEl',
49057 inputType : 'hidden',
49060 inputElement: false, // real input element?
49061 basedOn: false, // ????
49063 isFormField: true, // not sure where this is needed!!!!
49065 onResize : function(){
49066 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49067 if(!this.boxLabel){
49068 this.el.alignTo(this.wrap, 'c-c');
49072 initEvents : function(){
49073 Roo.form.Checkbox.superclass.initEvents.call(this);
49074 this.el.on("click", this.onClick, this);
49075 this.el.on("change", this.onClick, this);
49079 getResizeEl : function(){
49083 getPositionEl : function(){
49089 onRender : function(ct, position){
49090 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49092 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49094 var r1 = '<table><tr>';
49095 var r2 = '<tr class="x-form-daypick-icons">';
49096 for (var i=0; i < 7; i++) {
49097 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49098 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49101 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49102 viewEl.select('img').on('click', this.onClick, this);
49103 this.viewEl = viewEl;
49106 // this will not work on Chrome!!!
49107 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49108 this.el.on('propertychange', this.setFromHidden, this); //ie
49116 initValue : Roo.emptyFn,
49119 * Returns the checked state of the checkbox.
49120 * @return {Boolean} True if checked, else false
49122 getValue : function(){
49123 return this.el.dom.value;
49128 onClick : function(e){
49129 //this.setChecked(!this.checked);
49130 Roo.get(e.target).toggleClass('x-menu-item-checked');
49131 this.refreshValue();
49132 //if(this.el.dom.checked != this.checked){
49133 // this.setValue(this.el.dom.checked);
49138 refreshValue : function()
49141 this.viewEl.select('img',true).each(function(e,i,n) {
49142 val += e.is(".x-menu-item-checked") ? String(n) : '';
49144 this.setValue(val, true);
49148 * Sets the checked state of the checkbox.
49149 * On is always based on a string comparison between inputValue and the param.
49150 * @param {Boolean/String} value - the value to set
49151 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49153 setValue : function(v,suppressEvent){
49154 if (!this.el.dom) {
49157 var old = this.el.dom.value ;
49158 this.el.dom.value = v;
49159 if (suppressEvent) {
49163 // update display..
49164 this.viewEl.select('img',true).each(function(e,i,n) {
49166 var on = e.is(".x-menu-item-checked");
49167 var newv = v.indexOf(String(n)) > -1;
49169 e.toggleClass('x-menu-item-checked');
49175 this.fireEvent('change', this, v, old);
49180 // handle setting of hidden value by some other method!!?!?
49181 setFromHidden: function()
49186 //console.log("SET FROM HIDDEN");
49187 //alert('setFrom hidden');
49188 this.setValue(this.el.dom.value);
49191 onDestroy : function()
49194 Roo.get(this.viewEl).remove();
49197 Roo.form.DayPicker.superclass.onDestroy.call(this);
49201 * RooJS Library 1.1.1
49202 * Copyright(c) 2008-2011 Alan Knowles
49209 * @class Roo.form.ComboCheck
49210 * @extends Roo.form.ComboBox
49211 * A combobox for multiple select items.
49213 * FIXME - could do with a reset button..
49216 * Create a new ComboCheck
49217 * @param {Object} config Configuration options
49219 Roo.form.ComboCheck = function(config){
49220 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49221 // should verify some data...
49223 // hiddenName = required..
49224 // displayField = required
49225 // valudField == required
49226 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49228 Roo.each(req, function(e) {
49229 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49230 throw "Roo.form.ComboCheck : missing value for: " + e;
49237 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49242 selectedClass: 'x-menu-item-checked',
49245 onRender : function(ct, position){
49251 var cls = 'x-combo-list';
49254 this.tpl = new Roo.Template({
49255 html : '<div class="'+cls+'-item x-menu-check-item">' +
49256 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49257 '<span>{' + this.displayField + '}</span>' +
49264 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49265 this.view.singleSelect = false;
49266 this.view.multiSelect = true;
49267 this.view.toggleSelect = true;
49268 this.pageTb.add(new Roo.Toolbar.Fill(), {
49271 handler: function()
49278 onViewOver : function(e, t){
49284 onViewClick : function(doFocus,index){
49288 select: function () {
49289 //Roo.log("SELECT CALLED");
49292 selectByValue : function(xv, scrollIntoView){
49293 var ar = this.getValueArray();
49296 Roo.each(ar, function(v) {
49297 if(v === undefined || v === null){
49300 var r = this.findRecord(this.valueField, v);
49302 sels.push(this.store.indexOf(r))
49306 this.view.select(sels);
49312 onSelect : function(record, index){
49313 // Roo.log("onselect Called");
49314 // this is only called by the clear button now..
49315 this.view.clearSelections();
49316 this.setValue('[]');
49317 if (this.value != this.valueBefore) {
49318 this.fireEvent('change', this, this.value, this.valueBefore);
49319 this.valueBefore = this.value;
49322 getValueArray : function()
49327 //Roo.log(this.value);
49328 if (typeof(this.value) == 'undefined') {
49331 var ar = Roo.decode(this.value);
49332 return ar instanceof Array ? ar : []; //?? valid?
49335 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49340 expand : function ()
49343 Roo.form.ComboCheck.superclass.expand.call(this);
49344 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49345 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49350 collapse : function(){
49351 Roo.form.ComboCheck.superclass.collapse.call(this);
49352 var sl = this.view.getSelectedIndexes();
49353 var st = this.store;
49357 Roo.each(sl, function(i) {
49359 nv.push(r.get(this.valueField));
49361 this.setValue(Roo.encode(nv));
49362 if (this.value != this.valueBefore) {
49364 this.fireEvent('change', this, this.value, this.valueBefore);
49365 this.valueBefore = this.value;
49370 setValue : function(v){
49374 var vals = this.getValueArray();
49376 Roo.each(vals, function(k) {
49377 var r = this.findRecord(this.valueField, k);
49379 tv.push(r.data[this.displayField]);
49380 }else if(this.valueNotFoundText !== undefined){
49381 tv.push( this.valueNotFoundText );
49386 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49387 this.hiddenField.value = v;
49393 * Ext JS Library 1.1.1
49394 * Copyright(c) 2006-2007, Ext JS, LLC.
49396 * Originally Released Under LGPL - original licence link has changed is not relivant.
49399 * <script type="text/javascript">
49403 * @class Roo.form.Signature
49404 * @extends Roo.form.Field
49408 * @param {Object} config Configuration options
49411 Roo.form.Signature = function(config){
49412 Roo.form.Signature.superclass.constructor.call(this, config);
49414 this.addEvents({// not in used??
49417 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49418 * @param {Roo.form.Signature} combo This combo box
49423 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49424 * @param {Roo.form.ComboBox} combo This combo box
49425 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49431 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49433 * @cfg {Object} labels Label to use when rendering a form.
49437 * confirm : "Confirm"
49442 confirm : "Confirm"
49445 * @cfg {Number} width The signature panel width (defaults to 300)
49449 * @cfg {Number} height The signature panel height (defaults to 100)
49453 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49455 allowBlank : false,
49458 // {Object} signPanel The signature SVG panel element (defaults to {})
49460 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49461 isMouseDown : false,
49462 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49463 isConfirmed : false,
49464 // {String} signatureTmp SVG mapping string (defaults to empty string)
49468 defaultAutoCreate : { // modified by initCompnoent..
49474 onRender : function(ct, position){
49476 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49478 this.wrap = this.el.wrap({
49479 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49482 this.createToolbar(this);
49483 this.signPanel = this.wrap.createChild({
49485 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49489 this.svgID = Roo.id();
49490 this.svgEl = this.signPanel.createChild({
49491 xmlns : 'http://www.w3.org/2000/svg',
49493 id : this.svgID + "-svg",
49495 height: this.height,
49496 viewBox: '0 0 '+this.width+' '+this.height,
49500 id: this.svgID + "-svg-r",
49502 height: this.height,
49507 id: this.svgID + "-svg-l",
49509 y1: (this.height*0.8), // start set the line in 80% of height
49510 x2: this.width, // end
49511 y2: (this.height*0.8), // end set the line in 80% of height
49513 'stroke-width': "1",
49514 'stroke-dasharray': "3",
49515 'shape-rendering': "crispEdges",
49516 'pointer-events': "none"
49520 id: this.svgID + "-svg-p",
49522 'stroke-width': "3",
49524 'pointer-events': 'none'
49529 this.svgBox = this.svgEl.dom.getScreenCTM();
49531 createSVG : function(){
49532 var svg = this.signPanel;
49533 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49536 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49537 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49538 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49539 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49540 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49541 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49542 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49545 isTouchEvent : function(e){
49546 return e.type.match(/^touch/);
49548 getCoords : function (e) {
49549 var pt = this.svgEl.dom.createSVGPoint();
49552 if (this.isTouchEvent(e)) {
49553 pt.x = e.targetTouches[0].clientX;
49554 pt.y = e.targetTouches[0].clientY;
49556 var a = this.svgEl.dom.getScreenCTM();
49557 var b = a.inverse();
49558 var mx = pt.matrixTransform(b);
49559 return mx.x + ',' + mx.y;
49561 //mouse event headler
49562 down : function (e) {
49563 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49564 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49566 this.isMouseDown = true;
49568 e.preventDefault();
49570 move : function (e) {
49571 if (this.isMouseDown) {
49572 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49573 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49576 e.preventDefault();
49578 up : function (e) {
49579 this.isMouseDown = false;
49580 var sp = this.signatureTmp.split(' ');
49583 if(!sp[sp.length-2].match(/^L/)){
49587 this.signatureTmp = sp.join(" ");
49590 if(this.getValue() != this.signatureTmp){
49591 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49592 this.isConfirmed = false;
49594 e.preventDefault();
49598 * Protected method that will not generally be called directly. It
49599 * is called when the editor creates its toolbar. Override this method if you need to
49600 * add custom toolbar buttons.
49601 * @param {HtmlEditor} editor
49603 createToolbar : function(editor){
49604 function btn(id, toggle, handler){
49605 var xid = fid + '-'+ id ;
49609 cls : 'x-btn-icon x-edit-'+id,
49610 enableToggle:toggle !== false,
49611 scope: editor, // was editor...
49612 handler:handler||editor.relayBtnCmd,
49613 clickEvent:'mousedown',
49614 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49620 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49624 cls : ' x-signature-btn x-signature-'+id,
49625 scope: editor, // was editor...
49626 handler: this.reset,
49627 clickEvent:'mousedown',
49628 text: this.labels.clear
49635 cls : ' x-signature-btn x-signature-'+id,
49636 scope: editor, // was editor...
49637 handler: this.confirmHandler,
49638 clickEvent:'mousedown',
49639 text: this.labels.confirm
49646 * when user is clicked confirm then show this image.....
49648 * @return {String} Image Data URI
49650 getImageDataURI : function(){
49651 var svg = this.svgEl.dom.parentNode.innerHTML;
49652 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49657 * @return {Boolean} this.isConfirmed
49659 getConfirmed : function(){
49660 return this.isConfirmed;
49664 * @return {Number} this.width
49666 getWidth : function(){
49671 * @return {Number} this.height
49673 getHeight : function(){
49674 return this.height;
49677 getSignature : function(){
49678 return this.signatureTmp;
49681 reset : function(){
49682 this.signatureTmp = '';
49683 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49684 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49685 this.isConfirmed = false;
49686 Roo.form.Signature.superclass.reset.call(this);
49688 setSignature : function(s){
49689 this.signatureTmp = s;
49690 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49691 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49693 this.isConfirmed = false;
49694 Roo.form.Signature.superclass.reset.call(this);
49697 // Roo.log(this.signPanel.dom.contentWindow.up())
49700 setConfirmed : function(){
49704 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49707 confirmHandler : function(){
49708 if(!this.getSignature()){
49712 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49713 this.setValue(this.getSignature());
49714 this.isConfirmed = true;
49716 this.fireEvent('confirm', this);
49719 // Subclasses should provide the validation implementation by overriding this
49720 validateValue : function(value){
49721 if(this.allowBlank){
49725 if(this.isConfirmed){
49732 * Ext JS Library 1.1.1
49733 * Copyright(c) 2006-2007, Ext JS, LLC.
49735 * Originally Released Under LGPL - original licence link has changed is not relivant.
49738 * <script type="text/javascript">
49743 * @class Roo.form.ComboBox
49744 * @extends Roo.form.TriggerField
49745 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49747 * Create a new ComboBox.
49748 * @param {Object} config Configuration options
49750 Roo.form.Select = function(config){
49751 Roo.form.Select.superclass.constructor.call(this, config);
49755 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49757 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49760 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49761 * rendering into an Roo.Editor, defaults to false)
49764 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49765 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49768 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49771 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49772 * the dropdown list (defaults to undefined, with no header element)
49776 * @cfg {String/Roo.Template} tpl The template to use to render the output
49780 defaultAutoCreate : {tag: "select" },
49782 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49784 listWidth: undefined,
49786 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49787 * mode = 'remote' or 'text' if mode = 'local')
49789 displayField: undefined,
49791 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49792 * mode = 'remote' or 'value' if mode = 'local').
49793 * Note: use of a valueField requires the user make a selection
49794 * in order for a value to be mapped.
49796 valueField: undefined,
49800 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49801 * field's data value (defaults to the underlying DOM element's name)
49803 hiddenName: undefined,
49805 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49809 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49811 selectedClass: 'x-combo-selected',
49813 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49814 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49815 * which displays a downward arrow icon).
49817 triggerClass : 'x-form-arrow-trigger',
49819 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49823 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49824 * anchor positions (defaults to 'tl-bl')
49826 listAlign: 'tl-bl?',
49828 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49832 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49833 * query specified by the allQuery config option (defaults to 'query')
49835 triggerAction: 'query',
49837 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49838 * (defaults to 4, does not apply if editable = false)
49842 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49843 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49847 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49848 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49852 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49853 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49857 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49858 * when editable = true (defaults to false)
49860 selectOnFocus:false,
49862 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49864 queryParam: 'query',
49866 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49867 * when mode = 'remote' (defaults to 'Loading...')
49869 loadingText: 'Loading...',
49871 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49875 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49879 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49880 * traditional select (defaults to true)
49884 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49888 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49892 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49893 * listWidth has a higher value)
49897 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49898 * allow the user to set arbitrary text into the field (defaults to false)
49900 forceSelection:false,
49902 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49903 * if typeAhead = true (defaults to 250)
49905 typeAheadDelay : 250,
49907 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49908 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49910 valueNotFoundText : undefined,
49913 * @cfg {String} defaultValue The value displayed after loading the store.
49918 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49920 blockFocus : false,
49923 * @cfg {Boolean} disableClear Disable showing of clear button.
49925 disableClear : false,
49927 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49929 alwaysQuery : false,
49935 // element that contains real text value.. (when hidden is used..)
49938 onRender : function(ct, position){
49939 Roo.form.Field.prototype.onRender.call(this, ct, position);
49942 this.store.on('beforeload', this.onBeforeLoad, this);
49943 this.store.on('load', this.onLoad, this);
49944 this.store.on('loadexception', this.onLoadException, this);
49945 this.store.load({});
49953 initEvents : function(){
49954 //Roo.form.ComboBox.superclass.initEvents.call(this);
49958 onDestroy : function(){
49961 this.store.un('beforeload', this.onBeforeLoad, this);
49962 this.store.un('load', this.onLoad, this);
49963 this.store.un('loadexception', this.onLoadException, this);
49965 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49969 fireKey : function(e){
49970 if(e.isNavKeyPress() && !this.list.isVisible()){
49971 this.fireEvent("specialkey", this, e);
49976 onResize: function(w, h){
49984 * Allow or prevent the user from directly editing the field text. If false is passed,
49985 * the user will only be able to select from the items defined in the dropdown list. This method
49986 * is the runtime equivalent of setting the 'editable' config option at config time.
49987 * @param {Boolean} value True to allow the user to directly edit the field text
49989 setEditable : function(value){
49994 onBeforeLoad : function(){
49996 Roo.log("Select before load");
49999 this.innerList.update(this.loadingText ?
50000 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50001 //this.restrictHeight();
50002 this.selectedIndex = -1;
50006 onLoad : function(){
50009 var dom = this.el.dom;
50010 dom.innerHTML = '';
50011 var od = dom.ownerDocument;
50013 if (this.emptyText) {
50014 var op = od.createElement('option');
50015 op.setAttribute('value', '');
50016 op.innerHTML = String.format('{0}', this.emptyText);
50017 dom.appendChild(op);
50019 if(this.store.getCount() > 0){
50021 var vf = this.valueField;
50022 var df = this.displayField;
50023 this.store.data.each(function(r) {
50024 // which colmsn to use... testing - cdoe / title..
50025 var op = od.createElement('option');
50026 op.setAttribute('value', r.data[vf]);
50027 op.innerHTML = String.format('{0}', r.data[df]);
50028 dom.appendChild(op);
50030 if (typeof(this.defaultValue != 'undefined')) {
50031 this.setValue(this.defaultValue);
50036 //this.onEmptyResults();
50041 onLoadException : function()
50043 dom.innerHTML = '';
50045 Roo.log("Select on load exception");
50049 Roo.log(this.store.reader.jsonData);
50050 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50051 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50057 onTypeAhead : function(){
50062 onSelect : function(record, index){
50063 Roo.log('on select?');
50065 if(this.fireEvent('beforeselect', this, record, index) !== false){
50066 this.setFromData(index > -1 ? record.data : false);
50068 this.fireEvent('select', this, record, index);
50073 * Returns the currently selected field value or empty string if no value is set.
50074 * @return {String} value The selected value
50076 getValue : function(){
50077 var dom = this.el.dom;
50078 this.value = dom.options[dom.selectedIndex].value;
50084 * Clears any text/value currently set in the field
50086 clearValue : function(){
50088 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50093 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50094 * will be displayed in the field. If the value does not match the data value of an existing item,
50095 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50096 * Otherwise the field will be blank (although the value will still be set).
50097 * @param {String} value The value to match
50099 setValue : function(v){
50100 var d = this.el.dom;
50101 for (var i =0; i < d.options.length;i++) {
50102 if (v == d.options[i].value) {
50103 d.selectedIndex = i;
50111 * @property {Object} the last set data for the element
50116 * Sets the value of the field based on a object which is related to the record format for the store.
50117 * @param {Object} value the value to set as. or false on reset?
50119 setFromData : function(o){
50120 Roo.log('setfrom data?');
50126 reset : function(){
50130 findRecord : function(prop, value){
50135 if(this.store.getCount() > 0){
50136 this.store.each(function(r){
50137 if(r.data[prop] == value){
50147 getName: function()
50149 // returns hidden if it's set..
50150 if (!this.rendered) {return ''};
50151 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50159 onEmptyResults : function(){
50160 Roo.log('empty results');
50165 * Returns true if the dropdown list is expanded, else false.
50167 isExpanded : function(){
50172 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50173 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50174 * @param {String} value The data value of the item to select
50175 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50176 * selected item if it is not currently in view (defaults to true)
50177 * @return {Boolean} True if the value matched an item in the list, else false
50179 selectByValue : function(v, scrollIntoView){
50180 Roo.log('select By Value');
50183 if(v !== undefined && v !== null){
50184 var r = this.findRecord(this.valueField || this.displayField, v);
50186 this.select(this.store.indexOf(r), scrollIntoView);
50194 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50195 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50196 * @param {Number} index The zero-based index of the list item to select
50197 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50198 * selected item if it is not currently in view (defaults to true)
50200 select : function(index, scrollIntoView){
50201 Roo.log('select ');
50204 this.selectedIndex = index;
50205 this.view.select(index);
50206 if(scrollIntoView !== false){
50207 var el = this.view.getNode(index);
50209 this.innerList.scrollChildIntoView(el, false);
50217 validateBlur : function(){
50224 initQuery : function(){
50225 this.doQuery(this.getRawValue());
50229 doForce : function(){
50230 if(this.el.dom.value.length > 0){
50231 this.el.dom.value =
50232 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50238 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50239 * query allowing the query action to be canceled if needed.
50240 * @param {String} query The SQL query to execute
50241 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50242 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50243 * saved in the current store (defaults to false)
50245 doQuery : function(q, forceAll){
50247 Roo.log('doQuery?');
50248 if(q === undefined || q === null){
50253 forceAll: forceAll,
50257 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50261 forceAll = qe.forceAll;
50262 if(forceAll === true || (q.length >= this.minChars)){
50263 if(this.lastQuery != q || this.alwaysQuery){
50264 this.lastQuery = q;
50265 if(this.mode == 'local'){
50266 this.selectedIndex = -1;
50268 this.store.clearFilter();
50270 this.store.filter(this.displayField, q);
50274 this.store.baseParams[this.queryParam] = q;
50276 params: this.getParams(q)
50281 this.selectedIndex = -1;
50288 getParams : function(q){
50290 //p[this.queryParam] = q;
50293 p.limit = this.pageSize;
50299 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50301 collapse : function(){
50306 collapseIf : function(e){
50311 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50313 expand : function(){
50321 * @cfg {Boolean} grow
50325 * @cfg {Number} growMin
50329 * @cfg {Number} growMax
50337 setWidth : function()
50341 getResizeEl : function(){
50344 });//<script type="text/javasscript">
50348 * @class Roo.DDView
50349 * A DnD enabled version of Roo.View.
50350 * @param {Element/String} container The Element in which to create the View.
50351 * @param {String} tpl The template string used to create the markup for each element of the View
50352 * @param {Object} config The configuration properties. These include all the config options of
50353 * {@link Roo.View} plus some specific to this class.<br>
50355 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50356 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50358 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50359 .x-view-drag-insert-above {
50360 border-top:1px dotted #3366cc;
50362 .x-view-drag-insert-below {
50363 border-bottom:1px dotted #3366cc;
50369 Roo.DDView = function(container, tpl, config) {
50370 Roo.DDView.superclass.constructor.apply(this, arguments);
50371 this.getEl().setStyle("outline", "0px none");
50372 this.getEl().unselectable();
50373 if (this.dragGroup) {
50374 this.setDraggable(this.dragGroup.split(","));
50376 if (this.dropGroup) {
50377 this.setDroppable(this.dropGroup.split(","));
50379 if (this.deletable) {
50380 this.setDeletable();
50382 this.isDirtyFlag = false;
50388 Roo.extend(Roo.DDView, Roo.View, {
50389 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50390 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50391 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50392 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50396 reset: Roo.emptyFn,
50398 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50400 validate: function() {
50404 destroy: function() {
50405 this.purgeListeners();
50406 this.getEl.removeAllListeners();
50407 this.getEl().remove();
50408 if (this.dragZone) {
50409 if (this.dragZone.destroy) {
50410 this.dragZone.destroy();
50413 if (this.dropZone) {
50414 if (this.dropZone.destroy) {
50415 this.dropZone.destroy();
50420 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50421 getName: function() {
50425 /** Loads the View from a JSON string representing the Records to put into the Store. */
50426 setValue: function(v) {
50428 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50431 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50432 this.store.proxy = new Roo.data.MemoryProxy(data);
50436 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50437 getValue: function() {
50439 this.store.each(function(rec) {
50440 result += rec.id + ',';
50442 return result.substr(0, result.length - 1) + ')';
50445 getIds: function() {
50446 var i = 0, result = new Array(this.store.getCount());
50447 this.store.each(function(rec) {
50448 result[i++] = rec.id;
50453 isDirty: function() {
50454 return this.isDirtyFlag;
50458 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50459 * whole Element becomes the target, and this causes the drop gesture to append.
50461 getTargetFromEvent : function(e) {
50462 var target = e.getTarget();
50463 while ((target !== null) && (target.parentNode != this.el.dom)) {
50464 target = target.parentNode;
50467 target = this.el.dom.lastChild || this.el.dom;
50473 * Create the drag data which consists of an object which has the property "ddel" as
50474 * the drag proxy element.
50476 getDragData : function(e) {
50477 var target = this.findItemFromChild(e.getTarget());
50479 this.handleSelection(e);
50480 var selNodes = this.getSelectedNodes();
50483 copy: this.copy || (this.allowCopy && e.ctrlKey),
50487 var selectedIndices = this.getSelectedIndexes();
50488 for (var i = 0; i < selectedIndices.length; i++) {
50489 dragData.records.push(this.store.getAt(selectedIndices[i]));
50491 if (selNodes.length == 1) {
50492 dragData.ddel = target.cloneNode(true); // the div element
50494 var div = document.createElement('div'); // create the multi element drag "ghost"
50495 div.className = 'multi-proxy';
50496 for (var i = 0, len = selNodes.length; i < len; i++) {
50497 div.appendChild(selNodes[i].cloneNode(true));
50499 dragData.ddel = div;
50501 //console.log(dragData)
50502 //console.log(dragData.ddel.innerHTML)
50505 //console.log('nodragData')
50509 /** Specify to which ddGroup items in this DDView may be dragged. */
50510 setDraggable: function(ddGroup) {
50511 if (ddGroup instanceof Array) {
50512 Roo.each(ddGroup, this.setDraggable, this);
50515 if (this.dragZone) {
50516 this.dragZone.addToGroup(ddGroup);
50518 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50519 containerScroll: true,
50523 // Draggability implies selection. DragZone's mousedown selects the element.
50524 if (!this.multiSelect) { this.singleSelect = true; }
50526 // Wire the DragZone's handlers up to methods in *this*
50527 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50531 /** Specify from which ddGroup this DDView accepts drops. */
50532 setDroppable: function(ddGroup) {
50533 if (ddGroup instanceof Array) {
50534 Roo.each(ddGroup, this.setDroppable, this);
50537 if (this.dropZone) {
50538 this.dropZone.addToGroup(ddGroup);
50540 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50541 containerScroll: true,
50545 // Wire the DropZone's handlers up to methods in *this*
50546 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50547 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50548 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50549 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50550 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50554 /** Decide whether to drop above or below a View node. */
50555 getDropPoint : function(e, n, dd){
50556 if (n == this.el.dom) { return "above"; }
50557 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50558 var c = t + (b - t) / 2;
50559 var y = Roo.lib.Event.getPageY(e);
50567 onNodeEnter : function(n, dd, e, data){
50571 onNodeOver : function(n, dd, e, data){
50572 var pt = this.getDropPoint(e, n, dd);
50573 // set the insert point style on the target node
50574 var dragElClass = this.dropNotAllowed;
50577 if (pt == "above"){
50578 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50579 targetElClass = "x-view-drag-insert-above";
50581 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50582 targetElClass = "x-view-drag-insert-below";
50584 if (this.lastInsertClass != targetElClass){
50585 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50586 this.lastInsertClass = targetElClass;
50589 return dragElClass;
50592 onNodeOut : function(n, dd, e, data){
50593 this.removeDropIndicators(n);
50596 onNodeDrop : function(n, dd, e, data){
50597 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50600 var pt = this.getDropPoint(e, n, dd);
50601 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50602 if (pt == "below") { insertAt++; }
50603 for (var i = 0; i < data.records.length; i++) {
50604 var r = data.records[i];
50605 var dup = this.store.getById(r.id);
50606 if (dup && (dd != this.dragZone)) {
50607 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50610 this.store.insert(insertAt++, r.copy());
50612 data.source.isDirtyFlag = true;
50614 this.store.insert(insertAt++, r);
50616 this.isDirtyFlag = true;
50619 this.dragZone.cachedTarget = null;
50623 removeDropIndicators : function(n){
50625 Roo.fly(n).removeClass([
50626 "x-view-drag-insert-above",
50627 "x-view-drag-insert-below"]);
50628 this.lastInsertClass = "_noclass";
50633 * Utility method. Add a delete option to the DDView's context menu.
50634 * @param {String} imageUrl The URL of the "delete" icon image.
50636 setDeletable: function(imageUrl) {
50637 if (!this.singleSelect && !this.multiSelect) {
50638 this.singleSelect = true;
50640 var c = this.getContextMenu();
50641 this.contextMenu.on("itemclick", function(item) {
50644 this.remove(this.getSelectedIndexes());
50648 this.contextMenu.add({
50655 /** Return the context menu for this DDView. */
50656 getContextMenu: function() {
50657 if (!this.contextMenu) {
50658 // Create the View's context menu
50659 this.contextMenu = new Roo.menu.Menu({
50660 id: this.id + "-contextmenu"
50662 this.el.on("contextmenu", this.showContextMenu, this);
50664 return this.contextMenu;
50667 disableContextMenu: function() {
50668 if (this.contextMenu) {
50669 this.el.un("contextmenu", this.showContextMenu, this);
50673 showContextMenu: function(e, item) {
50674 item = this.findItemFromChild(e.getTarget());
50677 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50678 this.contextMenu.showAt(e.getXY());
50683 * Remove {@link Roo.data.Record}s at the specified indices.
50684 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50686 remove: function(selectedIndices) {
50687 selectedIndices = [].concat(selectedIndices);
50688 for (var i = 0; i < selectedIndices.length; i++) {
50689 var rec = this.store.getAt(selectedIndices[i]);
50690 this.store.remove(rec);
50695 * Double click fires the event, but also, if this is draggable, and there is only one other
50696 * related DropZone, it transfers the selected node.
50698 onDblClick : function(e){
50699 var item = this.findItemFromChild(e.getTarget());
50701 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50704 if (this.dragGroup) {
50705 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50706 while (targets.indexOf(this.dropZone) > -1) {
50707 targets.remove(this.dropZone);
50709 if (targets.length == 1) {
50710 this.dragZone.cachedTarget = null;
50711 var el = Roo.get(targets[0].getEl());
50712 var box = el.getBox(true);
50713 targets[0].onNodeDrop(el.dom, {
50715 xy: [box.x, box.y + box.height - 1]
50716 }, null, this.getDragData(e));
50722 handleSelection: function(e) {
50723 this.dragZone.cachedTarget = null;
50724 var item = this.findItemFromChild(e.getTarget());
50726 this.clearSelections(true);
50729 if (item && (this.multiSelect || this.singleSelect)){
50730 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50731 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50732 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50733 this.unselect(item);
50735 this.select(item, this.multiSelect && e.ctrlKey);
50736 this.lastSelection = item;
50741 onItemClick : function(item, index, e){
50742 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50748 unselect : function(nodeInfo, suppressEvent){
50749 var node = this.getNode(nodeInfo);
50750 if(node && this.isSelected(node)){
50751 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50752 Roo.fly(node).removeClass(this.selectedClass);
50753 this.selections.remove(node);
50754 if(!suppressEvent){
50755 this.fireEvent("selectionchange", this, this.selections);
50763 * Ext JS Library 1.1.1
50764 * Copyright(c) 2006-2007, Ext JS, LLC.
50766 * Originally Released Under LGPL - original licence link has changed is not relivant.
50769 * <script type="text/javascript">
50773 * @class Roo.LayoutManager
50774 * @extends Roo.util.Observable
50775 * Base class for layout managers.
50777 Roo.LayoutManager = function(container, config){
50778 Roo.LayoutManager.superclass.constructor.call(this);
50779 this.el = Roo.get(container);
50780 // ie scrollbar fix
50781 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50782 document.body.scroll = "no";
50783 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50784 this.el.position('relative');
50786 this.id = this.el.id;
50787 this.el.addClass("x-layout-container");
50788 /** false to disable window resize monitoring @type Boolean */
50789 this.monitorWindowResize = true;
50794 * Fires when a layout is performed.
50795 * @param {Roo.LayoutManager} this
50799 * @event regionresized
50800 * Fires when the user resizes a region.
50801 * @param {Roo.LayoutRegion} region The resized region
50802 * @param {Number} newSize The new size (width for east/west, height for north/south)
50804 "regionresized" : true,
50806 * @event regioncollapsed
50807 * Fires when a region is collapsed.
50808 * @param {Roo.LayoutRegion} region The collapsed region
50810 "regioncollapsed" : true,
50812 * @event regionexpanded
50813 * Fires when a region is expanded.
50814 * @param {Roo.LayoutRegion} region The expanded region
50816 "regionexpanded" : true
50818 this.updating = false;
50819 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50822 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50824 * Returns true if this layout is currently being updated
50825 * @return {Boolean}
50827 isUpdating : function(){
50828 return this.updating;
50832 * Suspend the LayoutManager from doing auto-layouts while
50833 * making multiple add or remove calls
50835 beginUpdate : function(){
50836 this.updating = true;
50840 * Restore auto-layouts and optionally disable the manager from performing a layout
50841 * @param {Boolean} noLayout true to disable a layout update
50843 endUpdate : function(noLayout){
50844 this.updating = false;
50850 layout: function(){
50854 onRegionResized : function(region, newSize){
50855 this.fireEvent("regionresized", region, newSize);
50859 onRegionCollapsed : function(region){
50860 this.fireEvent("regioncollapsed", region);
50863 onRegionExpanded : function(region){
50864 this.fireEvent("regionexpanded", region);
50868 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50869 * performs box-model adjustments.
50870 * @return {Object} The size as an object {width: (the width), height: (the height)}
50872 getViewSize : function(){
50874 if(this.el.dom != document.body){
50875 size = this.el.getSize();
50877 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50879 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50880 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50885 * Returns the Element this layout is bound to.
50886 * @return {Roo.Element}
50888 getEl : function(){
50893 * Returns the specified region.
50894 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50895 * @return {Roo.LayoutRegion}
50897 getRegion : function(target){
50898 return this.regions[target.toLowerCase()];
50901 onWindowResize : function(){
50902 if(this.monitorWindowResize){
50908 * Ext JS Library 1.1.1
50909 * Copyright(c) 2006-2007, Ext JS, LLC.
50911 * Originally Released Under LGPL - original licence link has changed is not relivant.
50914 * <script type="text/javascript">
50917 * @class Roo.BorderLayout
50918 * @extends Roo.LayoutManager
50919 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50920 * please see: <br><br>
50921 * <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>
50922 * <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>
50925 var layout = new Roo.BorderLayout(document.body, {
50959 preferredTabWidth: 150
50964 var CP = Roo.ContentPanel;
50966 layout.beginUpdate();
50967 layout.add("north", new CP("north", "North"));
50968 layout.add("south", new CP("south", {title: "South", closable: true}));
50969 layout.add("west", new CP("west", {title: "West"}));
50970 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50971 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50972 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50973 layout.getRegion("center").showPanel("center1");
50974 layout.endUpdate();
50977 <b>The container the layout is rendered into can be either the body element or any other element.
50978 If it is not the body element, the container needs to either be an absolute positioned element,
50979 or you will need to add "position:relative" to the css of the container. You will also need to specify
50980 the container size if it is not the body element.</b>
50983 * Create a new BorderLayout
50984 * @param {String/HTMLElement/Element} container The container this layout is bound to
50985 * @param {Object} config Configuration options
50987 Roo.BorderLayout = function(container, config){
50988 config = config || {};
50989 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50990 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50991 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50992 var target = this.factory.validRegions[i];
50993 if(config[target]){
50994 this.addRegion(target, config[target]);
50999 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51001 * Creates and adds a new region if it doesn't already exist.
51002 * @param {String} target The target region key (north, south, east, west or center).
51003 * @param {Object} config The regions config object
51004 * @return {BorderLayoutRegion} The new region
51006 addRegion : function(target, config){
51007 if(!this.regions[target]){
51008 var r = this.factory.create(target, this, config);
51009 this.bindRegion(target, r);
51011 return this.regions[target];
51015 bindRegion : function(name, r){
51016 this.regions[name] = r;
51017 r.on("visibilitychange", this.layout, this);
51018 r.on("paneladded", this.layout, this);
51019 r.on("panelremoved", this.layout, this);
51020 r.on("invalidated", this.layout, this);
51021 r.on("resized", this.onRegionResized, this);
51022 r.on("collapsed", this.onRegionCollapsed, this);
51023 r.on("expanded", this.onRegionExpanded, this);
51027 * Performs a layout update.
51029 layout : function(){
51030 if(this.updating) {
51033 var size = this.getViewSize();
51034 var w = size.width;
51035 var h = size.height;
51040 //var x = 0, y = 0;
51042 var rs = this.regions;
51043 var north = rs["north"];
51044 var south = rs["south"];
51045 var west = rs["west"];
51046 var east = rs["east"];
51047 var center = rs["center"];
51048 //if(this.hideOnLayout){ // not supported anymore
51049 //c.el.setStyle("display", "none");
51051 if(north && north.isVisible()){
51052 var b = north.getBox();
51053 var m = north.getMargins();
51054 b.width = w - (m.left+m.right);
51057 centerY = b.height + b.y + m.bottom;
51058 centerH -= centerY;
51059 north.updateBox(this.safeBox(b));
51061 if(south && south.isVisible()){
51062 var b = south.getBox();
51063 var m = south.getMargins();
51064 b.width = w - (m.left+m.right);
51066 var totalHeight = (b.height + m.top + m.bottom);
51067 b.y = h - totalHeight + m.top;
51068 centerH -= totalHeight;
51069 south.updateBox(this.safeBox(b));
51071 if(west && west.isVisible()){
51072 var b = west.getBox();
51073 var m = west.getMargins();
51074 b.height = centerH - (m.top+m.bottom);
51076 b.y = centerY + m.top;
51077 var totalWidth = (b.width + m.left + m.right);
51078 centerX += totalWidth;
51079 centerW -= totalWidth;
51080 west.updateBox(this.safeBox(b));
51082 if(east && east.isVisible()){
51083 var b = east.getBox();
51084 var m = east.getMargins();
51085 b.height = centerH - (m.top+m.bottom);
51086 var totalWidth = (b.width + m.left + m.right);
51087 b.x = w - totalWidth + m.left;
51088 b.y = centerY + m.top;
51089 centerW -= totalWidth;
51090 east.updateBox(this.safeBox(b));
51093 var m = center.getMargins();
51095 x: centerX + m.left,
51096 y: centerY + m.top,
51097 width: centerW - (m.left+m.right),
51098 height: centerH - (m.top+m.bottom)
51100 //if(this.hideOnLayout){
51101 //center.el.setStyle("display", "block");
51103 center.updateBox(this.safeBox(centerBox));
51106 this.fireEvent("layout", this);
51110 safeBox : function(box){
51111 box.width = Math.max(0, box.width);
51112 box.height = Math.max(0, box.height);
51117 * Adds a ContentPanel (or subclass) to this layout.
51118 * @param {String} target The target region key (north, south, east, west or center).
51119 * @param {Roo.ContentPanel} panel The panel to add
51120 * @return {Roo.ContentPanel} The added panel
51122 add : function(target, panel){
51124 target = target.toLowerCase();
51125 return this.regions[target].add(panel);
51129 * Remove a ContentPanel (or subclass) to this layout.
51130 * @param {String} target The target region key (north, south, east, west or center).
51131 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51132 * @return {Roo.ContentPanel} The removed panel
51134 remove : function(target, panel){
51135 target = target.toLowerCase();
51136 return this.regions[target].remove(panel);
51140 * Searches all regions for a panel with the specified id
51141 * @param {String} panelId
51142 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51144 findPanel : function(panelId){
51145 var rs = this.regions;
51146 for(var target in rs){
51147 if(typeof rs[target] != "function"){
51148 var p = rs[target].getPanel(panelId);
51158 * Searches all regions for a panel with the specified id and activates (shows) it.
51159 * @param {String/ContentPanel} panelId The panels id or the panel itself
51160 * @return {Roo.ContentPanel} The shown panel or null
51162 showPanel : function(panelId) {
51163 var rs = this.regions;
51164 for(var target in rs){
51165 var r = rs[target];
51166 if(typeof r != "function"){
51167 if(r.hasPanel(panelId)){
51168 return r.showPanel(panelId);
51176 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51177 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51179 restoreState : function(provider){
51181 provider = Roo.state.Manager;
51183 var sm = new Roo.LayoutStateManager();
51184 sm.init(this, provider);
51188 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51189 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51190 * a valid ContentPanel config object. Example:
51192 // Create the main layout
51193 var layout = new Roo.BorderLayout('main-ct', {
51204 // Create and add multiple ContentPanels at once via configs
51207 id: 'source-files',
51209 title:'Ext Source Files',
51222 * @param {Object} regions An object containing ContentPanel configs by region name
51224 batchAdd : function(regions){
51225 this.beginUpdate();
51226 for(var rname in regions){
51227 var lr = this.regions[rname];
51229 this.addTypedPanels(lr, regions[rname]);
51236 addTypedPanels : function(lr, ps){
51237 if(typeof ps == 'string'){
51238 lr.add(new Roo.ContentPanel(ps));
51240 else if(ps instanceof Array){
51241 for(var i =0, len = ps.length; i < len; i++){
51242 this.addTypedPanels(lr, ps[i]);
51245 else if(!ps.events){ // raw config?
51247 delete ps.el; // prevent conflict
51248 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51250 else { // panel object assumed!
51255 * Adds a xtype elements to the layout.
51259 xtype : 'ContentPanel',
51266 xtype : 'NestedLayoutPanel',
51272 items : [ ... list of content panels or nested layout panels.. ]
51276 * @param {Object} cfg Xtype definition of item to add.
51278 addxtype : function(cfg)
51280 // basically accepts a pannel...
51281 // can accept a layout region..!?!?
51282 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51284 if (!cfg.xtype.match(/Panel$/)) {
51289 if (typeof(cfg.region) == 'undefined') {
51290 Roo.log("Failed to add Panel, region was not set");
51294 var region = cfg.region;
51300 xitems = cfg.items;
51307 case 'ContentPanel': // ContentPanel (el, cfg)
51308 case 'ScrollPanel': // ContentPanel (el, cfg)
51310 if(cfg.autoCreate) {
51311 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51313 var el = this.el.createChild();
51314 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51317 this.add(region, ret);
51321 case 'TreePanel': // our new panel!
51322 cfg.el = this.el.createChild();
51323 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51324 this.add(region, ret);
51327 case 'NestedLayoutPanel':
51328 // create a new Layout (which is a Border Layout...
51329 var el = this.el.createChild();
51330 var clayout = cfg.layout;
51332 clayout.items = clayout.items || [];
51333 // replace this exitems with the clayout ones..
51334 xitems = clayout.items;
51337 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51338 cfg.background = false;
51340 var layout = new Roo.BorderLayout(el, clayout);
51342 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51343 //console.log('adding nested layout panel ' + cfg.toSource());
51344 this.add(region, ret);
51345 nb = {}; /// find first...
51350 // needs grid and region
51352 //var el = this.getRegion(region).el.createChild();
51353 var el = this.el.createChild();
51354 // create the grid first...
51356 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51358 if (region == 'center' && this.active ) {
51359 cfg.background = false;
51361 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51363 this.add(region, ret);
51364 if (cfg.background) {
51365 ret.on('activate', function(gp) {
51366 if (!gp.grid.rendered) {
51381 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51383 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51384 this.add(region, ret);
51387 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51391 // GridPanel (grid, cfg)
51394 this.beginUpdate();
51398 Roo.each(xitems, function(i) {
51399 region = nb && i.region ? i.region : false;
51401 var add = ret.addxtype(i);
51404 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51405 if (!i.background) {
51406 abn[region] = nb[region] ;
51413 // make the last non-background panel active..
51414 //if (nb) { Roo.log(abn); }
51417 for(var r in abn) {
51418 region = this.getRegion(r);
51420 // tried using nb[r], but it does not work..
51422 region.showPanel(abn[r]);
51433 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51434 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51435 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51436 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51439 var CP = Roo.ContentPanel;
51441 var layout = Roo.BorderLayout.create({
51445 panels: [new CP("north", "North")]
51454 panels: [new CP("west", {title: "West"})]
51463 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51472 panels: [new CP("south", {title: "South", closable: true})]
51479 preferredTabWidth: 150,
51481 new CP("center1", {title: "Close Me", closable: true}),
51482 new CP("center2", {title: "Center Panel", closable: false})
51487 layout.getRegion("center").showPanel("center1");
51492 Roo.BorderLayout.create = function(config, targetEl){
51493 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51494 layout.beginUpdate();
51495 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51496 for(var j = 0, jlen = regions.length; j < jlen; j++){
51497 var lr = regions[j];
51498 if(layout.regions[lr] && config[lr].panels){
51499 var r = layout.regions[lr];
51500 var ps = config[lr].panels;
51501 layout.addTypedPanels(r, ps);
51504 layout.endUpdate();
51509 Roo.BorderLayout.RegionFactory = {
51511 validRegions : ["north","south","east","west","center"],
51514 create : function(target, mgr, config){
51515 target = target.toLowerCase();
51516 if(config.lightweight || config.basic){
51517 return new Roo.BasicLayoutRegion(mgr, config, target);
51521 return new Roo.NorthLayoutRegion(mgr, config);
51523 return new Roo.SouthLayoutRegion(mgr, config);
51525 return new Roo.EastLayoutRegion(mgr, config);
51527 return new Roo.WestLayoutRegion(mgr, config);
51529 return new Roo.CenterLayoutRegion(mgr, config);
51531 throw 'Layout region "'+target+'" not supported.';
51535 * Ext JS Library 1.1.1
51536 * Copyright(c) 2006-2007, Ext JS, LLC.
51538 * Originally Released Under LGPL - original licence link has changed is not relivant.
51541 * <script type="text/javascript">
51545 * @class Roo.BasicLayoutRegion
51546 * @extends Roo.util.Observable
51547 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51548 * and does not have a titlebar, tabs or any other features. All it does is size and position
51549 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51551 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51553 this.position = pos;
51556 * @scope Roo.BasicLayoutRegion
51560 * @event beforeremove
51561 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51562 * @param {Roo.LayoutRegion} this
51563 * @param {Roo.ContentPanel} panel The panel
51564 * @param {Object} e The cancel event object
51566 "beforeremove" : true,
51568 * @event invalidated
51569 * Fires when the layout for this region is changed.
51570 * @param {Roo.LayoutRegion} this
51572 "invalidated" : true,
51574 * @event visibilitychange
51575 * Fires when this region is shown or hidden
51576 * @param {Roo.LayoutRegion} this
51577 * @param {Boolean} visibility true or false
51579 "visibilitychange" : true,
51581 * @event paneladded
51582 * Fires when a panel is added.
51583 * @param {Roo.LayoutRegion} this
51584 * @param {Roo.ContentPanel} panel The panel
51586 "paneladded" : true,
51588 * @event panelremoved
51589 * Fires when a panel is removed.
51590 * @param {Roo.LayoutRegion} this
51591 * @param {Roo.ContentPanel} panel The panel
51593 "panelremoved" : true,
51595 * @event beforecollapse
51596 * Fires when this region before collapse.
51597 * @param {Roo.LayoutRegion} this
51599 "beforecollapse" : true,
51602 * Fires when this region is collapsed.
51603 * @param {Roo.LayoutRegion} this
51605 "collapsed" : true,
51608 * Fires when this region is expanded.
51609 * @param {Roo.LayoutRegion} this
51614 * Fires when this region is slid into view.
51615 * @param {Roo.LayoutRegion} this
51617 "slideshow" : true,
51620 * Fires when this region slides out of view.
51621 * @param {Roo.LayoutRegion} this
51623 "slidehide" : true,
51625 * @event panelactivated
51626 * Fires when a panel is activated.
51627 * @param {Roo.LayoutRegion} this
51628 * @param {Roo.ContentPanel} panel The activated panel
51630 "panelactivated" : true,
51633 * Fires when the user resizes this region.
51634 * @param {Roo.LayoutRegion} this
51635 * @param {Number} newSize The new size (width for east/west, height for north/south)
51639 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51640 this.panels = new Roo.util.MixedCollection();
51641 this.panels.getKey = this.getPanelId.createDelegate(this);
51643 this.activePanel = null;
51644 // ensure listeners are added...
51646 if (config.listeners || config.events) {
51647 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51648 listeners : config.listeners || {},
51649 events : config.events || {}
51653 if(skipConfig !== true){
51654 this.applyConfig(config);
51658 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51659 getPanelId : function(p){
51663 applyConfig : function(config){
51664 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51665 this.config = config;
51670 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51671 * the width, for horizontal (north, south) the height.
51672 * @param {Number} newSize The new width or height
51674 resizeTo : function(newSize){
51675 var el = this.el ? this.el :
51676 (this.activePanel ? this.activePanel.getEl() : null);
51678 switch(this.position){
51681 el.setWidth(newSize);
51682 this.fireEvent("resized", this, newSize);
51686 el.setHeight(newSize);
51687 this.fireEvent("resized", this, newSize);
51693 getBox : function(){
51694 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51697 getMargins : function(){
51698 return this.margins;
51701 updateBox : function(box){
51703 var el = this.activePanel.getEl();
51704 el.dom.style.left = box.x + "px";
51705 el.dom.style.top = box.y + "px";
51706 this.activePanel.setSize(box.width, box.height);
51710 * Returns the container element for this region.
51711 * @return {Roo.Element}
51713 getEl : function(){
51714 return this.activePanel;
51718 * Returns true if this region is currently visible.
51719 * @return {Boolean}
51721 isVisible : function(){
51722 return this.activePanel ? true : false;
51725 setActivePanel : function(panel){
51726 panel = this.getPanel(panel);
51727 if(this.activePanel && this.activePanel != panel){
51728 this.activePanel.setActiveState(false);
51729 this.activePanel.getEl().setLeftTop(-10000,-10000);
51731 this.activePanel = panel;
51732 panel.setActiveState(true);
51734 panel.setSize(this.box.width, this.box.height);
51736 this.fireEvent("panelactivated", this, panel);
51737 this.fireEvent("invalidated");
51741 * Show the specified panel.
51742 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51743 * @return {Roo.ContentPanel} The shown panel or null
51745 showPanel : function(panel){
51746 if(panel = this.getPanel(panel)){
51747 this.setActivePanel(panel);
51753 * Get the active panel for this region.
51754 * @return {Roo.ContentPanel} The active panel or null
51756 getActivePanel : function(){
51757 return this.activePanel;
51761 * Add the passed ContentPanel(s)
51762 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51763 * @return {Roo.ContentPanel} The panel added (if only one was added)
51765 add : function(panel){
51766 if(arguments.length > 1){
51767 for(var i = 0, len = arguments.length; i < len; i++) {
51768 this.add(arguments[i]);
51772 if(this.hasPanel(panel)){
51773 this.showPanel(panel);
51776 var el = panel.getEl();
51777 if(el.dom.parentNode != this.mgr.el.dom){
51778 this.mgr.el.dom.appendChild(el.dom);
51780 if(panel.setRegion){
51781 panel.setRegion(this);
51783 this.panels.add(panel);
51784 el.setStyle("position", "absolute");
51785 if(!panel.background){
51786 this.setActivePanel(panel);
51787 if(this.config.initialSize && this.panels.getCount()==1){
51788 this.resizeTo(this.config.initialSize);
51791 this.fireEvent("paneladded", this, panel);
51796 * Returns true if the panel is in this region.
51797 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51798 * @return {Boolean}
51800 hasPanel : function(panel){
51801 if(typeof panel == "object"){ // must be panel obj
51802 panel = panel.getId();
51804 return this.getPanel(panel) ? true : false;
51808 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51809 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51810 * @param {Boolean} preservePanel Overrides the config preservePanel option
51811 * @return {Roo.ContentPanel} The panel that was removed
51813 remove : function(panel, preservePanel){
51814 panel = this.getPanel(panel);
51819 this.fireEvent("beforeremove", this, panel, e);
51820 if(e.cancel === true){
51823 var panelId = panel.getId();
51824 this.panels.removeKey(panelId);
51829 * Returns the panel specified or null if it's not in this region.
51830 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51831 * @return {Roo.ContentPanel}
51833 getPanel : function(id){
51834 if(typeof id == "object"){ // must be panel obj
51837 return this.panels.get(id);
51841 * Returns this regions position (north/south/east/west/center).
51844 getPosition: function(){
51845 return this.position;
51849 * Ext JS Library 1.1.1
51850 * Copyright(c) 2006-2007, Ext JS, LLC.
51852 * Originally Released Under LGPL - original licence link has changed is not relivant.
51855 * <script type="text/javascript">
51859 * @class Roo.LayoutRegion
51860 * @extends Roo.BasicLayoutRegion
51861 * This class represents a region in a layout manager.
51862 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51863 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51864 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51865 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51866 * @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})
51867 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51868 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51869 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51870 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51871 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51872 * @cfg {String} title The title for the region (overrides panel titles)
51873 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51874 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51875 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51876 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51877 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51878 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51879 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51880 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51881 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51882 * @cfg {Boolean} showPin True to show a pin button
51883 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51884 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51885 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51886 * @cfg {Number} width For East/West panels
51887 * @cfg {Number} height For North/South panels
51888 * @cfg {Boolean} split To show the splitter
51889 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51891 Roo.LayoutRegion = function(mgr, config, pos){
51892 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51893 var dh = Roo.DomHelper;
51894 /** This region's container element
51895 * @type Roo.Element */
51896 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51897 /** This region's title element
51898 * @type Roo.Element */
51900 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51901 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51902 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51904 this.titleEl.enableDisplayMode();
51905 /** This region's title text element
51906 * @type HTMLElement */
51907 this.titleTextEl = this.titleEl.dom.firstChild;
51908 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51909 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51910 this.closeBtn.enableDisplayMode();
51911 this.closeBtn.on("click", this.closeClicked, this);
51912 this.closeBtn.hide();
51914 this.createBody(config);
51915 this.visible = true;
51916 this.collapsed = false;
51918 if(config.hideWhenEmpty){
51920 this.on("paneladded", this.validateVisibility, this);
51921 this.on("panelremoved", this.validateVisibility, this);
51923 this.applyConfig(config);
51926 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51928 createBody : function(){
51929 /** This region's body element
51930 * @type Roo.Element */
51931 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51934 applyConfig : function(c){
51935 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51936 var dh = Roo.DomHelper;
51937 if(c.titlebar !== false){
51938 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51939 this.collapseBtn.on("click", this.collapse, this);
51940 this.collapseBtn.enableDisplayMode();
51942 if(c.showPin === true || this.showPin){
51943 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51944 this.stickBtn.enableDisplayMode();
51945 this.stickBtn.on("click", this.expand, this);
51946 this.stickBtn.hide();
51949 /** This region's collapsed element
51950 * @type Roo.Element */
51951 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51952 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51954 if(c.floatable !== false){
51955 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51956 this.collapsedEl.on("click", this.collapseClick, this);
51959 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51960 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51961 id: "message", unselectable: "on", style:{"float":"left"}});
51962 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51964 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51965 this.expandBtn.on("click", this.expand, this);
51967 if(this.collapseBtn){
51968 this.collapseBtn.setVisible(c.collapsible == true);
51970 this.cmargins = c.cmargins || this.cmargins ||
51971 (this.position == "west" || this.position == "east" ?
51972 {top: 0, left: 2, right:2, bottom: 0} :
51973 {top: 2, left: 0, right:0, bottom: 2});
51974 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51975 this.bottomTabs = c.tabPosition != "top";
51976 this.autoScroll = c.autoScroll || false;
51977 if(this.autoScroll){
51978 this.bodyEl.setStyle("overflow", "auto");
51980 this.bodyEl.setStyle("overflow", "hidden");
51982 //if(c.titlebar !== false){
51983 if((!c.titlebar && !c.title) || c.titlebar === false){
51984 this.titleEl.hide();
51986 this.titleEl.show();
51988 this.titleTextEl.innerHTML = c.title;
51992 this.duration = c.duration || .30;
51993 this.slideDuration = c.slideDuration || .45;
51996 this.collapse(true);
52003 * Returns true if this region is currently visible.
52004 * @return {Boolean}
52006 isVisible : function(){
52007 return this.visible;
52011 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52012 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52014 setCollapsedTitle : function(title){
52015 title = title || " ";
52016 if(this.collapsedTitleTextEl){
52017 this.collapsedTitleTextEl.innerHTML = title;
52021 getBox : function(){
52023 if(!this.collapsed){
52024 b = this.el.getBox(false, true);
52026 b = this.collapsedEl.getBox(false, true);
52031 getMargins : function(){
52032 return this.collapsed ? this.cmargins : this.margins;
52035 highlight : function(){
52036 this.el.addClass("x-layout-panel-dragover");
52039 unhighlight : function(){
52040 this.el.removeClass("x-layout-panel-dragover");
52043 updateBox : function(box){
52045 if(!this.collapsed){
52046 this.el.dom.style.left = box.x + "px";
52047 this.el.dom.style.top = box.y + "px";
52048 this.updateBody(box.width, box.height);
52050 this.collapsedEl.dom.style.left = box.x + "px";
52051 this.collapsedEl.dom.style.top = box.y + "px";
52052 this.collapsedEl.setSize(box.width, box.height);
52055 this.tabs.autoSizeTabs();
52059 updateBody : function(w, h){
52061 this.el.setWidth(w);
52062 w -= this.el.getBorderWidth("rl");
52063 if(this.config.adjustments){
52064 w += this.config.adjustments[0];
52068 this.el.setHeight(h);
52069 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52070 h -= this.el.getBorderWidth("tb");
52071 if(this.config.adjustments){
52072 h += this.config.adjustments[1];
52074 this.bodyEl.setHeight(h);
52076 h = this.tabs.syncHeight(h);
52079 if(this.panelSize){
52080 w = w !== null ? w : this.panelSize.width;
52081 h = h !== null ? h : this.panelSize.height;
52083 if(this.activePanel){
52084 var el = this.activePanel.getEl();
52085 w = w !== null ? w : el.getWidth();
52086 h = h !== null ? h : el.getHeight();
52087 this.panelSize = {width: w, height: h};
52088 this.activePanel.setSize(w, h);
52090 if(Roo.isIE && this.tabs){
52091 this.tabs.el.repaint();
52096 * Returns the container element for this region.
52097 * @return {Roo.Element}
52099 getEl : function(){
52104 * Hides this region.
52107 if(!this.collapsed){
52108 this.el.dom.style.left = "-2000px";
52111 this.collapsedEl.dom.style.left = "-2000px";
52112 this.collapsedEl.hide();
52114 this.visible = false;
52115 this.fireEvent("visibilitychange", this, false);
52119 * Shows this region if it was previously hidden.
52122 if(!this.collapsed){
52125 this.collapsedEl.show();
52127 this.visible = true;
52128 this.fireEvent("visibilitychange", this, true);
52131 closeClicked : function(){
52132 if(this.activePanel){
52133 this.remove(this.activePanel);
52137 collapseClick : function(e){
52139 e.stopPropagation();
52142 e.stopPropagation();
52148 * Collapses this region.
52149 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52151 collapse : function(skipAnim, skipCheck = false){
52152 if(this.collapsed) {
52156 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52158 this.collapsed = true;
52160 this.split.el.hide();
52162 if(this.config.animate && skipAnim !== true){
52163 this.fireEvent("invalidated", this);
52164 this.animateCollapse();
52166 this.el.setLocation(-20000,-20000);
52168 this.collapsedEl.show();
52169 this.fireEvent("collapsed", this);
52170 this.fireEvent("invalidated", this);
52176 animateCollapse : function(){
52181 * Expands this region if it was previously collapsed.
52182 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52183 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52185 expand : function(e, skipAnim){
52187 e.stopPropagation();
52189 if(!this.collapsed || this.el.hasActiveFx()) {
52193 this.afterSlideIn();
52196 this.collapsed = false;
52197 if(this.config.animate && skipAnim !== true){
52198 this.animateExpand();
52202 this.split.el.show();
52204 this.collapsedEl.setLocation(-2000,-2000);
52205 this.collapsedEl.hide();
52206 this.fireEvent("invalidated", this);
52207 this.fireEvent("expanded", this);
52211 animateExpand : function(){
52215 initTabs : function()
52217 this.bodyEl.setStyle("overflow", "hidden");
52218 var ts = new Roo.TabPanel(
52221 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52222 disableTooltips: this.config.disableTabTips,
52223 toolbar : this.config.toolbar
52226 if(this.config.hideTabs){
52227 ts.stripWrap.setDisplayed(false);
52230 ts.resizeTabs = this.config.resizeTabs === true;
52231 ts.minTabWidth = this.config.minTabWidth || 40;
52232 ts.maxTabWidth = this.config.maxTabWidth || 250;
52233 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52234 ts.monitorResize = false;
52235 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52236 ts.bodyEl.addClass('x-layout-tabs-body');
52237 this.panels.each(this.initPanelAsTab, this);
52240 initPanelAsTab : function(panel){
52241 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52242 this.config.closeOnTab && panel.isClosable());
52243 if(panel.tabTip !== undefined){
52244 ti.setTooltip(panel.tabTip);
52246 ti.on("activate", function(){
52247 this.setActivePanel(panel);
52249 if(this.config.closeOnTab){
52250 ti.on("beforeclose", function(t, e){
52252 this.remove(panel);
52258 updatePanelTitle : function(panel, title){
52259 if(this.activePanel == panel){
52260 this.updateTitle(title);
52263 var ti = this.tabs.getTab(panel.getEl().id);
52265 if(panel.tabTip !== undefined){
52266 ti.setTooltip(panel.tabTip);
52271 updateTitle : function(title){
52272 if(this.titleTextEl && !this.config.title){
52273 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52277 setActivePanel : function(panel){
52278 panel = this.getPanel(panel);
52279 if(this.activePanel && this.activePanel != panel){
52280 this.activePanel.setActiveState(false);
52282 this.activePanel = panel;
52283 panel.setActiveState(true);
52284 if(this.panelSize){
52285 panel.setSize(this.panelSize.width, this.panelSize.height);
52288 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52290 this.updateTitle(panel.getTitle());
52292 this.fireEvent("invalidated", this);
52294 this.fireEvent("panelactivated", this, panel);
52298 * Shows the specified panel.
52299 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52300 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52302 showPanel : function(panel)
52304 panel = this.getPanel(panel);
52307 var tab = this.tabs.getTab(panel.getEl().id);
52308 if(tab.isHidden()){
52309 this.tabs.unhideTab(tab.id);
52313 this.setActivePanel(panel);
52320 * Get the active panel for this region.
52321 * @return {Roo.ContentPanel} The active panel or null
52323 getActivePanel : function(){
52324 return this.activePanel;
52327 validateVisibility : function(){
52328 if(this.panels.getCount() < 1){
52329 this.updateTitle(" ");
52330 this.closeBtn.hide();
52333 if(!this.isVisible()){
52340 * Adds the passed ContentPanel(s) to this region.
52341 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52342 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52344 add : function(panel){
52345 if(arguments.length > 1){
52346 for(var i = 0, len = arguments.length; i < len; i++) {
52347 this.add(arguments[i]);
52351 if(this.hasPanel(panel)){
52352 this.showPanel(panel);
52355 panel.setRegion(this);
52356 this.panels.add(panel);
52357 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52358 this.bodyEl.dom.appendChild(panel.getEl().dom);
52359 if(panel.background !== true){
52360 this.setActivePanel(panel);
52362 this.fireEvent("paneladded", this, panel);
52368 this.initPanelAsTab(panel);
52370 if(panel.background !== true){
52371 this.tabs.activate(panel.getEl().id);
52373 this.fireEvent("paneladded", this, panel);
52378 * Hides the tab for the specified panel.
52379 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52381 hidePanel : function(panel){
52382 if(this.tabs && (panel = this.getPanel(panel))){
52383 this.tabs.hideTab(panel.getEl().id);
52388 * Unhides the tab for a previously hidden panel.
52389 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52391 unhidePanel : function(panel){
52392 if(this.tabs && (panel = this.getPanel(panel))){
52393 this.tabs.unhideTab(panel.getEl().id);
52397 clearPanels : function(){
52398 while(this.panels.getCount() > 0){
52399 this.remove(this.panels.first());
52404 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52405 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52406 * @param {Boolean} preservePanel Overrides the config preservePanel option
52407 * @return {Roo.ContentPanel} The panel that was removed
52409 remove : function(panel, preservePanel){
52410 panel = this.getPanel(panel);
52415 this.fireEvent("beforeremove", this, panel, e);
52416 if(e.cancel === true){
52419 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52420 var panelId = panel.getId();
52421 this.panels.removeKey(panelId);
52423 document.body.appendChild(panel.getEl().dom);
52426 this.tabs.removeTab(panel.getEl().id);
52427 }else if (!preservePanel){
52428 this.bodyEl.dom.removeChild(panel.getEl().dom);
52430 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52431 var p = this.panels.first();
52432 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52433 tempEl.appendChild(p.getEl().dom);
52434 this.bodyEl.update("");
52435 this.bodyEl.dom.appendChild(p.getEl().dom);
52437 this.updateTitle(p.getTitle());
52439 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52440 this.setActivePanel(p);
52442 panel.setRegion(null);
52443 if(this.activePanel == panel){
52444 this.activePanel = null;
52446 if(this.config.autoDestroy !== false && preservePanel !== true){
52447 try{panel.destroy();}catch(e){}
52449 this.fireEvent("panelremoved", this, panel);
52454 * Returns the TabPanel component used by this region
52455 * @return {Roo.TabPanel}
52457 getTabs : function(){
52461 createTool : function(parentEl, className){
52462 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52463 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52464 btn.addClassOnOver("x-layout-tools-button-over");
52469 * Ext JS Library 1.1.1
52470 * Copyright(c) 2006-2007, Ext JS, LLC.
52472 * Originally Released Under LGPL - original licence link has changed is not relivant.
52475 * <script type="text/javascript">
52481 * @class Roo.SplitLayoutRegion
52482 * @extends Roo.LayoutRegion
52483 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52485 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52486 this.cursor = cursor;
52487 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52490 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52491 splitTip : "Drag to resize.",
52492 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52493 useSplitTips : false,
52495 applyConfig : function(config){
52496 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52499 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52500 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52501 /** The SplitBar for this region
52502 * @type Roo.SplitBar */
52503 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52504 this.split.on("moved", this.onSplitMove, this);
52505 this.split.useShim = config.useShim === true;
52506 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52507 if(this.useSplitTips){
52508 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52510 if(config.collapsible){
52511 this.split.el.on("dblclick", this.collapse, this);
52514 if(typeof config.minSize != "undefined"){
52515 this.split.minSize = config.minSize;
52517 if(typeof config.maxSize != "undefined"){
52518 this.split.maxSize = config.maxSize;
52520 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52521 this.hideSplitter();
52526 getHMaxSize : function(){
52527 var cmax = this.config.maxSize || 10000;
52528 var center = this.mgr.getRegion("center");
52529 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52532 getVMaxSize : function(){
52533 var cmax = this.config.maxSize || 10000;
52534 var center = this.mgr.getRegion("center");
52535 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52538 onSplitMove : function(split, newSize){
52539 this.fireEvent("resized", this, newSize);
52543 * Returns the {@link Roo.SplitBar} for this region.
52544 * @return {Roo.SplitBar}
52546 getSplitBar : function(){
52551 this.hideSplitter();
52552 Roo.SplitLayoutRegion.superclass.hide.call(this);
52555 hideSplitter : function(){
52557 this.split.el.setLocation(-2000,-2000);
52558 this.split.el.hide();
52564 this.split.el.show();
52566 Roo.SplitLayoutRegion.superclass.show.call(this);
52569 beforeSlide: function(){
52570 if(Roo.isGecko){// firefox overflow auto bug workaround
52571 this.bodyEl.clip();
52573 this.tabs.bodyEl.clip();
52575 if(this.activePanel){
52576 this.activePanel.getEl().clip();
52578 if(this.activePanel.beforeSlide){
52579 this.activePanel.beforeSlide();
52585 afterSlide : function(){
52586 if(Roo.isGecko){// firefox overflow auto bug workaround
52587 this.bodyEl.unclip();
52589 this.tabs.bodyEl.unclip();
52591 if(this.activePanel){
52592 this.activePanel.getEl().unclip();
52593 if(this.activePanel.afterSlide){
52594 this.activePanel.afterSlide();
52600 initAutoHide : function(){
52601 if(this.autoHide !== false){
52602 if(!this.autoHideHd){
52603 var st = new Roo.util.DelayedTask(this.slideIn, this);
52604 this.autoHideHd = {
52605 "mouseout": function(e){
52606 if(!e.within(this.el, true)){
52610 "mouseover" : function(e){
52616 this.el.on(this.autoHideHd);
52620 clearAutoHide : function(){
52621 if(this.autoHide !== false){
52622 this.el.un("mouseout", this.autoHideHd.mouseout);
52623 this.el.un("mouseover", this.autoHideHd.mouseover);
52627 clearMonitor : function(){
52628 Roo.get(document).un("click", this.slideInIf, this);
52631 // these names are backwards but not changed for compat
52632 slideOut : function(){
52633 if(this.isSlid || this.el.hasActiveFx()){
52636 this.isSlid = true;
52637 if(this.collapseBtn){
52638 this.collapseBtn.hide();
52640 this.closeBtnState = this.closeBtn.getStyle('display');
52641 this.closeBtn.hide();
52643 this.stickBtn.show();
52646 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52647 this.beforeSlide();
52648 this.el.setStyle("z-index", 10001);
52649 this.el.slideIn(this.getSlideAnchor(), {
52650 callback: function(){
52652 this.initAutoHide();
52653 Roo.get(document).on("click", this.slideInIf, this);
52654 this.fireEvent("slideshow", this);
52661 afterSlideIn : function(){
52662 this.clearAutoHide();
52663 this.isSlid = false;
52664 this.clearMonitor();
52665 this.el.setStyle("z-index", "");
52666 if(this.collapseBtn){
52667 this.collapseBtn.show();
52669 this.closeBtn.setStyle('display', this.closeBtnState);
52671 this.stickBtn.hide();
52673 this.fireEvent("slidehide", this);
52676 slideIn : function(cb){
52677 if(!this.isSlid || this.el.hasActiveFx()){
52681 this.isSlid = false;
52682 this.beforeSlide();
52683 this.el.slideOut(this.getSlideAnchor(), {
52684 callback: function(){
52685 this.el.setLeftTop(-10000, -10000);
52687 this.afterSlideIn();
52695 slideInIf : function(e){
52696 if(!e.within(this.el)){
52701 animateCollapse : function(){
52702 this.beforeSlide();
52703 this.el.setStyle("z-index", 20000);
52704 var anchor = this.getSlideAnchor();
52705 this.el.slideOut(anchor, {
52706 callback : function(){
52707 this.el.setStyle("z-index", "");
52708 this.collapsedEl.slideIn(anchor, {duration:.3});
52710 this.el.setLocation(-10000,-10000);
52712 this.fireEvent("collapsed", this);
52719 animateExpand : function(){
52720 this.beforeSlide();
52721 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52722 this.el.setStyle("z-index", 20000);
52723 this.collapsedEl.hide({
52726 this.el.slideIn(this.getSlideAnchor(), {
52727 callback : function(){
52728 this.el.setStyle("z-index", "");
52731 this.split.el.show();
52733 this.fireEvent("invalidated", this);
52734 this.fireEvent("expanded", this);
52762 getAnchor : function(){
52763 return this.anchors[this.position];
52766 getCollapseAnchor : function(){
52767 return this.canchors[this.position];
52770 getSlideAnchor : function(){
52771 return this.sanchors[this.position];
52774 getAlignAdj : function(){
52775 var cm = this.cmargins;
52776 switch(this.position){
52792 getExpandAdj : function(){
52793 var c = this.collapsedEl, cm = this.cmargins;
52794 switch(this.position){
52796 return [-(cm.right+c.getWidth()+cm.left), 0];
52799 return [cm.right+c.getWidth()+cm.left, 0];
52802 return [0, -(cm.top+cm.bottom+c.getHeight())];
52805 return [0, cm.top+cm.bottom+c.getHeight()];
52811 * Ext JS Library 1.1.1
52812 * Copyright(c) 2006-2007, Ext JS, LLC.
52814 * Originally Released Under LGPL - original licence link has changed is not relivant.
52817 * <script type="text/javascript">
52820 * These classes are private internal classes
52822 Roo.CenterLayoutRegion = function(mgr, config){
52823 Roo.LayoutRegion.call(this, mgr, config, "center");
52824 this.visible = true;
52825 this.minWidth = config.minWidth || 20;
52826 this.minHeight = config.minHeight || 20;
52829 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52831 // center panel can't be hidden
52835 // center panel can't be hidden
52838 getMinWidth: function(){
52839 return this.minWidth;
52842 getMinHeight: function(){
52843 return this.minHeight;
52848 Roo.NorthLayoutRegion = function(mgr, config){
52849 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52851 this.split.placement = Roo.SplitBar.TOP;
52852 this.split.orientation = Roo.SplitBar.VERTICAL;
52853 this.split.el.addClass("x-layout-split-v");
52855 var size = config.initialSize || config.height;
52856 if(typeof size != "undefined"){
52857 this.el.setHeight(size);
52860 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52861 orientation: Roo.SplitBar.VERTICAL,
52862 getBox : function(){
52863 if(this.collapsed){
52864 return this.collapsedEl.getBox();
52866 var box = this.el.getBox();
52868 box.height += this.split.el.getHeight();
52873 updateBox : function(box){
52874 if(this.split && !this.collapsed){
52875 box.height -= this.split.el.getHeight();
52876 this.split.el.setLeft(box.x);
52877 this.split.el.setTop(box.y+box.height);
52878 this.split.el.setWidth(box.width);
52880 if(this.collapsed){
52881 this.updateBody(box.width, null);
52883 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52887 Roo.SouthLayoutRegion = function(mgr, config){
52888 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52890 this.split.placement = Roo.SplitBar.BOTTOM;
52891 this.split.orientation = Roo.SplitBar.VERTICAL;
52892 this.split.el.addClass("x-layout-split-v");
52894 var size = config.initialSize || config.height;
52895 if(typeof size != "undefined"){
52896 this.el.setHeight(size);
52899 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52900 orientation: Roo.SplitBar.VERTICAL,
52901 getBox : function(){
52902 if(this.collapsed){
52903 return this.collapsedEl.getBox();
52905 var box = this.el.getBox();
52907 var sh = this.split.el.getHeight();
52914 updateBox : function(box){
52915 if(this.split && !this.collapsed){
52916 var sh = this.split.el.getHeight();
52919 this.split.el.setLeft(box.x);
52920 this.split.el.setTop(box.y-sh);
52921 this.split.el.setWidth(box.width);
52923 if(this.collapsed){
52924 this.updateBody(box.width, null);
52926 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52930 Roo.EastLayoutRegion = function(mgr, config){
52931 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52933 this.split.placement = Roo.SplitBar.RIGHT;
52934 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52935 this.split.el.addClass("x-layout-split-h");
52937 var size = config.initialSize || config.width;
52938 if(typeof size != "undefined"){
52939 this.el.setWidth(size);
52942 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52943 orientation: Roo.SplitBar.HORIZONTAL,
52944 getBox : function(){
52945 if(this.collapsed){
52946 return this.collapsedEl.getBox();
52948 var box = this.el.getBox();
52950 var sw = this.split.el.getWidth();
52957 updateBox : function(box){
52958 if(this.split && !this.collapsed){
52959 var sw = this.split.el.getWidth();
52961 this.split.el.setLeft(box.x);
52962 this.split.el.setTop(box.y);
52963 this.split.el.setHeight(box.height);
52966 if(this.collapsed){
52967 this.updateBody(null, box.height);
52969 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52973 Roo.WestLayoutRegion = function(mgr, config){
52974 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52976 this.split.placement = Roo.SplitBar.LEFT;
52977 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52978 this.split.el.addClass("x-layout-split-h");
52980 var size = config.initialSize || config.width;
52981 if(typeof size != "undefined"){
52982 this.el.setWidth(size);
52985 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52986 orientation: Roo.SplitBar.HORIZONTAL,
52987 getBox : function(){
52988 if(this.collapsed){
52989 return this.collapsedEl.getBox();
52991 var box = this.el.getBox();
52993 box.width += this.split.el.getWidth();
52998 updateBox : function(box){
52999 if(this.split && !this.collapsed){
53000 var sw = this.split.el.getWidth();
53002 this.split.el.setLeft(box.x+box.width);
53003 this.split.el.setTop(box.y);
53004 this.split.el.setHeight(box.height);
53006 if(this.collapsed){
53007 this.updateBody(null, box.height);
53009 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53014 * Ext JS Library 1.1.1
53015 * Copyright(c) 2006-2007, Ext JS, LLC.
53017 * Originally Released Under LGPL - original licence link has changed is not relivant.
53020 * <script type="text/javascript">
53025 * Private internal class for reading and applying state
53027 Roo.LayoutStateManager = function(layout){
53028 // default empty state
53037 Roo.LayoutStateManager.prototype = {
53038 init : function(layout, provider){
53039 this.provider = provider;
53040 var state = provider.get(layout.id+"-layout-state");
53042 var wasUpdating = layout.isUpdating();
53044 layout.beginUpdate();
53046 for(var key in state){
53047 if(typeof state[key] != "function"){
53048 var rstate = state[key];
53049 var r = layout.getRegion(key);
53052 r.resizeTo(rstate.size);
53054 if(rstate.collapsed == true){
53057 r.expand(null, true);
53063 layout.endUpdate();
53065 this.state = state;
53067 this.layout = layout;
53068 layout.on("regionresized", this.onRegionResized, this);
53069 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53070 layout.on("regionexpanded", this.onRegionExpanded, this);
53073 storeState : function(){
53074 this.provider.set(this.layout.id+"-layout-state", this.state);
53077 onRegionResized : function(region, newSize){
53078 this.state[region.getPosition()].size = newSize;
53082 onRegionCollapsed : function(region){
53083 this.state[region.getPosition()].collapsed = true;
53087 onRegionExpanded : function(region){
53088 this.state[region.getPosition()].collapsed = false;
53093 * Ext JS Library 1.1.1
53094 * Copyright(c) 2006-2007, Ext JS, LLC.
53096 * Originally Released Under LGPL - original licence link has changed is not relivant.
53099 * <script type="text/javascript">
53102 * @class Roo.ContentPanel
53103 * @extends Roo.util.Observable
53104 * A basic ContentPanel element.
53105 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53106 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53107 * @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
53108 * @cfg {Boolean} closable True if the panel can be closed/removed
53109 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53110 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53111 * @cfg {Toolbar} toolbar A toolbar for this panel
53112 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53113 * @cfg {String} title The title for this panel
53114 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53115 * @cfg {String} url Calls {@link #setUrl} with this value
53116 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53117 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53118 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53119 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53122 * Create a new ContentPanel.
53123 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53124 * @param {String/Object} config A string to set only the title or a config object
53125 * @param {String} content (optional) Set the HTML content for this panel
53126 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53128 Roo.ContentPanel = function(el, config, content){
53132 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53136 if (config && config.parentLayout) {
53137 el = config.parentLayout.el.createChild();
53140 if(el.autoCreate){ // xtype is available if this is called from factory
53144 this.el = Roo.get(el);
53145 if(!this.el && config && config.autoCreate){
53146 if(typeof config.autoCreate == "object"){
53147 if(!config.autoCreate.id){
53148 config.autoCreate.id = config.id||el;
53150 this.el = Roo.DomHelper.append(document.body,
53151 config.autoCreate, true);
53153 this.el = Roo.DomHelper.append(document.body,
53154 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53157 this.closable = false;
53158 this.loaded = false;
53159 this.active = false;
53160 if(typeof config == "string"){
53161 this.title = config;
53163 Roo.apply(this, config);
53166 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53167 this.wrapEl = this.el.wrap();
53168 this.toolbar.container = this.el.insertSibling(false, 'before');
53169 this.toolbar = new Roo.Toolbar(this.toolbar);
53172 // xtype created footer. - not sure if will work as we normally have to render first..
53173 if (this.footer && !this.footer.el && this.footer.xtype) {
53174 if (!this.wrapEl) {
53175 this.wrapEl = this.el.wrap();
53178 this.footer.container = this.wrapEl.createChild();
53180 this.footer = Roo.factory(this.footer, Roo);
53185 this.resizeEl = Roo.get(this.resizeEl, true);
53187 this.resizeEl = this.el;
53189 // handle view.xtype
53197 * Fires when this panel is activated.
53198 * @param {Roo.ContentPanel} this
53202 * @event deactivate
53203 * Fires when this panel is activated.
53204 * @param {Roo.ContentPanel} this
53206 "deactivate" : true,
53210 * Fires when this panel is resized if fitToFrame is true.
53211 * @param {Roo.ContentPanel} this
53212 * @param {Number} width The width after any component adjustments
53213 * @param {Number} height The height after any component adjustments
53219 * Fires when this tab is created
53220 * @param {Roo.ContentPanel} this
53231 if(this.autoScroll){
53232 this.resizeEl.setStyle("overflow", "auto");
53234 // fix randome scrolling
53235 this.el.on('scroll', function() {
53236 Roo.log('fix random scolling');
53237 this.scrollTo('top',0);
53240 content = content || this.content;
53242 this.setContent(content);
53244 if(config && config.url){
53245 this.setUrl(this.url, this.params, this.loadOnce);
53250 Roo.ContentPanel.superclass.constructor.call(this);
53252 if (this.view && typeof(this.view.xtype) != 'undefined') {
53253 this.view.el = this.el.appendChild(document.createElement("div"));
53254 this.view = Roo.factory(this.view);
53255 this.view.render && this.view.render(false, '');
53259 this.fireEvent('render', this);
53262 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53264 setRegion : function(region){
53265 this.region = region;
53267 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53269 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53274 * Returns the toolbar for this Panel if one was configured.
53275 * @return {Roo.Toolbar}
53277 getToolbar : function(){
53278 return this.toolbar;
53281 setActiveState : function(active){
53282 this.active = active;
53284 this.fireEvent("deactivate", this);
53286 this.fireEvent("activate", this);
53290 * Updates this panel's element
53291 * @param {String} content The new content
53292 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53294 setContent : function(content, loadScripts){
53295 this.el.update(content, loadScripts);
53298 ignoreResize : function(w, h){
53299 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53302 this.lastSize = {width: w, height: h};
53307 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53308 * @return {Roo.UpdateManager} The UpdateManager
53310 getUpdateManager : function(){
53311 return this.el.getUpdateManager();
53314 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53315 * @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:
53318 url: "your-url.php",
53319 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53320 callback: yourFunction,
53321 scope: yourObject, //(optional scope)
53324 text: "Loading...",
53329 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53330 * 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.
53331 * @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}
53332 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53333 * @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.
53334 * @return {Roo.ContentPanel} this
53337 var um = this.el.getUpdateManager();
53338 um.update.apply(um, arguments);
53344 * 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.
53345 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53346 * @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)
53347 * @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)
53348 * @return {Roo.UpdateManager} The UpdateManager
53350 setUrl : function(url, params, loadOnce){
53351 if(this.refreshDelegate){
53352 this.removeListener("activate", this.refreshDelegate);
53354 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53355 this.on("activate", this.refreshDelegate);
53356 return this.el.getUpdateManager();
53359 _handleRefresh : function(url, params, loadOnce){
53360 if(!loadOnce || !this.loaded){
53361 var updater = this.el.getUpdateManager();
53362 updater.update(url, params, this._setLoaded.createDelegate(this));
53366 _setLoaded : function(){
53367 this.loaded = true;
53371 * Returns this panel's id
53374 getId : function(){
53379 * Returns this panel's element - used by regiosn to add.
53380 * @return {Roo.Element}
53382 getEl : function(){
53383 return this.wrapEl || this.el;
53386 adjustForComponents : function(width, height)
53388 //Roo.log('adjustForComponents ');
53389 if(this.resizeEl != this.el){
53390 width -= this.el.getFrameWidth('lr');
53391 height -= this.el.getFrameWidth('tb');
53394 var te = this.toolbar.getEl();
53395 height -= te.getHeight();
53396 te.setWidth(width);
53399 var te = this.footer.getEl();
53400 Roo.log("footer:" + te.getHeight());
53402 height -= te.getHeight();
53403 te.setWidth(width);
53407 if(this.adjustments){
53408 width += this.adjustments[0];
53409 height += this.adjustments[1];
53411 return {"width": width, "height": height};
53414 setSize : function(width, height){
53415 if(this.fitToFrame && !this.ignoreResize(width, height)){
53416 if(this.fitContainer && this.resizeEl != this.el){
53417 this.el.setSize(width, height);
53419 var size = this.adjustForComponents(width, height);
53420 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53421 this.fireEvent('resize', this, size.width, size.height);
53426 * Returns this panel's title
53429 getTitle : function(){
53434 * Set this panel's title
53435 * @param {String} title
53437 setTitle : function(title){
53438 this.title = title;
53440 this.region.updatePanelTitle(this, title);
53445 * Returns true is this panel was configured to be closable
53446 * @return {Boolean}
53448 isClosable : function(){
53449 return this.closable;
53452 beforeSlide : function(){
53454 this.resizeEl.clip();
53457 afterSlide : function(){
53459 this.resizeEl.unclip();
53463 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53464 * Will fail silently if the {@link #setUrl} method has not been called.
53465 * This does not activate the panel, just updates its content.
53467 refresh : function(){
53468 if(this.refreshDelegate){
53469 this.loaded = false;
53470 this.refreshDelegate();
53475 * Destroys this panel
53477 destroy : function(){
53478 this.el.removeAllListeners();
53479 var tempEl = document.createElement("span");
53480 tempEl.appendChild(this.el.dom);
53481 tempEl.innerHTML = "";
53487 * form - if the content panel contains a form - this is a reference to it.
53488 * @type {Roo.form.Form}
53492 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53493 * This contains a reference to it.
53499 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53509 * @param {Object} cfg Xtype definition of item to add.
53512 addxtype : function(cfg) {
53514 if (cfg.xtype.match(/^Form$/)) {
53517 //if (this.footer) {
53518 // el = this.footer.container.insertSibling(false, 'before');
53520 el = this.el.createChild();
53523 this.form = new Roo.form.Form(cfg);
53526 if ( this.form.allItems.length) {
53527 this.form.render(el.dom);
53531 // should only have one of theses..
53532 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53533 // views.. should not be just added - used named prop 'view''
53535 cfg.el = this.el.appendChild(document.createElement("div"));
53538 var ret = new Roo.factory(cfg);
53540 ret.render && ret.render(false, ''); // render blank..
53549 * @class Roo.GridPanel
53550 * @extends Roo.ContentPanel
53552 * Create a new GridPanel.
53553 * @param {Roo.grid.Grid} grid The grid for this panel
53554 * @param {String/Object} config A string to set only the panel's title, or a config object
53556 Roo.GridPanel = function(grid, config){
53559 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53560 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53562 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53564 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53567 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53569 // xtype created footer. - not sure if will work as we normally have to render first..
53570 if (this.footer && !this.footer.el && this.footer.xtype) {
53572 this.footer.container = this.grid.getView().getFooterPanel(true);
53573 this.footer.dataSource = this.grid.dataSource;
53574 this.footer = Roo.factory(this.footer, Roo);
53578 grid.monitorWindowResize = false; // turn off autosizing
53579 grid.autoHeight = false;
53580 grid.autoWidth = false;
53582 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53585 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53586 getId : function(){
53587 return this.grid.id;
53591 * Returns the grid for this panel
53592 * @return {Roo.grid.Grid}
53594 getGrid : function(){
53598 setSize : function(width, height){
53599 if(!this.ignoreResize(width, height)){
53600 var grid = this.grid;
53601 var size = this.adjustForComponents(width, height);
53602 grid.getGridEl().setSize(size.width, size.height);
53607 beforeSlide : function(){
53608 this.grid.getView().scroller.clip();
53611 afterSlide : function(){
53612 this.grid.getView().scroller.unclip();
53615 destroy : function(){
53616 this.grid.destroy();
53618 Roo.GridPanel.superclass.destroy.call(this);
53624 * @class Roo.NestedLayoutPanel
53625 * @extends Roo.ContentPanel
53627 * Create a new NestedLayoutPanel.
53630 * @param {Roo.BorderLayout} layout The layout for this panel
53631 * @param {String/Object} config A string to set only the title or a config object
53633 Roo.NestedLayoutPanel = function(layout, config)
53635 // construct with only one argument..
53636 /* FIXME - implement nicer consturctors
53637 if (layout.layout) {
53639 layout = config.layout;
53640 delete config.layout;
53642 if (layout.xtype && !layout.getEl) {
53643 // then layout needs constructing..
53644 layout = Roo.factory(layout, Roo);
53649 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53651 layout.monitorWindowResize = false; // turn off autosizing
53652 this.layout = layout;
53653 this.layout.getEl().addClass("x-layout-nested-layout");
53660 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53662 setSize : function(width, height){
53663 if(!this.ignoreResize(width, height)){
53664 var size = this.adjustForComponents(width, height);
53665 var el = this.layout.getEl();
53666 el.setSize(size.width, size.height);
53667 var touch = el.dom.offsetWidth;
53668 this.layout.layout();
53669 // ie requires a double layout on the first pass
53670 if(Roo.isIE && !this.initialized){
53671 this.initialized = true;
53672 this.layout.layout();
53677 // activate all subpanels if not currently active..
53679 setActiveState : function(active){
53680 this.active = active;
53682 this.fireEvent("deactivate", this);
53686 this.fireEvent("activate", this);
53687 // not sure if this should happen before or after..
53688 if (!this.layout) {
53689 return; // should not happen..
53692 for (var r in this.layout.regions) {
53693 reg = this.layout.getRegion(r);
53694 if (reg.getActivePanel()) {
53695 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53696 reg.setActivePanel(reg.getActivePanel());
53699 if (!reg.panels.length) {
53702 reg.showPanel(reg.getPanel(0));
53711 * Returns the nested BorderLayout for this panel
53712 * @return {Roo.BorderLayout}
53714 getLayout : function(){
53715 return this.layout;
53719 * Adds a xtype elements to the layout of the nested panel
53723 xtype : 'ContentPanel',
53730 xtype : 'NestedLayoutPanel',
53736 items : [ ... list of content panels or nested layout panels.. ]
53740 * @param {Object} cfg Xtype definition of item to add.
53742 addxtype : function(cfg) {
53743 return this.layout.addxtype(cfg);
53748 Roo.ScrollPanel = function(el, config, content){
53749 config = config || {};
53750 config.fitToFrame = true;
53751 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53753 this.el.dom.style.overflow = "hidden";
53754 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53755 this.el.removeClass("x-layout-inactive-content");
53756 this.el.on("mousewheel", this.onWheel, this);
53758 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53759 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53760 up.unselectable(); down.unselectable();
53761 up.on("click", this.scrollUp, this);
53762 down.on("click", this.scrollDown, this);
53763 up.addClassOnOver("x-scroller-btn-over");
53764 down.addClassOnOver("x-scroller-btn-over");
53765 up.addClassOnClick("x-scroller-btn-click");
53766 down.addClassOnClick("x-scroller-btn-click");
53767 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53769 this.resizeEl = this.el;
53770 this.el = wrap; this.up = up; this.down = down;
53773 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53775 wheelIncrement : 5,
53776 scrollUp : function(){
53777 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53780 scrollDown : function(){
53781 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53784 afterScroll : function(){
53785 var el = this.resizeEl;
53786 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53787 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53788 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53791 setSize : function(){
53792 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53793 this.afterScroll();
53796 onWheel : function(e){
53797 var d = e.getWheelDelta();
53798 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53799 this.afterScroll();
53803 setContent : function(content, loadScripts){
53804 this.resizeEl.update(content, loadScripts);
53818 * @class Roo.TreePanel
53819 * @extends Roo.ContentPanel
53821 * Create a new TreePanel. - defaults to fit/scoll contents.
53822 * @param {String/Object} config A string to set only the panel's title, or a config object
53823 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53825 Roo.TreePanel = function(config){
53826 var el = config.el;
53827 var tree = config.tree;
53828 delete config.tree;
53829 delete config.el; // hopefull!
53831 // wrapper for IE7 strict & safari scroll issue
53833 var treeEl = el.createChild();
53834 config.resizeEl = treeEl;
53838 Roo.TreePanel.superclass.constructor.call(this, el, config);
53841 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53842 //console.log(tree);
53843 this.on('activate', function()
53845 if (this.tree.rendered) {
53848 //console.log('render tree');
53849 this.tree.render();
53851 // this should not be needed.. - it's actually the 'el' that resizes?
53852 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53854 //this.on('resize', function (cp, w, h) {
53855 // this.tree.innerCt.setWidth(w);
53856 // this.tree.innerCt.setHeight(h);
53857 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53864 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53881 * Ext JS Library 1.1.1
53882 * Copyright(c) 2006-2007, Ext JS, LLC.
53884 * Originally Released Under LGPL - original licence link has changed is not relivant.
53887 * <script type="text/javascript">
53892 * @class Roo.ReaderLayout
53893 * @extends Roo.BorderLayout
53894 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53895 * center region containing two nested regions (a top one for a list view and one for item preview below),
53896 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53897 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53898 * expedites the setup of the overall layout and regions for this common application style.
53901 var reader = new Roo.ReaderLayout();
53902 var CP = Roo.ContentPanel; // shortcut for adding
53904 reader.beginUpdate();
53905 reader.add("north", new CP("north", "North"));
53906 reader.add("west", new CP("west", {title: "West"}));
53907 reader.add("east", new CP("east", {title: "East"}));
53909 reader.regions.listView.add(new CP("listView", "List"));
53910 reader.regions.preview.add(new CP("preview", "Preview"));
53911 reader.endUpdate();
53914 * Create a new ReaderLayout
53915 * @param {Object} config Configuration options
53916 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53917 * document.body if omitted)
53919 Roo.ReaderLayout = function(config, renderTo){
53920 var c = config || {size:{}};
53921 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53922 north: c.north !== false ? Roo.apply({
53926 }, c.north) : false,
53927 west: c.west !== false ? Roo.apply({
53935 margins:{left:5,right:0,bottom:5,top:5},
53936 cmargins:{left:5,right:5,bottom:5,top:5}
53937 }, c.west) : false,
53938 east: c.east !== false ? Roo.apply({
53946 margins:{left:0,right:5,bottom:5,top:5},
53947 cmargins:{left:5,right:5,bottom:5,top:5}
53948 }, c.east) : false,
53949 center: Roo.apply({
53950 tabPosition: 'top',
53954 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53958 this.el.addClass('x-reader');
53960 this.beginUpdate();
53962 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53963 south: c.preview !== false ? Roo.apply({
53970 cmargins:{top:5,left:0, right:0, bottom:0}
53971 }, c.preview) : false,
53972 center: Roo.apply({
53978 this.add('center', new Roo.NestedLayoutPanel(inner,
53979 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53983 this.regions.preview = inner.getRegion('south');
53984 this.regions.listView = inner.getRegion('center');
53987 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53989 * Ext JS Library 1.1.1
53990 * Copyright(c) 2006-2007, Ext JS, LLC.
53992 * Originally Released Under LGPL - original licence link has changed is not relivant.
53995 * <script type="text/javascript">
53999 * @class Roo.grid.Grid
54000 * @extends Roo.util.Observable
54001 * This class represents the primary interface of a component based grid control.
54002 * <br><br>Usage:<pre><code>
54003 var grid = new Roo.grid.Grid("my-container-id", {
54006 selModel: mySelectionModel,
54007 autoSizeColumns: true,
54008 monitorWindowResize: false,
54009 trackMouseOver: true
54014 * <b>Common Problems:</b><br/>
54015 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54016 * element will correct this<br/>
54017 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54018 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54019 * are unpredictable.<br/>
54020 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54021 * grid to calculate dimensions/offsets.<br/>
54023 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54024 * The container MUST have some type of size defined for the grid to fill. The container will be
54025 * automatically set to position relative if it isn't already.
54026 * @param {Object} config A config object that sets properties on this grid.
54028 Roo.grid.Grid = function(container, config){
54029 // initialize the container
54030 this.container = Roo.get(container);
54031 this.container.update("");
54032 this.container.setStyle("overflow", "hidden");
54033 this.container.addClass('x-grid-container');
54035 this.id = this.container.id;
54037 Roo.apply(this, config);
54038 // check and correct shorthanded configs
54040 this.dataSource = this.ds;
54044 this.colModel = this.cm;
54048 this.selModel = this.sm;
54052 if (this.selModel) {
54053 this.selModel = Roo.factory(this.selModel, Roo.grid);
54054 this.sm = this.selModel;
54055 this.sm.xmodule = this.xmodule || false;
54057 if (typeof(this.colModel.config) == 'undefined') {
54058 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54059 this.cm = this.colModel;
54060 this.cm.xmodule = this.xmodule || false;
54062 if (this.dataSource) {
54063 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54064 this.ds = this.dataSource;
54065 this.ds.xmodule = this.xmodule || false;
54072 this.container.setWidth(this.width);
54076 this.container.setHeight(this.height);
54083 * The raw click event for the entire grid.
54084 * @param {Roo.EventObject} e
54089 * The raw dblclick event for the entire grid.
54090 * @param {Roo.EventObject} e
54094 * @event contextmenu
54095 * The raw contextmenu event for the entire grid.
54096 * @param {Roo.EventObject} e
54098 "contextmenu" : true,
54101 * The raw mousedown event for the entire grid.
54102 * @param {Roo.EventObject} e
54104 "mousedown" : true,
54107 * The raw mouseup event for the entire grid.
54108 * @param {Roo.EventObject} e
54113 * The raw mouseover event for the entire grid.
54114 * @param {Roo.EventObject} e
54116 "mouseover" : true,
54119 * The raw mouseout event for the entire grid.
54120 * @param {Roo.EventObject} e
54125 * The raw keypress event for the entire grid.
54126 * @param {Roo.EventObject} e
54131 * The raw keydown event for the entire grid.
54132 * @param {Roo.EventObject} e
54140 * Fires when a cell is clicked
54141 * @param {Grid} this
54142 * @param {Number} rowIndex
54143 * @param {Number} columnIndex
54144 * @param {Roo.EventObject} e
54146 "cellclick" : true,
54148 * @event celldblclick
54149 * Fires when a cell is double clicked
54150 * @param {Grid} this
54151 * @param {Number} rowIndex
54152 * @param {Number} columnIndex
54153 * @param {Roo.EventObject} e
54155 "celldblclick" : true,
54158 * Fires when a row is clicked
54159 * @param {Grid} this
54160 * @param {Number} rowIndex
54161 * @param {Roo.EventObject} e
54165 * @event rowdblclick
54166 * Fires when a row is double clicked
54167 * @param {Grid} this
54168 * @param {Number} rowIndex
54169 * @param {Roo.EventObject} e
54171 "rowdblclick" : true,
54173 * @event headerclick
54174 * Fires when a header is clicked
54175 * @param {Grid} this
54176 * @param {Number} columnIndex
54177 * @param {Roo.EventObject} e
54179 "headerclick" : true,
54181 * @event headerdblclick
54182 * Fires when a header cell is double clicked
54183 * @param {Grid} this
54184 * @param {Number} columnIndex
54185 * @param {Roo.EventObject} e
54187 "headerdblclick" : true,
54189 * @event rowcontextmenu
54190 * Fires when a row is right clicked
54191 * @param {Grid} this
54192 * @param {Number} rowIndex
54193 * @param {Roo.EventObject} e
54195 "rowcontextmenu" : true,
54197 * @event cellcontextmenu
54198 * Fires when a cell is right clicked
54199 * @param {Grid} this
54200 * @param {Number} rowIndex
54201 * @param {Number} cellIndex
54202 * @param {Roo.EventObject} e
54204 "cellcontextmenu" : true,
54206 * @event headercontextmenu
54207 * Fires when a header is right clicked
54208 * @param {Grid} this
54209 * @param {Number} columnIndex
54210 * @param {Roo.EventObject} e
54212 "headercontextmenu" : true,
54214 * @event bodyscroll
54215 * Fires when the body element is scrolled
54216 * @param {Number} scrollLeft
54217 * @param {Number} scrollTop
54219 "bodyscroll" : true,
54221 * @event columnresize
54222 * Fires when the user resizes a column
54223 * @param {Number} columnIndex
54224 * @param {Number} newSize
54226 "columnresize" : true,
54228 * @event columnmove
54229 * Fires when the user moves a column
54230 * @param {Number} oldIndex
54231 * @param {Number} newIndex
54233 "columnmove" : true,
54236 * Fires when row(s) start being dragged
54237 * @param {Grid} this
54238 * @param {Roo.GridDD} dd The drag drop object
54239 * @param {event} e The raw browser event
54241 "startdrag" : true,
54244 * Fires when a drag operation is complete
54245 * @param {Grid} this
54246 * @param {Roo.GridDD} dd The drag drop object
54247 * @param {event} e The raw browser event
54252 * Fires when dragged row(s) are dropped on a valid DD target
54253 * @param {Grid} this
54254 * @param {Roo.GridDD} dd The drag drop object
54255 * @param {String} targetId The target drag drop object
54256 * @param {event} e The raw browser event
54261 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54262 * @param {Grid} this
54263 * @param {Roo.GridDD} dd The drag drop object
54264 * @param {String} targetId The target drag drop object
54265 * @param {event} e The raw browser event
54270 * Fires when the dragged row(s) first cross another DD target while being dragged
54271 * @param {Grid} this
54272 * @param {Roo.GridDD} dd The drag drop object
54273 * @param {String} targetId The target drag drop object
54274 * @param {event} e The raw browser event
54276 "dragenter" : true,
54279 * Fires when the dragged row(s) leave another DD target while being dragged
54280 * @param {Grid} this
54281 * @param {Roo.GridDD} dd The drag drop object
54282 * @param {String} targetId The target drag drop object
54283 * @param {event} e The raw browser event
54288 * Fires when a row is rendered, so you can change add a style to it.
54289 * @param {GridView} gridview The grid view
54290 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54296 * Fires when the grid is rendered
54297 * @param {Grid} grid
54302 Roo.grid.Grid.superclass.constructor.call(this);
54304 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54307 * @cfg {String} ddGroup - drag drop group.
54311 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54313 minColumnWidth : 25,
54316 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54317 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54318 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54320 autoSizeColumns : false,
54323 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54325 autoSizeHeaders : true,
54328 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54330 monitorWindowResize : true,
54333 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54334 * rows measured to get a columns size. Default is 0 (all rows).
54336 maxRowsToMeasure : 0,
54339 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54341 trackMouseOver : true,
54344 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54348 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54350 enableDragDrop : false,
54353 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54355 enableColumnMove : true,
54358 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54360 enableColumnHide : true,
54363 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54365 enableRowHeightSync : false,
54368 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54373 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54375 autoHeight : false,
54378 * @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.
54380 autoExpandColumn : false,
54383 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54386 autoExpandMin : 50,
54389 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54391 autoExpandMax : 1000,
54394 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54399 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54403 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54413 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54414 * of a fixed width. Default is false.
54417 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54420 * Called once after all setup has been completed and the grid is ready to be rendered.
54421 * @return {Roo.grid.Grid} this
54423 render : function()
54425 var c = this.container;
54426 // try to detect autoHeight/width mode
54427 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54428 this.autoHeight = true;
54430 var view = this.getView();
54433 c.on("click", this.onClick, this);
54434 c.on("dblclick", this.onDblClick, this);
54435 c.on("contextmenu", this.onContextMenu, this);
54436 c.on("keydown", this.onKeyDown, this);
54438 c.on("touchstart", this.onTouchStart, this);
54441 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54443 this.getSelectionModel().init(this);
54448 this.loadMask = new Roo.LoadMask(this.container,
54449 Roo.apply({store:this.dataSource}, this.loadMask));
54453 if (this.toolbar && this.toolbar.xtype) {
54454 this.toolbar.container = this.getView().getHeaderPanel(true);
54455 this.toolbar = new Roo.Toolbar(this.toolbar);
54457 if (this.footer && this.footer.xtype) {
54458 this.footer.dataSource = this.getDataSource();
54459 this.footer.container = this.getView().getFooterPanel(true);
54460 this.footer = Roo.factory(this.footer, Roo);
54462 if (this.dropTarget && this.dropTarget.xtype) {
54463 delete this.dropTarget.xtype;
54464 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54468 this.rendered = true;
54469 this.fireEvent('render', this);
54474 * Reconfigures the grid to use a different Store and Column Model.
54475 * The View will be bound to the new objects and refreshed.
54476 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54477 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54479 reconfigure : function(dataSource, colModel){
54481 this.loadMask.destroy();
54482 this.loadMask = new Roo.LoadMask(this.container,
54483 Roo.apply({store:dataSource}, this.loadMask));
54485 this.view.bind(dataSource, colModel);
54486 this.dataSource = dataSource;
54487 this.colModel = colModel;
54488 this.view.refresh(true);
54492 onKeyDown : function(e){
54493 this.fireEvent("keydown", e);
54497 * Destroy this grid.
54498 * @param {Boolean} removeEl True to remove the element
54500 destroy : function(removeEl, keepListeners){
54502 this.loadMask.destroy();
54504 var c = this.container;
54505 c.removeAllListeners();
54506 this.view.destroy();
54507 this.colModel.purgeListeners();
54508 if(!keepListeners){
54509 this.purgeListeners();
54512 if(removeEl === true){
54518 processEvent : function(name, e){
54519 // does this fire select???
54520 //Roo.log('grid:processEvent ' + name);
54522 if (name != 'touchstart' ) {
54523 this.fireEvent(name, e);
54526 var t = e.getTarget();
54528 var header = v.findHeaderIndex(t);
54529 if(header !== false){
54530 var ename = name == 'touchstart' ? 'click' : name;
54532 this.fireEvent("header" + ename, this, header, e);
54534 var row = v.findRowIndex(t);
54535 var cell = v.findCellIndex(t);
54536 if (name == 'touchstart') {
54537 // first touch is always a click.
54538 // hopefull this happens after selection is updated.?
54541 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54542 var cs = this.selModel.getSelectedCell();
54543 if (row == cs[0] && cell == cs[1]){
54547 if (typeof(this.selModel.getSelections) != 'undefined') {
54548 var cs = this.selModel.getSelections();
54549 var ds = this.dataSource;
54550 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54561 this.fireEvent("row" + name, this, row, e);
54562 if(cell !== false){
54563 this.fireEvent("cell" + name, this, row, cell, e);
54570 onClick : function(e){
54571 this.processEvent("click", e);
54574 onTouchStart : function(e){
54575 this.processEvent("touchstart", e);
54579 onContextMenu : function(e, t){
54580 this.processEvent("contextmenu", e);
54584 onDblClick : function(e){
54585 this.processEvent("dblclick", e);
54589 walkCells : function(row, col, step, fn, scope){
54590 var cm = this.colModel, clen = cm.getColumnCount();
54591 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54603 if(fn.call(scope || this, row, col, cm) === true){
54621 if(fn.call(scope || this, row, col, cm) === true){
54633 getSelections : function(){
54634 return this.selModel.getSelections();
54638 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54639 * but if manual update is required this method will initiate it.
54641 autoSize : function(){
54643 this.view.layout();
54644 if(this.view.adjustForScroll){
54645 this.view.adjustForScroll();
54651 * Returns the grid's underlying element.
54652 * @return {Element} The element
54654 getGridEl : function(){
54655 return this.container;
54658 // private for compatibility, overridden by editor grid
54659 stopEditing : function(){},
54662 * Returns the grid's SelectionModel.
54663 * @return {SelectionModel}
54665 getSelectionModel : function(){
54666 if(!this.selModel){
54667 this.selModel = new Roo.grid.RowSelectionModel();
54669 return this.selModel;
54673 * Returns the grid's DataSource.
54674 * @return {DataSource}
54676 getDataSource : function(){
54677 return this.dataSource;
54681 * Returns the grid's ColumnModel.
54682 * @return {ColumnModel}
54684 getColumnModel : function(){
54685 return this.colModel;
54689 * Returns the grid's GridView object.
54690 * @return {GridView}
54692 getView : function(){
54694 this.view = new Roo.grid.GridView(this.viewConfig);
54699 * Called to get grid's drag proxy text, by default returns this.ddText.
54702 getDragDropText : function(){
54703 var count = this.selModel.getCount();
54704 return String.format(this.ddText, count, count == 1 ? '' : 's');
54708 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54709 * %0 is replaced with the number of selected rows.
54712 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54714 * Ext JS Library 1.1.1
54715 * Copyright(c) 2006-2007, Ext JS, LLC.
54717 * Originally Released Under LGPL - original licence link has changed is not relivant.
54720 * <script type="text/javascript">
54723 Roo.grid.AbstractGridView = function(){
54727 "beforerowremoved" : true,
54728 "beforerowsinserted" : true,
54729 "beforerefresh" : true,
54730 "rowremoved" : true,
54731 "rowsinserted" : true,
54732 "rowupdated" : true,
54735 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54738 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54739 rowClass : "x-grid-row",
54740 cellClass : "x-grid-cell",
54741 tdClass : "x-grid-td",
54742 hdClass : "x-grid-hd",
54743 splitClass : "x-grid-hd-split",
54745 init: function(grid){
54747 var cid = this.grid.getGridEl().id;
54748 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54749 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54750 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54751 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54754 getColumnRenderers : function(){
54755 var renderers = [];
54756 var cm = this.grid.colModel;
54757 var colCount = cm.getColumnCount();
54758 for(var i = 0; i < colCount; i++){
54759 renderers[i] = cm.getRenderer(i);
54764 getColumnIds : function(){
54766 var cm = this.grid.colModel;
54767 var colCount = cm.getColumnCount();
54768 for(var i = 0; i < colCount; i++){
54769 ids[i] = cm.getColumnId(i);
54774 getDataIndexes : function(){
54775 if(!this.indexMap){
54776 this.indexMap = this.buildIndexMap();
54778 return this.indexMap.colToData;
54781 getColumnIndexByDataIndex : function(dataIndex){
54782 if(!this.indexMap){
54783 this.indexMap = this.buildIndexMap();
54785 return this.indexMap.dataToCol[dataIndex];
54789 * Set a css style for a column dynamically.
54790 * @param {Number} colIndex The index of the column
54791 * @param {String} name The css property name
54792 * @param {String} value The css value
54794 setCSSStyle : function(colIndex, name, value){
54795 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54796 Roo.util.CSS.updateRule(selector, name, value);
54799 generateRules : function(cm){
54800 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54801 Roo.util.CSS.removeStyleSheet(rulesId);
54802 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54803 var cid = cm.getColumnId(i);
54804 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54805 this.tdSelector, cid, " {\n}\n",
54806 this.hdSelector, cid, " {\n}\n",
54807 this.splitSelector, cid, " {\n}\n");
54809 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54813 * Ext JS Library 1.1.1
54814 * Copyright(c) 2006-2007, Ext JS, LLC.
54816 * Originally Released Under LGPL - original licence link has changed is not relivant.
54819 * <script type="text/javascript">
54823 // This is a support class used internally by the Grid components
54824 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54826 this.view = grid.getView();
54827 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54828 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54830 this.setHandleElId(Roo.id(hd));
54831 this.setOuterHandleElId(Roo.id(hd2));
54833 this.scroll = false;
54835 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54837 getDragData : function(e){
54838 var t = Roo.lib.Event.getTarget(e);
54839 var h = this.view.findHeaderCell(t);
54841 return {ddel: h.firstChild, header:h};
54846 onInitDrag : function(e){
54847 this.view.headersDisabled = true;
54848 var clone = this.dragData.ddel.cloneNode(true);
54849 clone.id = Roo.id();
54850 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54851 this.proxy.update(clone);
54855 afterValidDrop : function(){
54857 setTimeout(function(){
54858 v.headersDisabled = false;
54862 afterInvalidDrop : function(){
54864 setTimeout(function(){
54865 v.headersDisabled = false;
54871 * Ext JS Library 1.1.1
54872 * Copyright(c) 2006-2007, Ext JS, LLC.
54874 * Originally Released Under LGPL - original licence link has changed is not relivant.
54877 * <script type="text/javascript">
54880 // This is a support class used internally by the Grid components
54881 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54883 this.view = grid.getView();
54884 // split the proxies so they don't interfere with mouse events
54885 this.proxyTop = Roo.DomHelper.append(document.body, {
54886 cls:"col-move-top", html:" "
54888 this.proxyBottom = Roo.DomHelper.append(document.body, {
54889 cls:"col-move-bottom", html:" "
54891 this.proxyTop.hide = this.proxyBottom.hide = function(){
54892 this.setLeftTop(-100,-100);
54893 this.setStyle("visibility", "hidden");
54895 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54896 // temporarily disabled
54897 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54898 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54900 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54901 proxyOffsets : [-4, -9],
54902 fly: Roo.Element.fly,
54904 getTargetFromEvent : function(e){
54905 var t = Roo.lib.Event.getTarget(e);
54906 var cindex = this.view.findCellIndex(t);
54907 if(cindex !== false){
54908 return this.view.getHeaderCell(cindex);
54913 nextVisible : function(h){
54914 var v = this.view, cm = this.grid.colModel;
54917 if(!cm.isHidden(v.getCellIndex(h))){
54925 prevVisible : function(h){
54926 var v = this.view, cm = this.grid.colModel;
54929 if(!cm.isHidden(v.getCellIndex(h))){
54937 positionIndicator : function(h, n, e){
54938 var x = Roo.lib.Event.getPageX(e);
54939 var r = Roo.lib.Dom.getRegion(n.firstChild);
54940 var px, pt, py = r.top + this.proxyOffsets[1];
54941 if((r.right - x) <= (r.right-r.left)/2){
54942 px = r.right+this.view.borderWidth;
54948 var oldIndex = this.view.getCellIndex(h);
54949 var newIndex = this.view.getCellIndex(n);
54951 if(this.grid.colModel.isFixed(newIndex)){
54955 var locked = this.grid.colModel.isLocked(newIndex);
54960 if(oldIndex < newIndex){
54963 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54966 px += this.proxyOffsets[0];
54967 this.proxyTop.setLeftTop(px, py);
54968 this.proxyTop.show();
54969 if(!this.bottomOffset){
54970 this.bottomOffset = this.view.mainHd.getHeight();
54972 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54973 this.proxyBottom.show();
54977 onNodeEnter : function(n, dd, e, data){
54978 if(data.header != n){
54979 this.positionIndicator(data.header, n, e);
54983 onNodeOver : function(n, dd, e, data){
54984 var result = false;
54985 if(data.header != n){
54986 result = this.positionIndicator(data.header, n, e);
54989 this.proxyTop.hide();
54990 this.proxyBottom.hide();
54992 return result ? this.dropAllowed : this.dropNotAllowed;
54995 onNodeOut : function(n, dd, e, data){
54996 this.proxyTop.hide();
54997 this.proxyBottom.hide();
55000 onNodeDrop : function(n, dd, e, data){
55001 var h = data.header;
55003 var cm = this.grid.colModel;
55004 var x = Roo.lib.Event.getPageX(e);
55005 var r = Roo.lib.Dom.getRegion(n.firstChild);
55006 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55007 var oldIndex = this.view.getCellIndex(h);
55008 var newIndex = this.view.getCellIndex(n);
55009 var locked = cm.isLocked(newIndex);
55013 if(oldIndex < newIndex){
55016 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55019 cm.setLocked(oldIndex, locked, true);
55020 cm.moveColumn(oldIndex, newIndex);
55021 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55029 * Ext JS Library 1.1.1
55030 * Copyright(c) 2006-2007, Ext JS, LLC.
55032 * Originally Released Under LGPL - original licence link has changed is not relivant.
55035 * <script type="text/javascript">
55039 * @class Roo.grid.GridView
55040 * @extends Roo.util.Observable
55043 * @param {Object} config
55045 Roo.grid.GridView = function(config){
55046 Roo.grid.GridView.superclass.constructor.call(this);
55049 Roo.apply(this, config);
55052 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55054 unselectable : 'unselectable="on"',
55055 unselectableCls : 'x-unselectable',
55058 rowClass : "x-grid-row",
55060 cellClass : "x-grid-col",
55062 tdClass : "x-grid-td",
55064 hdClass : "x-grid-hd",
55066 splitClass : "x-grid-split",
55068 sortClasses : ["sort-asc", "sort-desc"],
55070 enableMoveAnim : false,
55074 dh : Roo.DomHelper,
55076 fly : Roo.Element.fly,
55078 css : Roo.util.CSS,
55084 scrollIncrement : 22,
55086 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55088 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55090 bind : function(ds, cm){
55092 this.ds.un("load", this.onLoad, this);
55093 this.ds.un("datachanged", this.onDataChange, this);
55094 this.ds.un("add", this.onAdd, this);
55095 this.ds.un("remove", this.onRemove, this);
55096 this.ds.un("update", this.onUpdate, this);
55097 this.ds.un("clear", this.onClear, this);
55100 ds.on("load", this.onLoad, this);
55101 ds.on("datachanged", this.onDataChange, this);
55102 ds.on("add", this.onAdd, this);
55103 ds.on("remove", this.onRemove, this);
55104 ds.on("update", this.onUpdate, this);
55105 ds.on("clear", this.onClear, this);
55110 this.cm.un("widthchange", this.onColWidthChange, this);
55111 this.cm.un("headerchange", this.onHeaderChange, this);
55112 this.cm.un("hiddenchange", this.onHiddenChange, this);
55113 this.cm.un("columnmoved", this.onColumnMove, this);
55114 this.cm.un("columnlockchange", this.onColumnLock, this);
55117 this.generateRules(cm);
55118 cm.on("widthchange", this.onColWidthChange, this);
55119 cm.on("headerchange", this.onHeaderChange, this);
55120 cm.on("hiddenchange", this.onHiddenChange, this);
55121 cm.on("columnmoved", this.onColumnMove, this);
55122 cm.on("columnlockchange", this.onColumnLock, this);
55127 init: function(grid){
55128 Roo.grid.GridView.superclass.init.call(this, grid);
55130 this.bind(grid.dataSource, grid.colModel);
55132 grid.on("headerclick", this.handleHeaderClick, this);
55134 if(grid.trackMouseOver){
55135 grid.on("mouseover", this.onRowOver, this);
55136 grid.on("mouseout", this.onRowOut, this);
55138 grid.cancelTextSelection = function(){};
55139 this.gridId = grid.id;
55141 var tpls = this.templates || {};
55144 tpls.master = new Roo.Template(
55145 '<div class="x-grid" hidefocus="true">',
55146 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55147 '<div class="x-grid-topbar"></div>',
55148 '<div class="x-grid-scroller"><div></div></div>',
55149 '<div class="x-grid-locked">',
55150 '<div class="x-grid-header">{lockedHeader}</div>',
55151 '<div class="x-grid-body">{lockedBody}</div>',
55153 '<div class="x-grid-viewport">',
55154 '<div class="x-grid-header">{header}</div>',
55155 '<div class="x-grid-body">{body}</div>',
55157 '<div class="x-grid-bottombar"></div>',
55159 '<div class="x-grid-resize-proxy"> </div>',
55162 tpls.master.disableformats = true;
55166 tpls.header = new Roo.Template(
55167 '<table border="0" cellspacing="0" cellpadding="0">',
55168 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55171 tpls.header.disableformats = true;
55173 tpls.header.compile();
55176 tpls.hcell = new Roo.Template(
55177 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55178 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55181 tpls.hcell.disableFormats = true;
55183 tpls.hcell.compile();
55186 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55187 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55188 tpls.hsplit.disableFormats = true;
55190 tpls.hsplit.compile();
55193 tpls.body = new Roo.Template(
55194 '<table border="0" cellspacing="0" cellpadding="0">',
55195 "<tbody>{rows}</tbody>",
55198 tpls.body.disableFormats = true;
55200 tpls.body.compile();
55203 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55204 tpls.row.disableFormats = true;
55206 tpls.row.compile();
55209 tpls.cell = new Roo.Template(
55210 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55211 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55212 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55215 tpls.cell.disableFormats = true;
55217 tpls.cell.compile();
55219 this.templates = tpls;
55222 // remap these for backwards compat
55223 onColWidthChange : function(){
55224 this.updateColumns.apply(this, arguments);
55226 onHeaderChange : function(){
55227 this.updateHeaders.apply(this, arguments);
55229 onHiddenChange : function(){
55230 this.handleHiddenChange.apply(this, arguments);
55232 onColumnMove : function(){
55233 this.handleColumnMove.apply(this, arguments);
55235 onColumnLock : function(){
55236 this.handleLockChange.apply(this, arguments);
55239 onDataChange : function(){
55241 this.updateHeaderSortState();
55244 onClear : function(){
55248 onUpdate : function(ds, record){
55249 this.refreshRow(record);
55252 refreshRow : function(record){
55253 var ds = this.ds, index;
55254 if(typeof record == 'number'){
55256 record = ds.getAt(index);
55258 index = ds.indexOf(record);
55260 this.insertRows(ds, index, index, true);
55261 this.onRemove(ds, record, index+1, true);
55262 this.syncRowHeights(index, index);
55264 this.fireEvent("rowupdated", this, index, record);
55267 onAdd : function(ds, records, index){
55268 this.insertRows(ds, index, index + (records.length-1));
55271 onRemove : function(ds, record, index, isUpdate){
55272 if(isUpdate !== true){
55273 this.fireEvent("beforerowremoved", this, index, record);
55275 var bt = this.getBodyTable(), lt = this.getLockedTable();
55276 if(bt.rows[index]){
55277 bt.firstChild.removeChild(bt.rows[index]);
55279 if(lt.rows[index]){
55280 lt.firstChild.removeChild(lt.rows[index]);
55282 if(isUpdate !== true){
55283 this.stripeRows(index);
55284 this.syncRowHeights(index, index);
55286 this.fireEvent("rowremoved", this, index, record);
55290 onLoad : function(){
55291 this.scrollToTop();
55295 * Scrolls the grid to the top
55297 scrollToTop : function(){
55299 this.scroller.dom.scrollTop = 0;
55305 * Gets a panel in the header of the grid that can be used for toolbars etc.
55306 * After modifying the contents of this panel a call to grid.autoSize() may be
55307 * required to register any changes in size.
55308 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55309 * @return Roo.Element
55311 getHeaderPanel : function(doShow){
55313 this.headerPanel.show();
55315 return this.headerPanel;
55319 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55320 * After modifying the contents of this panel a call to grid.autoSize() may be
55321 * required to register any changes in size.
55322 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55323 * @return Roo.Element
55325 getFooterPanel : function(doShow){
55327 this.footerPanel.show();
55329 return this.footerPanel;
55332 initElements : function(){
55333 var E = Roo.Element;
55334 var el = this.grid.getGridEl().dom.firstChild;
55335 var cs = el.childNodes;
55337 this.el = new E(el);
55339 this.focusEl = new E(el.firstChild);
55340 this.focusEl.swallowEvent("click", true);
55342 this.headerPanel = new E(cs[1]);
55343 this.headerPanel.enableDisplayMode("block");
55345 this.scroller = new E(cs[2]);
55346 this.scrollSizer = new E(this.scroller.dom.firstChild);
55348 this.lockedWrap = new E(cs[3]);
55349 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55350 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55352 this.mainWrap = new E(cs[4]);
55353 this.mainHd = new E(this.mainWrap.dom.firstChild);
55354 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55356 this.footerPanel = new E(cs[5]);
55357 this.footerPanel.enableDisplayMode("block");
55359 this.resizeProxy = new E(cs[6]);
55361 this.headerSelector = String.format(
55362 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55363 this.lockedHd.id, this.mainHd.id
55366 this.splitterSelector = String.format(
55367 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55368 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55371 idToCssName : function(s)
55373 return s.replace(/[^a-z0-9]+/ig, '-');
55376 getHeaderCell : function(index){
55377 return Roo.DomQuery.select(this.headerSelector)[index];
55380 getHeaderCellMeasure : function(index){
55381 return this.getHeaderCell(index).firstChild;
55384 getHeaderCellText : function(index){
55385 return this.getHeaderCell(index).firstChild.firstChild;
55388 getLockedTable : function(){
55389 return this.lockedBody.dom.firstChild;
55392 getBodyTable : function(){
55393 return this.mainBody.dom.firstChild;
55396 getLockedRow : function(index){
55397 return this.getLockedTable().rows[index];
55400 getRow : function(index){
55401 return this.getBodyTable().rows[index];
55404 getRowComposite : function(index){
55406 this.rowEl = new Roo.CompositeElementLite();
55408 var els = [], lrow, mrow;
55409 if(lrow = this.getLockedRow(index)){
55412 if(mrow = this.getRow(index)){
55415 this.rowEl.elements = els;
55419 * Gets the 'td' of the cell
55421 * @param {Integer} rowIndex row to select
55422 * @param {Integer} colIndex column to select
55426 getCell : function(rowIndex, colIndex){
55427 var locked = this.cm.getLockedCount();
55429 if(colIndex < locked){
55430 source = this.lockedBody.dom.firstChild;
55432 source = this.mainBody.dom.firstChild;
55433 colIndex -= locked;
55435 return source.rows[rowIndex].childNodes[colIndex];
55438 getCellText : function(rowIndex, colIndex){
55439 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55442 getCellBox : function(cell){
55443 var b = this.fly(cell).getBox();
55444 if(Roo.isOpera){ // opera fails to report the Y
55445 b.y = cell.offsetTop + this.mainBody.getY();
55450 getCellIndex : function(cell){
55451 var id = String(cell.className).match(this.cellRE);
55453 return parseInt(id[1], 10);
55458 findHeaderIndex : function(n){
55459 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55460 return r ? this.getCellIndex(r) : false;
55463 findHeaderCell : function(n){
55464 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55465 return r ? r : false;
55468 findRowIndex : function(n){
55472 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55473 return r ? r.rowIndex : false;
55476 findCellIndex : function(node){
55477 var stop = this.el.dom;
55478 while(node && node != stop){
55479 if(this.findRE.test(node.className)){
55480 return this.getCellIndex(node);
55482 node = node.parentNode;
55487 getColumnId : function(index){
55488 return this.cm.getColumnId(index);
55491 getSplitters : function()
55493 if(this.splitterSelector){
55494 return Roo.DomQuery.select(this.splitterSelector);
55500 getSplitter : function(index){
55501 return this.getSplitters()[index];
55504 onRowOver : function(e, t){
55506 if((row = this.findRowIndex(t)) !== false){
55507 this.getRowComposite(row).addClass("x-grid-row-over");
55511 onRowOut : function(e, t){
55513 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55514 this.getRowComposite(row).removeClass("x-grid-row-over");
55518 renderHeaders : function(){
55520 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55521 var cb = [], lb = [], sb = [], lsb = [], p = {};
55522 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55523 p.cellId = "x-grid-hd-0-" + i;
55524 p.splitId = "x-grid-csplit-0-" + i;
55525 p.id = cm.getColumnId(i);
55526 p.value = cm.getColumnHeader(i) || "";
55527 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55528 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55529 if(!cm.isLocked(i)){
55530 cb[cb.length] = ct.apply(p);
55531 sb[sb.length] = st.apply(p);
55533 lb[lb.length] = ct.apply(p);
55534 lsb[lsb.length] = st.apply(p);
55537 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55538 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55541 updateHeaders : function(){
55542 var html = this.renderHeaders();
55543 this.lockedHd.update(html[0]);
55544 this.mainHd.update(html[1]);
55548 * Focuses the specified row.
55549 * @param {Number} row The row index
55551 focusRow : function(row)
55553 //Roo.log('GridView.focusRow');
55554 var x = this.scroller.dom.scrollLeft;
55555 this.focusCell(row, 0, false);
55556 this.scroller.dom.scrollLeft = x;
55560 * Focuses the specified cell.
55561 * @param {Number} row The row index
55562 * @param {Number} col The column index
55563 * @param {Boolean} hscroll false to disable horizontal scrolling
55565 focusCell : function(row, col, hscroll)
55567 //Roo.log('GridView.focusCell');
55568 var el = this.ensureVisible(row, col, hscroll);
55569 this.focusEl.alignTo(el, "tl-tl");
55571 this.focusEl.focus();
55573 this.focusEl.focus.defer(1, this.focusEl);
55578 * Scrolls the specified cell into view
55579 * @param {Number} row The row index
55580 * @param {Number} col The column index
55581 * @param {Boolean} hscroll false to disable horizontal scrolling
55583 ensureVisible : function(row, col, hscroll)
55585 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55586 //return null; //disable for testing.
55587 if(typeof row != "number"){
55588 row = row.rowIndex;
55590 if(row < 0 && row >= this.ds.getCount()){
55593 col = (col !== undefined ? col : 0);
55594 var cm = this.grid.colModel;
55595 while(cm.isHidden(col)){
55599 var el = this.getCell(row, col);
55603 var c = this.scroller.dom;
55605 var ctop = parseInt(el.offsetTop, 10);
55606 var cleft = parseInt(el.offsetLeft, 10);
55607 var cbot = ctop + el.offsetHeight;
55608 var cright = cleft + el.offsetWidth;
55610 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55611 var stop = parseInt(c.scrollTop, 10);
55612 var sleft = parseInt(c.scrollLeft, 10);
55613 var sbot = stop + ch;
55614 var sright = sleft + c.clientWidth;
55616 Roo.log('GridView.ensureVisible:' +
55618 ' c.clientHeight:' + c.clientHeight +
55619 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55627 c.scrollTop = ctop;
55628 //Roo.log("set scrolltop to ctop DISABLE?");
55629 }else if(cbot > sbot){
55630 //Roo.log("set scrolltop to cbot-ch");
55631 c.scrollTop = cbot-ch;
55634 if(hscroll !== false){
55636 c.scrollLeft = cleft;
55637 }else if(cright > sright){
55638 c.scrollLeft = cright-c.clientWidth;
55645 updateColumns : function(){
55646 this.grid.stopEditing();
55647 var cm = this.grid.colModel, colIds = this.getColumnIds();
55648 //var totalWidth = cm.getTotalWidth();
55650 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55651 //if(cm.isHidden(i)) continue;
55652 var w = cm.getColumnWidth(i);
55653 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55654 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55656 this.updateSplitters();
55659 generateRules : function(cm){
55660 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55661 Roo.util.CSS.removeStyleSheet(rulesId);
55662 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55663 var cid = cm.getColumnId(i);
55665 if(cm.config[i].align){
55666 align = 'text-align:'+cm.config[i].align+';';
55669 if(cm.isHidden(i)){
55670 hidden = 'display:none;';
55672 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55674 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55675 this.hdSelector, cid, " {\n", align, width, "}\n",
55676 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55677 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55679 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55682 updateSplitters : function(){
55683 var cm = this.cm, s = this.getSplitters();
55684 if(s){ // splitters not created yet
55685 var pos = 0, locked = true;
55686 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55687 if(cm.isHidden(i)) {
55690 var w = cm.getColumnWidth(i); // make sure it's a number
55691 if(!cm.isLocked(i) && locked){
55696 s[i].style.left = (pos-this.splitOffset) + "px";
55701 handleHiddenChange : function(colModel, colIndex, hidden){
55703 this.hideColumn(colIndex);
55705 this.unhideColumn(colIndex);
55709 hideColumn : function(colIndex){
55710 var cid = this.getColumnId(colIndex);
55711 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55712 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55714 this.updateHeaders();
55716 this.updateSplitters();
55720 unhideColumn : function(colIndex){
55721 var cid = this.getColumnId(colIndex);
55722 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55723 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55726 this.updateHeaders();
55728 this.updateSplitters();
55732 insertRows : function(dm, firstRow, lastRow, isUpdate){
55733 if(firstRow == 0 && lastRow == dm.getCount()-1){
55737 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55739 var s = this.getScrollState();
55740 var markup = this.renderRows(firstRow, lastRow);
55741 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55742 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55743 this.restoreScroll(s);
55745 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55746 this.syncRowHeights(firstRow, lastRow);
55747 this.stripeRows(firstRow);
55753 bufferRows : function(markup, target, index){
55754 var before = null, trows = target.rows, tbody = target.tBodies[0];
55755 if(index < trows.length){
55756 before = trows[index];
55758 var b = document.createElement("div");
55759 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55760 var rows = b.firstChild.rows;
55761 for(var i = 0, len = rows.length; i < len; i++){
55763 tbody.insertBefore(rows[0], before);
55765 tbody.appendChild(rows[0]);
55772 deleteRows : function(dm, firstRow, lastRow){
55773 if(dm.getRowCount()<1){
55774 this.fireEvent("beforerefresh", this);
55775 this.mainBody.update("");
55776 this.lockedBody.update("");
55777 this.fireEvent("refresh", this);
55779 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55780 var bt = this.getBodyTable();
55781 var tbody = bt.firstChild;
55782 var rows = bt.rows;
55783 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55784 tbody.removeChild(rows[firstRow]);
55786 this.stripeRows(firstRow);
55787 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55791 updateRows : function(dataSource, firstRow, lastRow){
55792 var s = this.getScrollState();
55794 this.restoreScroll(s);
55797 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55801 this.updateHeaderSortState();
55804 getScrollState : function(){
55806 var sb = this.scroller.dom;
55807 return {left: sb.scrollLeft, top: sb.scrollTop};
55810 stripeRows : function(startRow){
55811 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55814 startRow = startRow || 0;
55815 var rows = this.getBodyTable().rows;
55816 var lrows = this.getLockedTable().rows;
55817 var cls = ' x-grid-row-alt ';
55818 for(var i = startRow, len = rows.length; i < len; i++){
55819 var row = rows[i], lrow = lrows[i];
55820 var isAlt = ((i+1) % 2 == 0);
55821 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55822 if(isAlt == hasAlt){
55826 row.className += " x-grid-row-alt";
55828 row.className = row.className.replace("x-grid-row-alt", "");
55831 lrow.className = row.className;
55836 restoreScroll : function(state){
55837 //Roo.log('GridView.restoreScroll');
55838 var sb = this.scroller.dom;
55839 sb.scrollLeft = state.left;
55840 sb.scrollTop = state.top;
55844 syncScroll : function(){
55845 //Roo.log('GridView.syncScroll');
55846 var sb = this.scroller.dom;
55847 var sh = this.mainHd.dom;
55848 var bs = this.mainBody.dom;
55849 var lv = this.lockedBody.dom;
55850 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55851 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55854 handleScroll : function(e){
55856 var sb = this.scroller.dom;
55857 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55861 handleWheel : function(e){
55862 var d = e.getWheelDelta();
55863 this.scroller.dom.scrollTop -= d*22;
55864 // set this here to prevent jumpy scrolling on large tables
55865 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55869 renderRows : function(startRow, endRow){
55870 // pull in all the crap needed to render rows
55871 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55872 var colCount = cm.getColumnCount();
55874 if(ds.getCount() < 1){
55878 // build a map for all the columns
55880 for(var i = 0; i < colCount; i++){
55881 var name = cm.getDataIndex(i);
55883 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55884 renderer : cm.getRenderer(i),
55885 id : cm.getColumnId(i),
55886 locked : cm.isLocked(i),
55887 has_editor : cm.isCellEditable(i)
55891 startRow = startRow || 0;
55892 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55894 // records to render
55895 var rs = ds.getRange(startRow, endRow);
55897 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55900 // As much as I hate to duplicate code, this was branched because FireFox really hates
55901 // [].join("") on strings. The performance difference was substantial enough to
55902 // branch this function
55903 doRender : Roo.isGecko ?
55904 function(cs, rs, ds, startRow, colCount, stripe){
55905 var ts = this.templates, ct = ts.cell, rt = ts.row;
55907 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55909 var hasListener = this.grid.hasListener('rowclass');
55911 for(var j = 0, len = rs.length; j < len; j++){
55912 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55913 for(var i = 0; i < colCount; i++){
55915 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55917 p.css = p.attr = "";
55918 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55919 if(p.value == undefined || p.value === "") {
55920 p.value = " ";
55923 p.css += ' x-grid-editable-cell';
55925 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55926 p.css += ' x-grid-dirty-cell';
55928 var markup = ct.apply(p);
55936 if(stripe && ((rowIndex+1) % 2 == 0)){
55937 alt.push("x-grid-row-alt")
55940 alt.push( " x-grid-dirty-row");
55943 if(this.getRowClass){
55944 alt.push(this.getRowClass(r, rowIndex));
55950 rowIndex : rowIndex,
55953 this.grid.fireEvent('rowclass', this, rowcfg);
55954 alt.push(rowcfg.rowClass);
55956 rp.alt = alt.join(" ");
55957 lbuf+= rt.apply(rp);
55959 buf+= rt.apply(rp);
55961 return [lbuf, buf];
55963 function(cs, rs, ds, startRow, colCount, stripe){
55964 var ts = this.templates, ct = ts.cell, rt = ts.row;
55966 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55967 var hasListener = this.grid.hasListener('rowclass');
55970 for(var j = 0, len = rs.length; j < len; j++){
55971 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55972 for(var i = 0; i < colCount; i++){
55974 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55976 p.css = p.attr = "";
55977 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55978 if(p.value == undefined || p.value === "") {
55979 p.value = " ";
55983 p.css += ' x-grid-editable-cell';
55985 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55986 p.css += ' x-grid-dirty-cell'
55989 var markup = ct.apply(p);
55991 cb[cb.length] = markup;
55993 lcb[lcb.length] = markup;
55997 if(stripe && ((rowIndex+1) % 2 == 0)){
55998 alt.push( "x-grid-row-alt");
56001 alt.push(" x-grid-dirty-row");
56004 if(this.getRowClass){
56005 alt.push( this.getRowClass(r, rowIndex));
56011 rowIndex : rowIndex,
56014 this.grid.fireEvent('rowclass', this, rowcfg);
56015 alt.push(rowcfg.rowClass);
56018 rp.alt = alt.join(" ");
56019 rp.cells = lcb.join("");
56020 lbuf[lbuf.length] = rt.apply(rp);
56021 rp.cells = cb.join("");
56022 buf[buf.length] = rt.apply(rp);
56024 return [lbuf.join(""), buf.join("")];
56027 renderBody : function(){
56028 var markup = this.renderRows();
56029 var bt = this.templates.body;
56030 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56034 * Refreshes the grid
56035 * @param {Boolean} headersToo
56037 refresh : function(headersToo){
56038 this.fireEvent("beforerefresh", this);
56039 this.grid.stopEditing();
56040 var result = this.renderBody();
56041 this.lockedBody.update(result[0]);
56042 this.mainBody.update(result[1]);
56043 if(headersToo === true){
56044 this.updateHeaders();
56045 this.updateColumns();
56046 this.updateSplitters();
56047 this.updateHeaderSortState();
56049 this.syncRowHeights();
56051 this.fireEvent("refresh", this);
56054 handleColumnMove : function(cm, oldIndex, newIndex){
56055 this.indexMap = null;
56056 var s = this.getScrollState();
56057 this.refresh(true);
56058 this.restoreScroll(s);
56059 this.afterMove(newIndex);
56062 afterMove : function(colIndex){
56063 if(this.enableMoveAnim && Roo.enableFx){
56064 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56066 // if multisort - fix sortOrder, and reload..
56067 if (this.grid.dataSource.multiSort) {
56068 // the we can call sort again..
56069 var dm = this.grid.dataSource;
56070 var cm = this.grid.colModel;
56072 for(var i = 0; i < cm.config.length; i++ ) {
56074 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56075 continue; // dont' bother, it's not in sort list or being set.
56078 so.push(cm.config[i].dataIndex);
56081 dm.load(dm.lastOptions);
56088 updateCell : function(dm, rowIndex, dataIndex){
56089 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56090 if(typeof colIndex == "undefined"){ // not present in grid
56093 var cm = this.grid.colModel;
56094 var cell = this.getCell(rowIndex, colIndex);
56095 var cellText = this.getCellText(rowIndex, colIndex);
56098 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56099 id : cm.getColumnId(colIndex),
56100 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56102 var renderer = cm.getRenderer(colIndex);
56103 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56104 if(typeof val == "undefined" || val === "") {
56107 cellText.innerHTML = val;
56108 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56109 this.syncRowHeights(rowIndex, rowIndex);
56112 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56114 if(this.grid.autoSizeHeaders){
56115 var h = this.getHeaderCellMeasure(colIndex);
56116 maxWidth = Math.max(maxWidth, h.scrollWidth);
56119 if(this.cm.isLocked(colIndex)){
56120 tb = this.getLockedTable();
56123 tb = this.getBodyTable();
56124 index = colIndex - this.cm.getLockedCount();
56127 var rows = tb.rows;
56128 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56129 for(var i = 0; i < stopIndex; i++){
56130 var cell = rows[i].childNodes[index].firstChild;
56131 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56134 return maxWidth + /*margin for error in IE*/ 5;
56137 * Autofit a column to its content.
56138 * @param {Number} colIndex
56139 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56141 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56142 if(this.cm.isHidden(colIndex)){
56143 return; // can't calc a hidden column
56146 var cid = this.cm.getColumnId(colIndex);
56147 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56148 if(this.grid.autoSizeHeaders){
56149 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56152 var newWidth = this.calcColumnWidth(colIndex);
56153 this.cm.setColumnWidth(colIndex,
56154 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56155 if(!suppressEvent){
56156 this.grid.fireEvent("columnresize", colIndex, newWidth);
56161 * Autofits all columns to their content and then expands to fit any extra space in the grid
56163 autoSizeColumns : function(){
56164 var cm = this.grid.colModel;
56165 var colCount = cm.getColumnCount();
56166 for(var i = 0; i < colCount; i++){
56167 this.autoSizeColumn(i, true, true);
56169 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56172 this.updateColumns();
56178 * Autofits all columns to the grid's width proportionate with their current size
56179 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56181 fitColumns : function(reserveScrollSpace){
56182 var cm = this.grid.colModel;
56183 var colCount = cm.getColumnCount();
56187 for (i = 0; i < colCount; i++){
56188 if(!cm.isHidden(i) && !cm.isFixed(i)){
56189 w = cm.getColumnWidth(i);
56195 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56196 if(reserveScrollSpace){
56199 var frac = (avail - cm.getTotalWidth())/width;
56200 while (cols.length){
56203 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56205 this.updateColumns();
56209 onRowSelect : function(rowIndex){
56210 var row = this.getRowComposite(rowIndex);
56211 row.addClass("x-grid-row-selected");
56214 onRowDeselect : function(rowIndex){
56215 var row = this.getRowComposite(rowIndex);
56216 row.removeClass("x-grid-row-selected");
56219 onCellSelect : function(row, col){
56220 var cell = this.getCell(row, col);
56222 Roo.fly(cell).addClass("x-grid-cell-selected");
56226 onCellDeselect : function(row, col){
56227 var cell = this.getCell(row, col);
56229 Roo.fly(cell).removeClass("x-grid-cell-selected");
56233 updateHeaderSortState : function(){
56235 // sort state can be single { field: xxx, direction : yyy}
56236 // or { xxx=>ASC , yyy : DESC ..... }
56239 if (!this.ds.multiSort) {
56240 var state = this.ds.getSortState();
56244 mstate[state.field] = state.direction;
56245 // FIXME... - this is not used here.. but might be elsewhere..
56246 this.sortState = state;
56249 mstate = this.ds.sortToggle;
56251 //remove existing sort classes..
56253 var sc = this.sortClasses;
56254 var hds = this.el.select(this.headerSelector).removeClass(sc);
56256 for(var f in mstate) {
56258 var sortColumn = this.cm.findColumnIndex(f);
56260 if(sortColumn != -1){
56261 var sortDir = mstate[f];
56262 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56271 handleHeaderClick : function(g, index,e){
56273 Roo.log("header click");
56276 // touch events on header are handled by context
56277 this.handleHdCtx(g,index,e);
56282 if(this.headersDisabled){
56285 var dm = g.dataSource, cm = g.colModel;
56286 if(!cm.isSortable(index)){
56291 if (dm.multiSort) {
56292 // update the sortOrder
56294 for(var i = 0; i < cm.config.length; i++ ) {
56296 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56297 continue; // dont' bother, it's not in sort list or being set.
56300 so.push(cm.config[i].dataIndex);
56306 dm.sort(cm.getDataIndex(index));
56310 destroy : function(){
56312 this.colMenu.removeAll();
56313 Roo.menu.MenuMgr.unregister(this.colMenu);
56314 this.colMenu.getEl().remove();
56315 delete this.colMenu;
56318 this.hmenu.removeAll();
56319 Roo.menu.MenuMgr.unregister(this.hmenu);
56320 this.hmenu.getEl().remove();
56323 if(this.grid.enableColumnMove){
56324 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56326 for(var dd in dds){
56327 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56328 var elid = dds[dd].dragElId;
56330 Roo.get(elid).remove();
56331 } else if(dds[dd].config.isTarget){
56332 dds[dd].proxyTop.remove();
56333 dds[dd].proxyBottom.remove();
56336 if(Roo.dd.DDM.locationCache[dd]){
56337 delete Roo.dd.DDM.locationCache[dd];
56340 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56343 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56344 this.bind(null, null);
56345 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56348 handleLockChange : function(){
56349 this.refresh(true);
56352 onDenyColumnLock : function(){
56356 onDenyColumnHide : function(){
56360 handleHdMenuClick : function(item){
56361 var index = this.hdCtxIndex;
56362 var cm = this.cm, ds = this.ds;
56365 ds.sort(cm.getDataIndex(index), "ASC");
56368 ds.sort(cm.getDataIndex(index), "DESC");
56371 var lc = cm.getLockedCount();
56372 if(cm.getColumnCount(true) <= lc+1){
56373 this.onDenyColumnLock();
56377 cm.setLocked(index, true, true);
56378 cm.moveColumn(index, lc);
56379 this.grid.fireEvent("columnmove", index, lc);
56381 cm.setLocked(index, true);
56385 var lc = cm.getLockedCount();
56386 if((lc-1) != index){
56387 cm.setLocked(index, false, true);
56388 cm.moveColumn(index, lc-1);
56389 this.grid.fireEvent("columnmove", index, lc-1);
56391 cm.setLocked(index, false);
56394 case 'wider': // used to expand cols on touch..
56396 var cw = cm.getColumnWidth(index);
56397 cw += (item.id == 'wider' ? 1 : -1) * 50;
56398 cw = Math.max(0, cw);
56399 cw = Math.min(cw,4000);
56400 cm.setColumnWidth(index, cw);
56404 index = cm.getIndexById(item.id.substr(4));
56406 if(item.checked && cm.getColumnCount(true) <= 1){
56407 this.onDenyColumnHide();
56410 cm.setHidden(index, item.checked);
56416 beforeColMenuShow : function(){
56417 var cm = this.cm, colCount = cm.getColumnCount();
56418 this.colMenu.removeAll();
56419 for(var i = 0; i < colCount; i++){
56420 this.colMenu.add(new Roo.menu.CheckItem({
56421 id: "col-"+cm.getColumnId(i),
56422 text: cm.getColumnHeader(i),
56423 checked: !cm.isHidden(i),
56429 handleHdCtx : function(g, index, e){
56431 var hd = this.getHeaderCell(index);
56432 this.hdCtxIndex = index;
56433 var ms = this.hmenu.items, cm = this.cm;
56434 ms.get("asc").setDisabled(!cm.isSortable(index));
56435 ms.get("desc").setDisabled(!cm.isSortable(index));
56436 if(this.grid.enableColLock !== false){
56437 ms.get("lock").setDisabled(cm.isLocked(index));
56438 ms.get("unlock").setDisabled(!cm.isLocked(index));
56440 this.hmenu.show(hd, "tl-bl");
56443 handleHdOver : function(e){
56444 var hd = this.findHeaderCell(e.getTarget());
56445 if(hd && !this.headersDisabled){
56446 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56447 this.fly(hd).addClass("x-grid-hd-over");
56452 handleHdOut : function(e){
56453 var hd = this.findHeaderCell(e.getTarget());
56455 this.fly(hd).removeClass("x-grid-hd-over");
56459 handleSplitDblClick : function(e, t){
56460 var i = this.getCellIndex(t);
56461 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56462 this.autoSizeColumn(i, true);
56467 render : function(){
56470 var colCount = cm.getColumnCount();
56472 if(this.grid.monitorWindowResize === true){
56473 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56475 var header = this.renderHeaders();
56476 var body = this.templates.body.apply({rows:""});
56477 var html = this.templates.master.apply({
56480 lockedHeader: header[0],
56484 //this.updateColumns();
56486 this.grid.getGridEl().dom.innerHTML = html;
56488 this.initElements();
56490 // a kludge to fix the random scolling effect in webkit
56491 this.el.on("scroll", function() {
56492 this.el.dom.scrollTop=0; // hopefully not recursive..
56495 this.scroller.on("scroll", this.handleScroll, this);
56496 this.lockedBody.on("mousewheel", this.handleWheel, this);
56497 this.mainBody.on("mousewheel", this.handleWheel, this);
56499 this.mainHd.on("mouseover", this.handleHdOver, this);
56500 this.mainHd.on("mouseout", this.handleHdOut, this);
56501 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56502 {delegate: "."+this.splitClass});
56504 this.lockedHd.on("mouseover", this.handleHdOver, this);
56505 this.lockedHd.on("mouseout", this.handleHdOut, this);
56506 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56507 {delegate: "."+this.splitClass});
56509 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56510 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56513 this.updateSplitters();
56515 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56516 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56517 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56520 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56521 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56523 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56524 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56526 if(this.grid.enableColLock !== false){
56527 this.hmenu.add('-',
56528 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56529 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56533 this.hmenu.add('-',
56534 {id:"wider", text: this.columnsWiderText},
56535 {id:"narrow", text: this.columnsNarrowText }
56541 if(this.grid.enableColumnHide !== false){
56543 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56544 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56545 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56547 this.hmenu.add('-',
56548 {id:"columns", text: this.columnsText, menu: this.colMenu}
56551 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56553 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56556 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56557 this.dd = new Roo.grid.GridDragZone(this.grid, {
56558 ddGroup : this.grid.ddGroup || 'GridDD'
56564 for(var i = 0; i < colCount; i++){
56565 if(cm.isHidden(i)){
56566 this.hideColumn(i);
56568 if(cm.config[i].align){
56569 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56570 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56574 this.updateHeaderSortState();
56576 this.beforeInitialResize();
56579 // two part rendering gives faster view to the user
56580 this.renderPhase2.defer(1, this);
56583 renderPhase2 : function(){
56584 // render the rows now
56586 if(this.grid.autoSizeColumns){
56587 this.autoSizeColumns();
56591 beforeInitialResize : function(){
56595 onColumnSplitterMoved : function(i, w){
56596 this.userResized = true;
56597 var cm = this.grid.colModel;
56598 cm.setColumnWidth(i, w, true);
56599 var cid = cm.getColumnId(i);
56600 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56601 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56602 this.updateSplitters();
56604 this.grid.fireEvent("columnresize", i, w);
56607 syncRowHeights : function(startIndex, endIndex){
56608 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56609 startIndex = startIndex || 0;
56610 var mrows = this.getBodyTable().rows;
56611 var lrows = this.getLockedTable().rows;
56612 var len = mrows.length-1;
56613 endIndex = Math.min(endIndex || len, len);
56614 for(var i = startIndex; i <= endIndex; i++){
56615 var m = mrows[i], l = lrows[i];
56616 var h = Math.max(m.offsetHeight, l.offsetHeight);
56617 m.style.height = l.style.height = h + "px";
56622 layout : function(initialRender, is2ndPass){
56624 var auto = g.autoHeight;
56625 var scrollOffset = 16;
56626 var c = g.getGridEl(), cm = this.cm,
56627 expandCol = g.autoExpandColumn,
56629 //c.beginMeasure();
56631 if(!c.dom.offsetWidth){ // display:none?
56633 this.lockedWrap.show();
56634 this.mainWrap.show();
56639 var hasLock = this.cm.isLocked(0);
56641 var tbh = this.headerPanel.getHeight();
56642 var bbh = this.footerPanel.getHeight();
56645 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56646 var newHeight = ch + c.getBorderWidth("tb");
56648 newHeight = Math.min(g.maxHeight, newHeight);
56650 c.setHeight(newHeight);
56654 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56657 var s = this.scroller;
56659 var csize = c.getSize(true);
56661 this.el.setSize(csize.width, csize.height);
56663 this.headerPanel.setWidth(csize.width);
56664 this.footerPanel.setWidth(csize.width);
56666 var hdHeight = this.mainHd.getHeight();
56667 var vw = csize.width;
56668 var vh = csize.height - (tbh + bbh);
56672 var bt = this.getBodyTable();
56674 if(cm.getLockedCount() == cm.config.length){
56675 bt = this.getLockedTable();
56678 var ltWidth = hasLock ?
56679 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56681 var scrollHeight = bt.offsetHeight;
56682 var scrollWidth = ltWidth + bt.offsetWidth;
56683 var vscroll = false, hscroll = false;
56685 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56687 var lw = this.lockedWrap, mw = this.mainWrap;
56688 var lb = this.lockedBody, mb = this.mainBody;
56690 setTimeout(function(){
56691 var t = s.dom.offsetTop;
56692 var w = s.dom.clientWidth,
56693 h = s.dom.clientHeight;
56696 lw.setSize(ltWidth, h);
56698 mw.setLeftTop(ltWidth, t);
56699 mw.setSize(w-ltWidth, h);
56701 lb.setHeight(h-hdHeight);
56702 mb.setHeight(h-hdHeight);
56704 if(is2ndPass !== true && !gv.userResized && expandCol){
56705 // high speed resize without full column calculation
56707 var ci = cm.getIndexById(expandCol);
56709 ci = cm.findColumnIndex(expandCol);
56711 ci = Math.max(0, ci); // make sure it's got at least the first col.
56712 var expandId = cm.getColumnId(ci);
56713 var tw = cm.getTotalWidth(false);
56714 var currentWidth = cm.getColumnWidth(ci);
56715 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56716 if(currentWidth != cw){
56717 cm.setColumnWidth(ci, cw, true);
56718 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56719 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56720 gv.updateSplitters();
56721 gv.layout(false, true);
56733 onWindowResize : function(){
56734 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56740 appendFooter : function(parentEl){
56744 sortAscText : "Sort Ascending",
56745 sortDescText : "Sort Descending",
56746 lockText : "Lock Column",
56747 unlockText : "Unlock Column",
56748 columnsText : "Columns",
56750 columnsWiderText : "Wider",
56751 columnsNarrowText : "Thinner"
56755 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56756 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56757 this.proxy.el.addClass('x-grid3-col-dd');
56760 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56761 handleMouseDown : function(e){
56765 callHandleMouseDown : function(e){
56766 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56771 * Ext JS Library 1.1.1
56772 * Copyright(c) 2006-2007, Ext JS, LLC.
56774 * Originally Released Under LGPL - original licence link has changed is not relivant.
56777 * <script type="text/javascript">
56781 // This is a support class used internally by the Grid components
56782 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56784 this.view = grid.getView();
56785 this.proxy = this.view.resizeProxy;
56786 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56787 "gridSplitters" + this.grid.getGridEl().id, {
56788 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56790 this.setHandleElId(Roo.id(hd));
56791 this.setOuterHandleElId(Roo.id(hd2));
56792 this.scroll = false;
56794 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56795 fly: Roo.Element.fly,
56797 b4StartDrag : function(x, y){
56798 this.view.headersDisabled = true;
56799 this.proxy.setHeight(this.view.mainWrap.getHeight());
56800 var w = this.cm.getColumnWidth(this.cellIndex);
56801 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56802 this.resetConstraints();
56803 this.setXConstraint(minw, 1000);
56804 this.setYConstraint(0, 0);
56805 this.minX = x - minw;
56806 this.maxX = x + 1000;
56808 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56812 handleMouseDown : function(e){
56813 ev = Roo.EventObject.setEvent(e);
56814 var t = this.fly(ev.getTarget());
56815 if(t.hasClass("x-grid-split")){
56816 this.cellIndex = this.view.getCellIndex(t.dom);
56817 this.split = t.dom;
56818 this.cm = this.grid.colModel;
56819 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56820 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56825 endDrag : function(e){
56826 this.view.headersDisabled = false;
56827 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56828 var diff = endX - this.startPos;
56829 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56832 autoOffset : function(){
56833 this.setDelta(0,0);
56837 * Ext JS Library 1.1.1
56838 * Copyright(c) 2006-2007, Ext JS, LLC.
56840 * Originally Released Under LGPL - original licence link has changed is not relivant.
56843 * <script type="text/javascript">
56847 // This is a support class used internally by the Grid components
56848 Roo.grid.GridDragZone = function(grid, config){
56849 this.view = grid.getView();
56850 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56851 if(this.view.lockedBody){
56852 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56853 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56855 this.scroll = false;
56857 this.ddel = document.createElement('div');
56858 this.ddel.className = 'x-grid-dd-wrap';
56861 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56862 ddGroup : "GridDD",
56864 getDragData : function(e){
56865 var t = Roo.lib.Event.getTarget(e);
56866 var rowIndex = this.view.findRowIndex(t);
56867 var sm = this.grid.selModel;
56869 //Roo.log(rowIndex);
56871 if (sm.getSelectedCell) {
56872 // cell selection..
56873 if (!sm.getSelectedCell()) {
56876 if (rowIndex != sm.getSelectedCell()[0]) {
56882 if(rowIndex !== false){
56887 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56889 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56892 if (e.hasModifier()){
56893 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56896 Roo.log("getDragData");
56901 rowIndex: rowIndex,
56902 selections:sm.getSelections ? sm.getSelections() : (
56903 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56910 onInitDrag : function(e){
56911 var data = this.dragData;
56912 this.ddel.innerHTML = this.grid.getDragDropText();
56913 this.proxy.update(this.ddel);
56914 // fire start drag?
56917 afterRepair : function(){
56918 this.dragging = false;
56921 getRepairXY : function(e, data){
56925 onEndDrag : function(data, e){
56929 onValidDrop : function(dd, e, id){
56934 beforeInvalidDrop : function(e, id){
56939 * Ext JS Library 1.1.1
56940 * Copyright(c) 2006-2007, Ext JS, LLC.
56942 * Originally Released Under LGPL - original licence link has changed is not relivant.
56945 * <script type="text/javascript">
56950 * @class Roo.grid.ColumnModel
56951 * @extends Roo.util.Observable
56952 * This is the default implementation of a ColumnModel used by the Grid. It defines
56953 * the columns in the grid.
56956 var colModel = new Roo.grid.ColumnModel([
56957 {header: "Ticker", width: 60, sortable: true, locked: true},
56958 {header: "Company Name", width: 150, sortable: true},
56959 {header: "Market Cap.", width: 100, sortable: true},
56960 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56961 {header: "Employees", width: 100, sortable: true, resizable: false}
56966 * The config options listed for this class are options which may appear in each
56967 * individual column definition.
56968 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56970 * @param {Object} config An Array of column config objects. See this class's
56971 * config objects for details.
56973 Roo.grid.ColumnModel = function(config){
56975 * The config passed into the constructor
56977 this.config = config;
56980 // if no id, create one
56981 // if the column does not have a dataIndex mapping,
56982 // map it to the order it is in the config
56983 for(var i = 0, len = config.length; i < len; i++){
56985 if(typeof c.dataIndex == "undefined"){
56988 if(typeof c.renderer == "string"){
56989 c.renderer = Roo.util.Format[c.renderer];
56991 if(typeof c.id == "undefined"){
56994 if(c.editor && c.editor.xtype){
56995 c.editor = Roo.factory(c.editor, Roo.grid);
56997 if(c.editor && c.editor.isFormField){
56998 c.editor = new Roo.grid.GridEditor(c.editor);
57000 this.lookup[c.id] = c;
57004 * The width of columns which have no width specified (defaults to 100)
57007 this.defaultWidth = 100;
57010 * Default sortable of columns which have no sortable specified (defaults to false)
57013 this.defaultSortable = false;
57017 * @event widthchange
57018 * Fires when the width of a column changes.
57019 * @param {ColumnModel} this
57020 * @param {Number} columnIndex The column index
57021 * @param {Number} newWidth The new width
57023 "widthchange": true,
57025 * @event headerchange
57026 * Fires when the text of a header changes.
57027 * @param {ColumnModel} this
57028 * @param {Number} columnIndex The column index
57029 * @param {Number} newText The new header text
57031 "headerchange": true,
57033 * @event hiddenchange
57034 * Fires when a column is hidden or "unhidden".
57035 * @param {ColumnModel} this
57036 * @param {Number} columnIndex The column index
57037 * @param {Boolean} hidden true if hidden, false otherwise
57039 "hiddenchange": true,
57041 * @event columnmoved
57042 * Fires when a column is moved.
57043 * @param {ColumnModel} this
57044 * @param {Number} oldIndex
57045 * @param {Number} newIndex
57047 "columnmoved" : true,
57049 * @event columlockchange
57050 * Fires when a column's locked state is changed
57051 * @param {ColumnModel} this
57052 * @param {Number} colIndex
57053 * @param {Boolean} locked true if locked
57055 "columnlockchange" : true
57057 Roo.grid.ColumnModel.superclass.constructor.call(this);
57059 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57061 * @cfg {String} header The header text to display in the Grid view.
57064 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57065 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57066 * specified, the column's index is used as an index into the Record's data Array.
57069 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57070 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57073 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57074 * Defaults to the value of the {@link #defaultSortable} property.
57075 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57078 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57081 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57084 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57087 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57090 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57091 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57092 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57093 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57096 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57099 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57102 * @cfg {String} cursor (Optional)
57105 * @cfg {String} tooltip (Optional)
57108 * @cfg {Number} xs (Optional)
57111 * @cfg {Number} sm (Optional)
57114 * @cfg {Number} md (Optional)
57117 * @cfg {Number} lg (Optional)
57120 * Returns the id of the column at the specified index.
57121 * @param {Number} index The column index
57122 * @return {String} the id
57124 getColumnId : function(index){
57125 return this.config[index].id;
57129 * Returns the column for a specified id.
57130 * @param {String} id The column id
57131 * @return {Object} the column
57133 getColumnById : function(id){
57134 return this.lookup[id];
57139 * Returns the column for a specified dataIndex.
57140 * @param {String} dataIndex The column dataIndex
57141 * @return {Object|Boolean} the column or false if not found
57143 getColumnByDataIndex: function(dataIndex){
57144 var index = this.findColumnIndex(dataIndex);
57145 return index > -1 ? this.config[index] : false;
57149 * Returns the index for a specified column id.
57150 * @param {String} id The column id
57151 * @return {Number} the index, or -1 if not found
57153 getIndexById : function(id){
57154 for(var i = 0, len = this.config.length; i < len; i++){
57155 if(this.config[i].id == id){
57163 * Returns the index for a specified column dataIndex.
57164 * @param {String} dataIndex The column dataIndex
57165 * @return {Number} the index, or -1 if not found
57168 findColumnIndex : function(dataIndex){
57169 for(var i = 0, len = this.config.length; i < len; i++){
57170 if(this.config[i].dataIndex == dataIndex){
57178 moveColumn : function(oldIndex, newIndex){
57179 var c = this.config[oldIndex];
57180 this.config.splice(oldIndex, 1);
57181 this.config.splice(newIndex, 0, c);
57182 this.dataMap = null;
57183 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57186 isLocked : function(colIndex){
57187 return this.config[colIndex].locked === true;
57190 setLocked : function(colIndex, value, suppressEvent){
57191 if(this.isLocked(colIndex) == value){
57194 this.config[colIndex].locked = value;
57195 if(!suppressEvent){
57196 this.fireEvent("columnlockchange", this, colIndex, value);
57200 getTotalLockedWidth : function(){
57201 var totalWidth = 0;
57202 for(var i = 0; i < this.config.length; i++){
57203 if(this.isLocked(i) && !this.isHidden(i)){
57204 this.totalWidth += this.getColumnWidth(i);
57210 getLockedCount : function(){
57211 for(var i = 0, len = this.config.length; i < len; i++){
57212 if(!this.isLocked(i)){
57217 return this.config.length;
57221 * Returns the number of columns.
57224 getColumnCount : function(visibleOnly){
57225 if(visibleOnly === true){
57227 for(var i = 0, len = this.config.length; i < len; i++){
57228 if(!this.isHidden(i)){
57234 return this.config.length;
57238 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57239 * @param {Function} fn
57240 * @param {Object} scope (optional)
57241 * @return {Array} result
57243 getColumnsBy : function(fn, scope){
57245 for(var i = 0, len = this.config.length; i < len; i++){
57246 var c = this.config[i];
57247 if(fn.call(scope||this, c, i) === true){
57255 * Returns true if the specified column is sortable.
57256 * @param {Number} col The column index
57257 * @return {Boolean}
57259 isSortable : function(col){
57260 if(typeof this.config[col].sortable == "undefined"){
57261 return this.defaultSortable;
57263 return this.config[col].sortable;
57267 * Returns the rendering (formatting) function defined for the column.
57268 * @param {Number} col The column index.
57269 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57271 getRenderer : function(col){
57272 if(!this.config[col].renderer){
57273 return Roo.grid.ColumnModel.defaultRenderer;
57275 return this.config[col].renderer;
57279 * Sets the rendering (formatting) function for a column.
57280 * @param {Number} col The column index
57281 * @param {Function} fn The function to use to process the cell's raw data
57282 * to return HTML markup for the grid view. The render function is called with
57283 * the following parameters:<ul>
57284 * <li>Data value.</li>
57285 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57286 * <li>css A CSS style string to apply to the table cell.</li>
57287 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57288 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57289 * <li>Row index</li>
57290 * <li>Column index</li>
57291 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57293 setRenderer : function(col, fn){
57294 this.config[col].renderer = fn;
57298 * Returns the width for the specified column.
57299 * @param {Number} col The column index
57302 getColumnWidth : function(col){
57303 return this.config[col].width * 1 || this.defaultWidth;
57307 * Sets the width for a column.
57308 * @param {Number} col The column index
57309 * @param {Number} width The new width
57311 setColumnWidth : function(col, width, suppressEvent){
57312 this.config[col].width = width;
57313 this.totalWidth = null;
57314 if(!suppressEvent){
57315 this.fireEvent("widthchange", this, col, width);
57320 * Returns the total width of all columns.
57321 * @param {Boolean} includeHidden True to include hidden column widths
57324 getTotalWidth : function(includeHidden){
57325 if(!this.totalWidth){
57326 this.totalWidth = 0;
57327 for(var i = 0, len = this.config.length; i < len; i++){
57328 if(includeHidden || !this.isHidden(i)){
57329 this.totalWidth += this.getColumnWidth(i);
57333 return this.totalWidth;
57337 * Returns the header for the specified column.
57338 * @param {Number} col The column index
57341 getColumnHeader : function(col){
57342 return this.config[col].header;
57346 * Sets the header for a column.
57347 * @param {Number} col The column index
57348 * @param {String} header The new header
57350 setColumnHeader : function(col, header){
57351 this.config[col].header = header;
57352 this.fireEvent("headerchange", this, col, header);
57356 * Returns the tooltip for the specified column.
57357 * @param {Number} col The column index
57360 getColumnTooltip : function(col){
57361 return this.config[col].tooltip;
57364 * Sets the tooltip for a column.
57365 * @param {Number} col The column index
57366 * @param {String} tooltip The new tooltip
57368 setColumnTooltip : function(col, tooltip){
57369 this.config[col].tooltip = tooltip;
57373 * Returns the dataIndex for the specified column.
57374 * @param {Number} col The column index
57377 getDataIndex : function(col){
57378 return this.config[col].dataIndex;
57382 * Sets the dataIndex for a column.
57383 * @param {Number} col The column index
57384 * @param {Number} dataIndex The new dataIndex
57386 setDataIndex : function(col, dataIndex){
57387 this.config[col].dataIndex = dataIndex;
57393 * Returns true if the cell is editable.
57394 * @param {Number} colIndex The column index
57395 * @param {Number} rowIndex The row index - this is nto actually used..?
57396 * @return {Boolean}
57398 isCellEditable : function(colIndex, rowIndex){
57399 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57403 * Returns the editor defined for the cell/column.
57404 * return false or null to disable editing.
57405 * @param {Number} colIndex The column index
57406 * @param {Number} rowIndex The row index
57409 getCellEditor : function(colIndex, rowIndex){
57410 return this.config[colIndex].editor;
57414 * Sets if a column is editable.
57415 * @param {Number} col The column index
57416 * @param {Boolean} editable True if the column is editable
57418 setEditable : function(col, editable){
57419 this.config[col].editable = editable;
57424 * Returns true if the column is hidden.
57425 * @param {Number} colIndex The column index
57426 * @return {Boolean}
57428 isHidden : function(colIndex){
57429 return this.config[colIndex].hidden;
57434 * Returns true if the column width cannot be changed
57436 isFixed : function(colIndex){
57437 return this.config[colIndex].fixed;
57441 * Returns true if the column can be resized
57442 * @return {Boolean}
57444 isResizable : function(colIndex){
57445 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57448 * Sets if a column is hidden.
57449 * @param {Number} colIndex The column index
57450 * @param {Boolean} hidden True if the column is hidden
57452 setHidden : function(colIndex, hidden){
57453 this.config[colIndex].hidden = hidden;
57454 this.totalWidth = null;
57455 this.fireEvent("hiddenchange", this, colIndex, hidden);
57459 * Sets the editor for a column.
57460 * @param {Number} col The column index
57461 * @param {Object} editor The editor object
57463 setEditor : function(col, editor){
57464 this.config[col].editor = editor;
57468 Roo.grid.ColumnModel.defaultRenderer = function(value)
57470 if(typeof value == "object") {
57473 if(typeof value == "string" && value.length < 1){
57477 return String.format("{0}", value);
57480 // Alias for backwards compatibility
57481 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57484 * Ext JS Library 1.1.1
57485 * Copyright(c) 2006-2007, Ext JS, LLC.
57487 * Originally Released Under LGPL - original licence link has changed is not relivant.
57490 * <script type="text/javascript">
57494 * @class Roo.grid.AbstractSelectionModel
57495 * @extends Roo.util.Observable
57496 * Abstract base class for grid SelectionModels. It provides the interface that should be
57497 * implemented by descendant classes. This class should not be directly instantiated.
57500 Roo.grid.AbstractSelectionModel = function(){
57501 this.locked = false;
57502 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57505 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57506 /** @ignore Called by the grid automatically. Do not call directly. */
57507 init : function(grid){
57513 * Locks the selections.
57516 this.locked = true;
57520 * Unlocks the selections.
57522 unlock : function(){
57523 this.locked = false;
57527 * Returns true if the selections are locked.
57528 * @return {Boolean}
57530 isLocked : function(){
57531 return this.locked;
57535 * Ext JS Library 1.1.1
57536 * Copyright(c) 2006-2007, Ext JS, LLC.
57538 * Originally Released Under LGPL - original licence link has changed is not relivant.
57541 * <script type="text/javascript">
57544 * @extends Roo.grid.AbstractSelectionModel
57545 * @class Roo.grid.RowSelectionModel
57546 * The default SelectionModel used by {@link Roo.grid.Grid}.
57547 * It supports multiple selections and keyboard selection/navigation.
57549 * @param {Object} config
57551 Roo.grid.RowSelectionModel = function(config){
57552 Roo.apply(this, config);
57553 this.selections = new Roo.util.MixedCollection(false, function(o){
57558 this.lastActive = false;
57562 * @event selectionchange
57563 * Fires when the selection changes
57564 * @param {SelectionModel} this
57566 "selectionchange" : true,
57568 * @event afterselectionchange
57569 * Fires after the selection changes (eg. by key press or clicking)
57570 * @param {SelectionModel} this
57572 "afterselectionchange" : true,
57574 * @event beforerowselect
57575 * Fires when a row is selected being selected, return false to cancel.
57576 * @param {SelectionModel} this
57577 * @param {Number} rowIndex The selected index
57578 * @param {Boolean} keepExisting False if other selections will be cleared
57580 "beforerowselect" : true,
57583 * Fires when a row is selected.
57584 * @param {SelectionModel} this
57585 * @param {Number} rowIndex The selected index
57586 * @param {Roo.data.Record} r The record
57588 "rowselect" : true,
57590 * @event rowdeselect
57591 * Fires when a row is deselected.
57592 * @param {SelectionModel} this
57593 * @param {Number} rowIndex The selected index
57595 "rowdeselect" : true
57597 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57598 this.locked = false;
57601 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57603 * @cfg {Boolean} singleSelect
57604 * True to allow selection of only one row at a time (defaults to false)
57606 singleSelect : false,
57609 initEvents : function(){
57611 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57612 this.grid.on("mousedown", this.handleMouseDown, this);
57613 }else{ // allow click to work like normal
57614 this.grid.on("rowclick", this.handleDragableRowClick, this);
57617 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57618 "up" : function(e){
57620 this.selectPrevious(e.shiftKey);
57621 }else if(this.last !== false && this.lastActive !== false){
57622 var last = this.last;
57623 this.selectRange(this.last, this.lastActive-1);
57624 this.grid.getView().focusRow(this.lastActive);
57625 if(last !== false){
57629 this.selectFirstRow();
57631 this.fireEvent("afterselectionchange", this);
57633 "down" : function(e){
57635 this.selectNext(e.shiftKey);
57636 }else if(this.last !== false && this.lastActive !== false){
57637 var last = this.last;
57638 this.selectRange(this.last, this.lastActive+1);
57639 this.grid.getView().focusRow(this.lastActive);
57640 if(last !== false){
57644 this.selectFirstRow();
57646 this.fireEvent("afterselectionchange", this);
57651 var view = this.grid.view;
57652 view.on("refresh", this.onRefresh, this);
57653 view.on("rowupdated", this.onRowUpdated, this);
57654 view.on("rowremoved", this.onRemove, this);
57658 onRefresh : function(){
57659 var ds = this.grid.dataSource, i, v = this.grid.view;
57660 var s = this.selections;
57661 s.each(function(r){
57662 if((i = ds.indexOfId(r.id)) != -1){
57664 s.add(ds.getAt(i)); // updating the selection relate data
57672 onRemove : function(v, index, r){
57673 this.selections.remove(r);
57677 onRowUpdated : function(v, index, r){
57678 if(this.isSelected(r)){
57679 v.onRowSelect(index);
57685 * @param {Array} records The records to select
57686 * @param {Boolean} keepExisting (optional) True to keep existing selections
57688 selectRecords : function(records, keepExisting){
57690 this.clearSelections();
57692 var ds = this.grid.dataSource;
57693 for(var i = 0, len = records.length; i < len; i++){
57694 this.selectRow(ds.indexOf(records[i]), true);
57699 * Gets the number of selected rows.
57702 getCount : function(){
57703 return this.selections.length;
57707 * Selects the first row in the grid.
57709 selectFirstRow : function(){
57714 * Select the last row.
57715 * @param {Boolean} keepExisting (optional) True to keep existing selections
57717 selectLastRow : function(keepExisting){
57718 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57722 * Selects the row immediately following the last selected row.
57723 * @param {Boolean} keepExisting (optional) True to keep existing selections
57725 selectNext : function(keepExisting){
57726 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57727 this.selectRow(this.last+1, keepExisting);
57728 this.grid.getView().focusRow(this.last);
57733 * Selects the row that precedes the last selected row.
57734 * @param {Boolean} keepExisting (optional) True to keep existing selections
57736 selectPrevious : function(keepExisting){
57738 this.selectRow(this.last-1, keepExisting);
57739 this.grid.getView().focusRow(this.last);
57744 * Returns the selected records
57745 * @return {Array} Array of selected records
57747 getSelections : function(){
57748 return [].concat(this.selections.items);
57752 * Returns the first selected record.
57755 getSelected : function(){
57756 return this.selections.itemAt(0);
57761 * Clears all selections.
57763 clearSelections : function(fast){
57768 var ds = this.grid.dataSource;
57769 var s = this.selections;
57770 s.each(function(r){
57771 this.deselectRow(ds.indexOfId(r.id));
57775 this.selections.clear();
57782 * Selects all rows.
57784 selectAll : function(){
57788 this.selections.clear();
57789 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57790 this.selectRow(i, true);
57795 * Returns True if there is a selection.
57796 * @return {Boolean}
57798 hasSelection : function(){
57799 return this.selections.length > 0;
57803 * Returns True if the specified row is selected.
57804 * @param {Number/Record} record The record or index of the record to check
57805 * @return {Boolean}
57807 isSelected : function(index){
57808 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57809 return (r && this.selections.key(r.id) ? true : false);
57813 * Returns True if the specified record id is selected.
57814 * @param {String} id The id of record to check
57815 * @return {Boolean}
57817 isIdSelected : function(id){
57818 return (this.selections.key(id) ? true : false);
57822 handleMouseDown : function(e, t){
57823 var view = this.grid.getView(), rowIndex;
57824 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57827 if(e.shiftKey && this.last !== false){
57828 var last = this.last;
57829 this.selectRange(last, rowIndex, e.ctrlKey);
57830 this.last = last; // reset the last
57831 view.focusRow(rowIndex);
57833 var isSelected = this.isSelected(rowIndex);
57834 if(e.button !== 0 && isSelected){
57835 view.focusRow(rowIndex);
57836 }else if(e.ctrlKey && isSelected){
57837 this.deselectRow(rowIndex);
57838 }else if(!isSelected){
57839 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57840 view.focusRow(rowIndex);
57843 this.fireEvent("afterselectionchange", this);
57846 handleDragableRowClick : function(grid, rowIndex, e)
57848 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57849 this.selectRow(rowIndex, false);
57850 grid.view.focusRow(rowIndex);
57851 this.fireEvent("afterselectionchange", this);
57856 * Selects multiple rows.
57857 * @param {Array} rows Array of the indexes of the row to select
57858 * @param {Boolean} keepExisting (optional) True to keep existing selections
57860 selectRows : function(rows, keepExisting){
57862 this.clearSelections();
57864 for(var i = 0, len = rows.length; i < len; i++){
57865 this.selectRow(rows[i], true);
57870 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57871 * @param {Number} startRow The index of the first row in the range
57872 * @param {Number} endRow The index of the last row in the range
57873 * @param {Boolean} keepExisting (optional) True to retain existing selections
57875 selectRange : function(startRow, endRow, keepExisting){
57880 this.clearSelections();
57882 if(startRow <= endRow){
57883 for(var i = startRow; i <= endRow; i++){
57884 this.selectRow(i, true);
57887 for(var i = startRow; i >= endRow; i--){
57888 this.selectRow(i, true);
57894 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57895 * @param {Number} startRow The index of the first row in the range
57896 * @param {Number} endRow The index of the last row in the range
57898 deselectRange : function(startRow, endRow, preventViewNotify){
57902 for(var i = startRow; i <= endRow; i++){
57903 this.deselectRow(i, preventViewNotify);
57909 * @param {Number} row The index of the row to select
57910 * @param {Boolean} keepExisting (optional) True to keep existing selections
57912 selectRow : function(index, keepExisting, preventViewNotify){
57913 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57916 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57917 if(!keepExisting || this.singleSelect){
57918 this.clearSelections();
57920 var r = this.grid.dataSource.getAt(index);
57921 this.selections.add(r);
57922 this.last = this.lastActive = index;
57923 if(!preventViewNotify){
57924 this.grid.getView().onRowSelect(index);
57926 this.fireEvent("rowselect", this, index, r);
57927 this.fireEvent("selectionchange", this);
57933 * @param {Number} row The index of the row to deselect
57935 deselectRow : function(index, preventViewNotify){
57939 if(this.last == index){
57942 if(this.lastActive == index){
57943 this.lastActive = false;
57945 var r = this.grid.dataSource.getAt(index);
57946 this.selections.remove(r);
57947 if(!preventViewNotify){
57948 this.grid.getView().onRowDeselect(index);
57950 this.fireEvent("rowdeselect", this, index);
57951 this.fireEvent("selectionchange", this);
57955 restoreLast : function(){
57957 this.last = this._last;
57962 acceptsNav : function(row, col, cm){
57963 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57967 onEditorKey : function(field, e){
57968 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57973 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57975 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57977 }else if(k == e.ENTER && !e.ctrlKey){
57981 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57983 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57985 }else if(k == e.ESC){
57989 g.startEditing(newCell[0], newCell[1]);
57994 * Ext JS Library 1.1.1
57995 * Copyright(c) 2006-2007, Ext JS, LLC.
57997 * Originally Released Under LGPL - original licence link has changed is not relivant.
58000 * <script type="text/javascript">
58003 * @class Roo.grid.CellSelectionModel
58004 * @extends Roo.grid.AbstractSelectionModel
58005 * This class provides the basic implementation for cell selection in a grid.
58007 * @param {Object} config The object containing the configuration of this model.
58008 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58010 Roo.grid.CellSelectionModel = function(config){
58011 Roo.apply(this, config);
58013 this.selection = null;
58017 * @event beforerowselect
58018 * Fires before a cell is selected.
58019 * @param {SelectionModel} this
58020 * @param {Number} rowIndex The selected row index
58021 * @param {Number} colIndex The selected cell index
58023 "beforecellselect" : true,
58025 * @event cellselect
58026 * Fires when a cell is selected.
58027 * @param {SelectionModel} this
58028 * @param {Number} rowIndex The selected row index
58029 * @param {Number} colIndex The selected cell index
58031 "cellselect" : true,
58033 * @event selectionchange
58034 * Fires when the active selection changes.
58035 * @param {SelectionModel} this
58036 * @param {Object} selection null for no selection or an object (o) with two properties
58038 <li>o.record: the record object for the row the selection is in</li>
58039 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58042 "selectionchange" : true,
58045 * Fires when the tab (or enter) was pressed on the last editable cell
58046 * You can use this to trigger add new row.
58047 * @param {SelectionModel} this
58051 * @event beforeeditnext
58052 * Fires before the next editable sell is made active
58053 * You can use this to skip to another cell or fire the tabend
58054 * if you set cell to false
58055 * @param {Object} eventdata object : { cell : [ row, col ] }
58057 "beforeeditnext" : true
58059 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58062 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58064 enter_is_tab: false,
58067 initEvents : function(){
58068 this.grid.on("mousedown", this.handleMouseDown, this);
58069 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58070 var view = this.grid.view;
58071 view.on("refresh", this.onViewChange, this);
58072 view.on("rowupdated", this.onRowUpdated, this);
58073 view.on("beforerowremoved", this.clearSelections, this);
58074 view.on("beforerowsinserted", this.clearSelections, this);
58075 if(this.grid.isEditor){
58076 this.grid.on("beforeedit", this.beforeEdit, this);
58081 beforeEdit : function(e){
58082 this.select(e.row, e.column, false, true, e.record);
58086 onRowUpdated : function(v, index, r){
58087 if(this.selection && this.selection.record == r){
58088 v.onCellSelect(index, this.selection.cell[1]);
58093 onViewChange : function(){
58094 this.clearSelections(true);
58098 * Returns the currently selected cell,.
58099 * @return {Array} The selected cell (row, column) or null if none selected.
58101 getSelectedCell : function(){
58102 return this.selection ? this.selection.cell : null;
58106 * Clears all selections.
58107 * @param {Boolean} true to prevent the gridview from being notified about the change.
58109 clearSelections : function(preventNotify){
58110 var s = this.selection;
58112 if(preventNotify !== true){
58113 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58115 this.selection = null;
58116 this.fireEvent("selectionchange", this, null);
58121 * Returns true if there is a selection.
58122 * @return {Boolean}
58124 hasSelection : function(){
58125 return this.selection ? true : false;
58129 handleMouseDown : function(e, t){
58130 var v = this.grid.getView();
58131 if(this.isLocked()){
58134 var row = v.findRowIndex(t);
58135 var cell = v.findCellIndex(t);
58136 if(row !== false && cell !== false){
58137 this.select(row, cell);
58143 * @param {Number} rowIndex
58144 * @param {Number} collIndex
58146 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58147 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58148 this.clearSelections();
58149 r = r || this.grid.dataSource.getAt(rowIndex);
58152 cell : [rowIndex, colIndex]
58154 if(!preventViewNotify){
58155 var v = this.grid.getView();
58156 v.onCellSelect(rowIndex, colIndex);
58157 if(preventFocus !== true){
58158 v.focusCell(rowIndex, colIndex);
58161 this.fireEvent("cellselect", this, rowIndex, colIndex);
58162 this.fireEvent("selectionchange", this, this.selection);
58167 isSelectable : function(rowIndex, colIndex, cm){
58168 return !cm.isHidden(colIndex);
58172 handleKeyDown : function(e){
58173 //Roo.log('Cell Sel Model handleKeyDown');
58174 if(!e.isNavKeyPress()){
58177 var g = this.grid, s = this.selection;
58180 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58182 this.select(cell[0], cell[1]);
58187 var walk = function(row, col, step){
58188 return g.walkCells(row, col, step, sm.isSelectable, sm);
58190 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58197 // handled by onEditorKey
58198 if (g.isEditor && g.editing) {
58202 newCell = walk(r, c-1, -1);
58204 newCell = walk(r, c+1, 1);
58209 newCell = walk(r+1, c, 1);
58213 newCell = walk(r-1, c, -1);
58217 newCell = walk(r, c+1, 1);
58221 newCell = walk(r, c-1, -1);
58226 if(g.isEditor && !g.editing){
58227 g.startEditing(r, c);
58236 this.select(newCell[0], newCell[1]);
58242 acceptsNav : function(row, col, cm){
58243 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58247 * @param {Number} field (not used) - as it's normally used as a listener
58248 * @param {Number} e - event - fake it by using
58250 * var e = Roo.EventObjectImpl.prototype;
58251 * e.keyCode = e.TAB
58255 onEditorKey : function(field, e){
58257 var k = e.getKey(),
58260 ed = g.activeEditor,
58262 ///Roo.log('onEditorKey' + k);
58265 if (this.enter_is_tab && k == e.ENTER) {
58271 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58273 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58279 } else if(k == e.ENTER && !e.ctrlKey){
58282 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58284 } else if(k == e.ESC){
58289 var ecall = { cell : newCell, forward : forward };
58290 this.fireEvent('beforeeditnext', ecall );
58291 newCell = ecall.cell;
58292 forward = ecall.forward;
58296 //Roo.log('next cell after edit');
58297 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58298 } else if (forward) {
58299 // tabbed past last
58300 this.fireEvent.defer(100, this, ['tabend',this]);
58305 * Ext JS Library 1.1.1
58306 * Copyright(c) 2006-2007, Ext JS, LLC.
58308 * Originally Released Under LGPL - original licence link has changed is not relivant.
58311 * <script type="text/javascript">
58315 * @class Roo.grid.EditorGrid
58316 * @extends Roo.grid.Grid
58317 * Class for creating and editable grid.
58318 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58319 * The container MUST have some type of size defined for the grid to fill. The container will be
58320 * automatically set to position relative if it isn't already.
58321 * @param {Object} dataSource The data model to bind to
58322 * @param {Object} colModel The column model with info about this grid's columns
58324 Roo.grid.EditorGrid = function(container, config){
58325 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58326 this.getGridEl().addClass("xedit-grid");
58328 if(!this.selModel){
58329 this.selModel = new Roo.grid.CellSelectionModel();
58332 this.activeEditor = null;
58336 * @event beforeedit
58337 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58338 * <ul style="padding:5px;padding-left:16px;">
58339 * <li>grid - This grid</li>
58340 * <li>record - The record being edited</li>
58341 * <li>field - The field name being edited</li>
58342 * <li>value - The value for the field being edited.</li>
58343 * <li>row - The grid row index</li>
58344 * <li>column - The grid column index</li>
58345 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58347 * @param {Object} e An edit event (see above for description)
58349 "beforeedit" : true,
58352 * Fires after a cell is edited. <br />
58353 * <ul style="padding:5px;padding-left:16px;">
58354 * <li>grid - This grid</li>
58355 * <li>record - The record being edited</li>
58356 * <li>field - The field name being edited</li>
58357 * <li>value - The value being set</li>
58358 * <li>originalValue - The original value for the field, before the edit.</li>
58359 * <li>row - The grid row index</li>
58360 * <li>column - The grid column index</li>
58362 * @param {Object} e An edit event (see above for description)
58364 "afteredit" : true,
58366 * @event validateedit
58367 * Fires after a cell is edited, but before the value is set in the record.
58368 * You can use this to modify the value being set in the field, Return false
58369 * to cancel the change. The edit event object has the following properties <br />
58370 * <ul style="padding:5px;padding-left:16px;">
58371 * <li>editor - This editor</li>
58372 * <li>grid - This grid</li>
58373 * <li>record - The record being edited</li>
58374 * <li>field - The field name being edited</li>
58375 * <li>value - The value being set</li>
58376 * <li>originalValue - The original value for the field, before the edit.</li>
58377 * <li>row - The grid row index</li>
58378 * <li>column - The grid column index</li>
58379 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58381 * @param {Object} e An edit event (see above for description)
58383 "validateedit" : true
58385 this.on("bodyscroll", this.stopEditing, this);
58386 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58389 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58391 * @cfg {Number} clicksToEdit
58392 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58399 trackMouseOver: false, // causes very odd FF errors
58401 onCellDblClick : function(g, row, col){
58402 this.startEditing(row, col);
58405 onEditComplete : function(ed, value, startValue){
58406 this.editing = false;
58407 this.activeEditor = null;
58408 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58410 var field = this.colModel.getDataIndex(ed.col);
58415 originalValue: startValue,
58422 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58425 if(String(value) !== String(startValue)){
58427 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58428 r.set(field, e.value);
58429 // if we are dealing with a combo box..
58430 // then we also set the 'name' colum to be the displayField
58431 if (ed.field.displayField && ed.field.name) {
58432 r.set(ed.field.name, ed.field.el.dom.value);
58435 delete e.cancel; //?? why!!!
58436 this.fireEvent("afteredit", e);
58439 this.fireEvent("afteredit", e); // always fire it!
58441 this.view.focusCell(ed.row, ed.col);
58445 * Starts editing the specified for the specified row/column
58446 * @param {Number} rowIndex
58447 * @param {Number} colIndex
58449 startEditing : function(row, col){
58450 this.stopEditing();
58451 if(this.colModel.isCellEditable(col, row)){
58452 this.view.ensureVisible(row, col, true);
58454 var r = this.dataSource.getAt(row);
58455 var field = this.colModel.getDataIndex(col);
58456 var cell = Roo.get(this.view.getCell(row,col));
58461 value: r.data[field],
58466 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58467 this.editing = true;
58468 var ed = this.colModel.getCellEditor(col, row);
58474 ed.render(ed.parentEl || document.body);
58480 (function(){ // complex but required for focus issues in safari, ie and opera
58484 ed.on("complete", this.onEditComplete, this, {single: true});
58485 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58486 this.activeEditor = ed;
58487 var v = r.data[field];
58488 ed.startEdit(this.view.getCell(row, col), v);
58489 // combo's with 'displayField and name set
58490 if (ed.field.displayField && ed.field.name) {
58491 ed.field.el.dom.value = r.data[ed.field.name];
58495 }).defer(50, this);
58501 * Stops any active editing
58503 stopEditing : function(){
58504 if(this.activeEditor){
58505 this.activeEditor.completeEdit();
58507 this.activeEditor = null;
58511 * Called to get grid's drag proxy text, by default returns this.ddText.
58514 getDragDropText : function(){
58515 var count = this.selModel.getSelectedCell() ? 1 : 0;
58516 return String.format(this.ddText, count, count == 1 ? '' : 's');
58521 * Ext JS Library 1.1.1
58522 * Copyright(c) 2006-2007, Ext JS, LLC.
58524 * Originally Released Under LGPL - original licence link has changed is not relivant.
58527 * <script type="text/javascript">
58530 // private - not really -- you end up using it !
58531 // This is a support class used internally by the Grid components
58534 * @class Roo.grid.GridEditor
58535 * @extends Roo.Editor
58536 * Class for creating and editable grid elements.
58537 * @param {Object} config any settings (must include field)
58539 Roo.grid.GridEditor = function(field, config){
58540 if (!config && field.field) {
58542 field = Roo.factory(config.field, Roo.form);
58544 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58545 field.monitorTab = false;
58548 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58551 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58554 alignment: "tl-tl",
58557 cls: "x-small-editor x-grid-editor",
58562 * Ext JS Library 1.1.1
58563 * Copyright(c) 2006-2007, Ext JS, LLC.
58565 * Originally Released Under LGPL - original licence link has changed is not relivant.
58568 * <script type="text/javascript">
58573 Roo.grid.PropertyRecord = Roo.data.Record.create([
58574 {name:'name',type:'string'}, 'value'
58578 Roo.grid.PropertyStore = function(grid, source){
58580 this.store = new Roo.data.Store({
58581 recordType : Roo.grid.PropertyRecord
58583 this.store.on('update', this.onUpdate, this);
58585 this.setSource(source);
58587 Roo.grid.PropertyStore.superclass.constructor.call(this);
58592 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58593 setSource : function(o){
58595 this.store.removeAll();
58598 if(this.isEditableValue(o[k])){
58599 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58602 this.store.loadRecords({records: data}, {}, true);
58605 onUpdate : function(ds, record, type){
58606 if(type == Roo.data.Record.EDIT){
58607 var v = record.data['value'];
58608 var oldValue = record.modified['value'];
58609 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58610 this.source[record.id] = v;
58612 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58619 getProperty : function(row){
58620 return this.store.getAt(row);
58623 isEditableValue: function(val){
58624 if(val && val instanceof Date){
58626 }else if(typeof val == 'object' || typeof val == 'function'){
58632 setValue : function(prop, value){
58633 this.source[prop] = value;
58634 this.store.getById(prop).set('value', value);
58637 getSource : function(){
58638 return this.source;
58642 Roo.grid.PropertyColumnModel = function(grid, store){
58645 g.PropertyColumnModel.superclass.constructor.call(this, [
58646 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58647 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58649 this.store = store;
58650 this.bselect = Roo.DomHelper.append(document.body, {
58651 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58652 {tag: 'option', value: 'true', html: 'true'},
58653 {tag: 'option', value: 'false', html: 'false'}
58656 Roo.id(this.bselect);
58659 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58660 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58661 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58662 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58663 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58665 this.renderCellDelegate = this.renderCell.createDelegate(this);
58666 this.renderPropDelegate = this.renderProp.createDelegate(this);
58669 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58673 valueText : 'Value',
58675 dateFormat : 'm/j/Y',
58678 renderDate : function(dateVal){
58679 return dateVal.dateFormat(this.dateFormat);
58682 renderBool : function(bVal){
58683 return bVal ? 'true' : 'false';
58686 isCellEditable : function(colIndex, rowIndex){
58687 return colIndex == 1;
58690 getRenderer : function(col){
58692 this.renderCellDelegate : this.renderPropDelegate;
58695 renderProp : function(v){
58696 return this.getPropertyName(v);
58699 renderCell : function(val){
58701 if(val instanceof Date){
58702 rv = this.renderDate(val);
58703 }else if(typeof val == 'boolean'){
58704 rv = this.renderBool(val);
58706 return Roo.util.Format.htmlEncode(rv);
58709 getPropertyName : function(name){
58710 var pn = this.grid.propertyNames;
58711 return pn && pn[name] ? pn[name] : name;
58714 getCellEditor : function(colIndex, rowIndex){
58715 var p = this.store.getProperty(rowIndex);
58716 var n = p.data['name'], val = p.data['value'];
58718 if(typeof(this.grid.customEditors[n]) == 'string'){
58719 return this.editors[this.grid.customEditors[n]];
58721 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58722 return this.grid.customEditors[n];
58724 if(val instanceof Date){
58725 return this.editors['date'];
58726 }else if(typeof val == 'number'){
58727 return this.editors['number'];
58728 }else if(typeof val == 'boolean'){
58729 return this.editors['boolean'];
58731 return this.editors['string'];
58737 * @class Roo.grid.PropertyGrid
58738 * @extends Roo.grid.EditorGrid
58739 * This class represents the interface of a component based property grid control.
58740 * <br><br>Usage:<pre><code>
58741 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58749 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58750 * The container MUST have some type of size defined for the grid to fill. The container will be
58751 * automatically set to position relative if it isn't already.
58752 * @param {Object} config A config object that sets properties on this grid.
58754 Roo.grid.PropertyGrid = function(container, config){
58755 config = config || {};
58756 var store = new Roo.grid.PropertyStore(this);
58757 this.store = store;
58758 var cm = new Roo.grid.PropertyColumnModel(this, store);
58759 store.store.sort('name', 'ASC');
58760 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58763 enableColLock:false,
58764 enableColumnMove:false,
58766 trackMouseOver: false,
58769 this.getGridEl().addClass('x-props-grid');
58770 this.lastEditRow = null;
58771 this.on('columnresize', this.onColumnResize, this);
58774 * @event beforepropertychange
58775 * Fires before a property changes (return false to stop?)
58776 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58777 * @param {String} id Record Id
58778 * @param {String} newval New Value
58779 * @param {String} oldval Old Value
58781 "beforepropertychange": true,
58783 * @event propertychange
58784 * Fires after a property changes
58785 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58786 * @param {String} id Record Id
58787 * @param {String} newval New Value
58788 * @param {String} oldval Old Value
58790 "propertychange": true
58792 this.customEditors = this.customEditors || {};
58794 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58797 * @cfg {Object} customEditors map of colnames=> custom editors.
58798 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58799 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58800 * false disables editing of the field.
58804 * @cfg {Object} propertyNames map of property Names to their displayed value
58807 render : function(){
58808 Roo.grid.PropertyGrid.superclass.render.call(this);
58809 this.autoSize.defer(100, this);
58812 autoSize : function(){
58813 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58815 this.view.fitColumns();
58819 onColumnResize : function(){
58820 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58824 * Sets the data for the Grid
58825 * accepts a Key => Value object of all the elements avaiable.
58826 * @param {Object} data to appear in grid.
58828 setSource : function(source){
58829 this.store.setSource(source);
58833 * Gets all the data from the grid.
58834 * @return {Object} data data stored in grid
58836 getSource : function(){
58837 return this.store.getSource();
58846 * @class Roo.grid.Calendar
58847 * @extends Roo.util.Grid
58848 * This class extends the Grid to provide a calendar widget
58849 * <br><br>Usage:<pre><code>
58850 var grid = new Roo.grid.Calendar("my-container-id", {
58853 selModel: mySelectionModel,
58854 autoSizeColumns: true,
58855 monitorWindowResize: false,
58856 trackMouseOver: true
58857 eventstore : real data store..
58863 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58864 * The container MUST have some type of size defined for the grid to fill. The container will be
58865 * automatically set to position relative if it isn't already.
58866 * @param {Object} config A config object that sets properties on this grid.
58868 Roo.grid.Calendar = function(container, config){
58869 // initialize the container
58870 this.container = Roo.get(container);
58871 this.container.update("");
58872 this.container.setStyle("overflow", "hidden");
58873 this.container.addClass('x-grid-container');
58875 this.id = this.container.id;
58877 Roo.apply(this, config);
58878 // check and correct shorthanded configs
58882 for (var r = 0;r < 6;r++) {
58885 for (var c =0;c < 7;c++) {
58889 if (this.eventStore) {
58890 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58891 this.eventStore.on('load',this.onLoad, this);
58892 this.eventStore.on('beforeload',this.clearEvents, this);
58896 this.dataSource = new Roo.data.Store({
58897 proxy: new Roo.data.MemoryProxy(rows),
58898 reader: new Roo.data.ArrayReader({}, [
58899 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58902 this.dataSource.load();
58903 this.ds = this.dataSource;
58904 this.ds.xmodule = this.xmodule || false;
58907 var cellRender = function(v,x,r)
58909 return String.format(
58910 '<div class="fc-day fc-widget-content"><div>' +
58911 '<div class="fc-event-container"></div>' +
58912 '<div class="fc-day-number">{0}</div>'+
58914 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58915 '</div></div>', v);
58920 this.colModel = new Roo.grid.ColumnModel( [
58922 xtype: 'ColumnModel',
58924 dataIndex : 'weekday0',
58926 renderer : cellRender
58929 xtype: 'ColumnModel',
58931 dataIndex : 'weekday1',
58933 renderer : cellRender
58936 xtype: 'ColumnModel',
58938 dataIndex : 'weekday2',
58939 header : 'Tuesday',
58940 renderer : cellRender
58943 xtype: 'ColumnModel',
58945 dataIndex : 'weekday3',
58946 header : 'Wednesday',
58947 renderer : cellRender
58950 xtype: 'ColumnModel',
58952 dataIndex : 'weekday4',
58953 header : 'Thursday',
58954 renderer : cellRender
58957 xtype: 'ColumnModel',
58959 dataIndex : 'weekday5',
58961 renderer : cellRender
58964 xtype: 'ColumnModel',
58966 dataIndex : 'weekday6',
58967 header : 'Saturday',
58968 renderer : cellRender
58971 this.cm = this.colModel;
58972 this.cm.xmodule = this.xmodule || false;
58976 //this.selModel = new Roo.grid.CellSelectionModel();
58977 //this.sm = this.selModel;
58978 //this.selModel.init(this);
58982 this.container.setWidth(this.width);
58986 this.container.setHeight(this.height);
58993 * The raw click event for the entire grid.
58994 * @param {Roo.EventObject} e
58999 * The raw dblclick event for the entire grid.
59000 * @param {Roo.EventObject} e
59004 * @event contextmenu
59005 * The raw contextmenu event for the entire grid.
59006 * @param {Roo.EventObject} e
59008 "contextmenu" : true,
59011 * The raw mousedown event for the entire grid.
59012 * @param {Roo.EventObject} e
59014 "mousedown" : true,
59017 * The raw mouseup event for the entire grid.
59018 * @param {Roo.EventObject} e
59023 * The raw mouseover event for the entire grid.
59024 * @param {Roo.EventObject} e
59026 "mouseover" : true,
59029 * The raw mouseout event for the entire grid.
59030 * @param {Roo.EventObject} e
59035 * The raw keypress event for the entire grid.
59036 * @param {Roo.EventObject} e
59041 * The raw keydown event for the entire grid.
59042 * @param {Roo.EventObject} e
59050 * Fires when a cell is clicked
59051 * @param {Grid} this
59052 * @param {Number} rowIndex
59053 * @param {Number} columnIndex
59054 * @param {Roo.EventObject} e
59056 "cellclick" : true,
59058 * @event celldblclick
59059 * Fires when a cell is double clicked
59060 * @param {Grid} this
59061 * @param {Number} rowIndex
59062 * @param {Number} columnIndex
59063 * @param {Roo.EventObject} e
59065 "celldblclick" : true,
59068 * Fires when a row is clicked
59069 * @param {Grid} this
59070 * @param {Number} rowIndex
59071 * @param {Roo.EventObject} e
59075 * @event rowdblclick
59076 * Fires when a row is double clicked
59077 * @param {Grid} this
59078 * @param {Number} rowIndex
59079 * @param {Roo.EventObject} e
59081 "rowdblclick" : true,
59083 * @event headerclick
59084 * Fires when a header is clicked
59085 * @param {Grid} this
59086 * @param {Number} columnIndex
59087 * @param {Roo.EventObject} e
59089 "headerclick" : true,
59091 * @event headerdblclick
59092 * Fires when a header cell is double clicked
59093 * @param {Grid} this
59094 * @param {Number} columnIndex
59095 * @param {Roo.EventObject} e
59097 "headerdblclick" : true,
59099 * @event rowcontextmenu
59100 * Fires when a row is right clicked
59101 * @param {Grid} this
59102 * @param {Number} rowIndex
59103 * @param {Roo.EventObject} e
59105 "rowcontextmenu" : true,
59107 * @event cellcontextmenu
59108 * Fires when a cell is right clicked
59109 * @param {Grid} this
59110 * @param {Number} rowIndex
59111 * @param {Number} cellIndex
59112 * @param {Roo.EventObject} e
59114 "cellcontextmenu" : true,
59116 * @event headercontextmenu
59117 * Fires when a header is right clicked
59118 * @param {Grid} this
59119 * @param {Number} columnIndex
59120 * @param {Roo.EventObject} e
59122 "headercontextmenu" : true,
59124 * @event bodyscroll
59125 * Fires when the body element is scrolled
59126 * @param {Number} scrollLeft
59127 * @param {Number} scrollTop
59129 "bodyscroll" : true,
59131 * @event columnresize
59132 * Fires when the user resizes a column
59133 * @param {Number} columnIndex
59134 * @param {Number} newSize
59136 "columnresize" : true,
59138 * @event columnmove
59139 * Fires when the user moves a column
59140 * @param {Number} oldIndex
59141 * @param {Number} newIndex
59143 "columnmove" : true,
59146 * Fires when row(s) start being dragged
59147 * @param {Grid} this
59148 * @param {Roo.GridDD} dd The drag drop object
59149 * @param {event} e The raw browser event
59151 "startdrag" : true,
59154 * Fires when a drag operation is complete
59155 * @param {Grid} this
59156 * @param {Roo.GridDD} dd The drag drop object
59157 * @param {event} e The raw browser event
59162 * Fires when dragged row(s) are dropped on a valid DD target
59163 * @param {Grid} this
59164 * @param {Roo.GridDD} dd The drag drop object
59165 * @param {String} targetId The target drag drop object
59166 * @param {event} e The raw browser event
59171 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59172 * @param {Grid} this
59173 * @param {Roo.GridDD} dd The drag drop object
59174 * @param {String} targetId The target drag drop object
59175 * @param {event} e The raw browser event
59180 * Fires when the dragged row(s) first cross another DD target while being dragged
59181 * @param {Grid} this
59182 * @param {Roo.GridDD} dd The drag drop object
59183 * @param {String} targetId The target drag drop object
59184 * @param {event} e The raw browser event
59186 "dragenter" : true,
59189 * Fires when the dragged row(s) leave another DD target while being dragged
59190 * @param {Grid} this
59191 * @param {Roo.GridDD} dd The drag drop object
59192 * @param {String} targetId The target drag drop object
59193 * @param {event} e The raw browser event
59198 * Fires when a row is rendered, so you can change add a style to it.
59199 * @param {GridView} gridview The grid view
59200 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59206 * Fires when the grid is rendered
59207 * @param {Grid} grid
59212 * Fires when a date is selected
59213 * @param {DatePicker} this
59214 * @param {Date} date The selected date
59218 * @event monthchange
59219 * Fires when the displayed month changes
59220 * @param {DatePicker} this
59221 * @param {Date} date The selected month
59223 'monthchange': true,
59225 * @event evententer
59226 * Fires when mouse over an event
59227 * @param {Calendar} this
59228 * @param {event} Event
59230 'evententer': true,
59232 * @event eventleave
59233 * Fires when the mouse leaves an
59234 * @param {Calendar} this
59237 'eventleave': true,
59239 * @event eventclick
59240 * Fires when the mouse click an
59241 * @param {Calendar} this
59244 'eventclick': true,
59246 * @event eventrender
59247 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59248 * @param {Calendar} this
59249 * @param {data} data to be modified
59251 'eventrender': true
59255 Roo.grid.Grid.superclass.constructor.call(this);
59256 this.on('render', function() {
59257 this.view.el.addClass('x-grid-cal');
59259 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59263 if (!Roo.grid.Calendar.style) {
59264 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59267 '.x-grid-cal .x-grid-col' : {
59268 height: 'auto !important',
59269 'vertical-align': 'top'
59271 '.x-grid-cal .fc-event-hori' : {
59282 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59284 * @cfg {Store} eventStore The store that loads events.
59289 activeDate : false,
59292 monitorWindowResize : false,
59295 resizeColumns : function() {
59296 var col = (this.view.el.getWidth() / 7) - 3;
59297 // loop through cols, and setWidth
59298 for(var i =0 ; i < 7 ; i++){
59299 this.cm.setColumnWidth(i, col);
59302 setDate :function(date) {
59304 Roo.log('setDate?');
59306 this.resizeColumns();
59307 var vd = this.activeDate;
59308 this.activeDate = date;
59309 // if(vd && this.el){
59310 // var t = date.getTime();
59311 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59312 // Roo.log('using add remove');
59314 // this.fireEvent('monthchange', this, date);
59316 // this.cells.removeClass("fc-state-highlight");
59317 // this.cells.each(function(c){
59318 // if(c.dateValue == t){
59319 // c.addClass("fc-state-highlight");
59320 // setTimeout(function(){
59321 // try{c.dom.firstChild.focus();}catch(e){}
59331 var days = date.getDaysInMonth();
59333 var firstOfMonth = date.getFirstDateOfMonth();
59334 var startingPos = firstOfMonth.getDay()-this.startDay;
59336 if(startingPos < this.startDay){
59340 var pm = date.add(Date.MONTH, -1);
59341 var prevStart = pm.getDaysInMonth()-startingPos;
59345 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59347 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59348 //this.cells.addClassOnOver('fc-state-hover');
59350 var cells = this.cells.elements;
59351 var textEls = this.textNodes;
59353 //Roo.each(cells, function(cell){
59354 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59357 days += startingPos;
59359 // convert everything to numbers so it's fast
59360 var day = 86400000;
59361 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59364 //Roo.log(prevStart);
59366 var today = new Date().clearTime().getTime();
59367 var sel = date.clearTime().getTime();
59368 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59369 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59370 var ddMatch = this.disabledDatesRE;
59371 var ddText = this.disabledDatesText;
59372 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59373 var ddaysText = this.disabledDaysText;
59374 var format = this.format;
59376 var setCellClass = function(cal, cell){
59378 //Roo.log('set Cell Class');
59380 var t = d.getTime();
59385 cell.dateValue = t;
59387 cell.className += " fc-today";
59388 cell.className += " fc-state-highlight";
59389 cell.title = cal.todayText;
59392 // disable highlight in other month..
59393 cell.className += " fc-state-highlight";
59398 //cell.className = " fc-state-disabled";
59399 cell.title = cal.minText;
59403 //cell.className = " fc-state-disabled";
59404 cell.title = cal.maxText;
59408 if(ddays.indexOf(d.getDay()) != -1){
59409 // cell.title = ddaysText;
59410 // cell.className = " fc-state-disabled";
59413 if(ddMatch && format){
59414 var fvalue = d.dateFormat(format);
59415 if(ddMatch.test(fvalue)){
59416 cell.title = ddText.replace("%0", fvalue);
59417 cell.className = " fc-state-disabled";
59421 if (!cell.initialClassName) {
59422 cell.initialClassName = cell.dom.className;
59425 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59430 for(; i < startingPos; i++) {
59431 cells[i].dayName = (++prevStart);
59432 Roo.log(textEls[i]);
59433 d.setDate(d.getDate()+1);
59435 //cells[i].className = "fc-past fc-other-month";
59436 setCellClass(this, cells[i]);
59441 for(; i < days; i++){
59442 intDay = i - startingPos + 1;
59443 cells[i].dayName = (intDay);
59444 d.setDate(d.getDate()+1);
59446 cells[i].className = ''; // "x-date-active";
59447 setCellClass(this, cells[i]);
59451 for(; i < 42; i++) {
59452 //textEls[i].innerHTML = (++extraDays);
59454 d.setDate(d.getDate()+1);
59455 cells[i].dayName = (++extraDays);
59456 cells[i].className = "fc-future fc-other-month";
59457 setCellClass(this, cells[i]);
59460 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59462 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59464 // this will cause all the cells to mis
59467 for (var r = 0;r < 6;r++) {
59468 for (var c =0;c < 7;c++) {
59469 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59473 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59474 for(i=0;i<cells.length;i++) {
59476 this.cells.elements[i].dayName = cells[i].dayName ;
59477 this.cells.elements[i].className = cells[i].className;
59478 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59479 this.cells.elements[i].title = cells[i].title ;
59480 this.cells.elements[i].dateValue = cells[i].dateValue ;
59486 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59487 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59489 ////if(totalRows != 6){
59490 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59491 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59494 this.fireEvent('monthchange', this, date);
59499 * Returns the grid's SelectionModel.
59500 * @return {SelectionModel}
59502 getSelectionModel : function(){
59503 if(!this.selModel){
59504 this.selModel = new Roo.grid.CellSelectionModel();
59506 return this.selModel;
59510 this.eventStore.load()
59516 findCell : function(dt) {
59517 dt = dt.clearTime().getTime();
59519 this.cells.each(function(c){
59520 //Roo.log("check " +c.dateValue + '?=' + dt);
59521 if(c.dateValue == dt){
59531 findCells : function(rec) {
59532 var s = rec.data.start_dt.clone().clearTime().getTime();
59534 var e= rec.data.end_dt.clone().clearTime().getTime();
59537 this.cells.each(function(c){
59538 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59540 if(c.dateValue > e){
59543 if(c.dateValue < s){
59552 findBestRow: function(cells)
59556 for (var i =0 ; i < cells.length;i++) {
59557 ret = Math.max(cells[i].rows || 0,ret);
59564 addItem : function(rec)
59566 // look for vertical location slot in
59567 var cells = this.findCells(rec);
59569 rec.row = this.findBestRow(cells);
59571 // work out the location.
59575 for(var i =0; i < cells.length; i++) {
59583 if (crow.start.getY() == cells[i].getY()) {
59585 crow.end = cells[i];
59601 for (var i = 0; i < cells.length;i++) {
59602 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59609 clearEvents: function() {
59611 if (!this.eventStore.getCount()) {
59614 // reset number of rows in cells.
59615 Roo.each(this.cells.elements, function(c){
59619 this.eventStore.each(function(e) {
59620 this.clearEvent(e);
59625 clearEvent : function(ev)
59628 Roo.each(ev.els, function(el) {
59629 el.un('mouseenter' ,this.onEventEnter, this);
59630 el.un('mouseleave' ,this.onEventLeave, this);
59638 renderEvent : function(ev,ctr) {
59640 ctr = this.view.el.select('.fc-event-container',true).first();
59644 this.clearEvent(ev);
59650 var cells = ev.cells;
59651 var rows = ev.rows;
59652 this.fireEvent('eventrender', this, ev);
59654 for(var i =0; i < rows.length; i++) {
59658 cls += ' fc-event-start';
59660 if ((i+1) == rows.length) {
59661 cls += ' fc-event-end';
59664 //Roo.log(ev.data);
59665 // how many rows should it span..
59666 var cg = this.eventTmpl.append(ctr,Roo.apply({
59669 }, ev.data) , true);
59672 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59673 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59674 cg.on('click', this.onEventClick, this, ev);
59678 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59679 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59682 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59683 cg.setWidth(ebox.right - sbox.x -2);
59687 renderEvents: function()
59689 // first make sure there is enough space..
59691 if (!this.eventTmpl) {
59692 this.eventTmpl = new Roo.Template(
59693 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59694 '<div class="fc-event-inner">' +
59695 '<span class="fc-event-time">{time}</span>' +
59696 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59698 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59706 this.cells.each(function(c) {
59707 //Roo.log(c.select('.fc-day-content div',true).first());
59708 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59711 var ctr = this.view.el.select('.fc-event-container',true).first();
59714 this.eventStore.each(function(ev){
59716 this.renderEvent(ev);
59720 this.view.layout();
59724 onEventEnter: function (e, el,event,d) {
59725 this.fireEvent('evententer', this, el, event);
59728 onEventLeave: function (e, el,event,d) {
59729 this.fireEvent('eventleave', this, el, event);
59732 onEventClick: function (e, el,event,d) {
59733 this.fireEvent('eventclick', this, el, event);
59736 onMonthChange: function () {
59740 onLoad: function () {
59742 //Roo.log('calendar onload');
59744 if(this.eventStore.getCount() > 0){
59748 this.eventStore.each(function(d){
59753 if (typeof(add.end_dt) == 'undefined') {
59754 Roo.log("Missing End time in calendar data: ");
59758 if (typeof(add.start_dt) == 'undefined') {
59759 Roo.log("Missing Start time in calendar data: ");
59763 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59764 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59765 add.id = add.id || d.id;
59766 add.title = add.title || '??';
59774 this.renderEvents();
59784 render : function ()
59788 if (!this.view.el.hasClass('course-timesheet')) {
59789 this.view.el.addClass('course-timesheet');
59791 if (this.tsStyle) {
59796 Roo.log(_this.grid.view.el.getWidth());
59799 this.tsStyle = Roo.util.CSS.createStyleSheet({
59800 '.course-timesheet .x-grid-row' : {
59803 '.x-grid-row td' : {
59804 'vertical-align' : 0
59806 '.course-edit-link' : {
59808 'text-overflow' : 'ellipsis',
59809 'overflow' : 'hidden',
59810 'white-space' : 'nowrap',
59811 'cursor' : 'pointer'
59816 '.de-act-sup-link' : {
59817 'color' : 'purple',
59818 'text-decoration' : 'line-through'
59822 'text-decoration' : 'line-through'
59824 '.course-timesheet .course-highlight' : {
59825 'border-top-style': 'dashed !important',
59826 'border-bottom-bottom': 'dashed !important'
59828 '.course-timesheet .course-item' : {
59829 'font-family' : 'tahoma, arial, helvetica',
59830 'font-size' : '11px',
59831 'overflow' : 'hidden',
59832 'padding-left' : '10px',
59833 'padding-right' : '10px',
59834 'padding-top' : '10px'
59842 monitorWindowResize : false,
59843 cellrenderer : function(v,x,r)
59848 xtype: 'CellSelectionModel',
59855 beforeload : function (_self, options)
59857 options.params = options.params || {};
59858 options.params._month = _this.monthField.getValue();
59859 options.params.limit = 9999;
59860 options.params['sort'] = 'when_dt';
59861 options.params['dir'] = 'ASC';
59862 this.proxy.loadResponse = this.loadResponse;
59864 //this.addColumns();
59866 load : function (_self, records, options)
59868 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59869 // if you click on the translation.. you can edit it...
59870 var el = Roo.get(this);
59871 var id = el.dom.getAttribute('data-id');
59872 var d = el.dom.getAttribute('data-date');
59873 var t = el.dom.getAttribute('data-time');
59874 //var id = this.child('span').dom.textContent;
59877 Pman.Dialog.CourseCalendar.show({
59881 productitem_active : id ? 1 : 0
59883 _this.grid.ds.load({});
59888 _this.panel.fireEvent('resize', [ '', '' ]);
59891 loadResponse : function(o, success, response){
59892 // this is overridden on before load..
59894 Roo.log("our code?");
59895 //Roo.log(success);
59896 //Roo.log(response)
59897 delete this.activeRequest;
59899 this.fireEvent("loadexception", this, o, response);
59900 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59905 result = o.reader.read(response);
59907 Roo.log("load exception?");
59908 this.fireEvent("loadexception", this, o, response, e);
59909 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59912 Roo.log("ready...");
59913 // loop through result.records;
59914 // and set this.tdate[date] = [] << array of records..
59916 Roo.each(result.records, function(r){
59918 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59919 _this.tdata[r.data.when_dt.format('j')] = [];
59921 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59924 //Roo.log(_this.tdata);
59926 result.records = [];
59927 result.totalRecords = 6;
59929 // let's generate some duumy records for the rows.
59930 //var st = _this.dateField.getValue();
59932 // work out monday..
59933 //st = st.add(Date.DAY, -1 * st.format('w'));
59935 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59937 var firstOfMonth = date.getFirstDayOfMonth();
59938 var days = date.getDaysInMonth();
59940 var firstAdded = false;
59941 for (var i = 0; i < result.totalRecords ; i++) {
59942 //var d= st.add(Date.DAY, i);
59945 for(var w = 0 ; w < 7 ; w++){
59946 if(!firstAdded && firstOfMonth != w){
59953 var dd = (d > 0 && d < 10) ? "0"+d : d;
59954 row['weekday'+w] = String.format(
59955 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59956 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59958 date.format('Y-m-')+dd
59961 if(typeof(_this.tdata[d]) != 'undefined'){
59962 Roo.each(_this.tdata[d], function(r){
59966 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59967 if(r.parent_id*1>0){
59968 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59971 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59972 deactive = 'de-act-link';
59975 row['weekday'+w] += String.format(
59976 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59978 r.product_id_name, //1
59979 r.when_dt.format('h:ia'), //2
59989 // only do this if something added..
59991 result.records.push(_this.grid.dataSource.reader.newRow(row));
59995 // push it twice. (second one with an hour..
59999 this.fireEvent("load", this, o, o.request.arg);
60000 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60002 sortInfo : {field: 'when_dt', direction : 'ASC' },
60004 xtype: 'HttpProxy',
60007 url : baseURL + '/Roo/Shop_course.php'
60010 xtype: 'JsonReader',
60027 'name': 'parent_id',
60031 'name': 'product_id',
60035 'name': 'productitem_id',
60053 click : function (_self, e)
60055 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60056 sd.setMonth(sd.getMonth()-1);
60057 _this.monthField.setValue(sd.format('Y-m-d'));
60058 _this.grid.ds.load({});
60064 xtype: 'Separator',
60068 xtype: 'MonthField',
60071 render : function (_self)
60073 _this.monthField = _self;
60074 // _this.monthField.set today
60076 select : function (combo, date)
60078 _this.grid.ds.load({});
60081 value : (function() { return new Date(); })()
60084 xtype: 'Separator',
60090 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60100 click : function (_self, e)
60102 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60103 sd.setMonth(sd.getMonth()+1);
60104 _this.monthField.setValue(sd.format('Y-m-d'));
60105 _this.grid.ds.load({});
60118 * Ext JS Library 1.1.1
60119 * Copyright(c) 2006-2007, Ext JS, LLC.
60121 * Originally Released Under LGPL - original licence link has changed is not relivant.
60124 * <script type="text/javascript">
60128 * @class Roo.LoadMask
60129 * A simple utility class for generically masking elements while loading data. If the element being masked has
60130 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60131 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60132 * element's UpdateManager load indicator and will be destroyed after the initial load.
60134 * Create a new LoadMask
60135 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60136 * @param {Object} config The config object
60138 Roo.LoadMask = function(el, config){
60139 this.el = Roo.get(el);
60140 Roo.apply(this, config);
60142 this.store.on('beforeload', this.onBeforeLoad, this);
60143 this.store.on('load', this.onLoad, this);
60144 this.store.on('loadexception', this.onLoadException, this);
60145 this.removeMask = false;
60147 var um = this.el.getUpdateManager();
60148 um.showLoadIndicator = false; // disable the default indicator
60149 um.on('beforeupdate', this.onBeforeLoad, this);
60150 um.on('update', this.onLoad, this);
60151 um.on('failure', this.onLoad, this);
60152 this.removeMask = true;
60156 Roo.LoadMask.prototype = {
60158 * @cfg {Boolean} removeMask
60159 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60160 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60163 * @cfg {String} msg
60164 * The text to display in a centered loading message box (defaults to 'Loading...')
60166 msg : 'Loading...',
60168 * @cfg {String} msgCls
60169 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60171 msgCls : 'x-mask-loading',
60174 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60180 * Disables the mask to prevent it from being displayed
60182 disable : function(){
60183 this.disabled = true;
60187 * Enables the mask so that it can be displayed
60189 enable : function(){
60190 this.disabled = false;
60193 onLoadException : function()
60195 Roo.log(arguments);
60197 if (typeof(arguments[3]) != 'undefined') {
60198 Roo.MessageBox.alert("Error loading",arguments[3]);
60202 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60203 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60210 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60213 onLoad : function()
60215 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60219 onBeforeLoad : function(){
60220 if(!this.disabled){
60221 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60226 destroy : function(){
60228 this.store.un('beforeload', this.onBeforeLoad, this);
60229 this.store.un('load', this.onLoad, this);
60230 this.store.un('loadexception', this.onLoadException, this);
60232 var um = this.el.getUpdateManager();
60233 um.un('beforeupdate', this.onBeforeLoad, this);
60234 um.un('update', this.onLoad, this);
60235 um.un('failure', this.onLoad, this);
60240 * Ext JS Library 1.1.1
60241 * Copyright(c) 2006-2007, Ext JS, LLC.
60243 * Originally Released Under LGPL - original licence link has changed is not relivant.
60246 * <script type="text/javascript">
60251 * @class Roo.XTemplate
60252 * @extends Roo.Template
60253 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60255 var t = new Roo.XTemplate(
60256 '<select name="{name}">',
60257 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60261 // then append, applying the master template values
60264 * Supported features:
60269 {a_variable} - output encoded.
60270 {a_variable.format:("Y-m-d")} - call a method on the variable
60271 {a_variable:raw} - unencoded output
60272 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60273 {a_variable:this.method_on_template(...)} - call a method on the template object.
60278 <tpl for="a_variable or condition.."></tpl>
60279 <tpl if="a_variable or condition"></tpl>
60280 <tpl exec="some javascript"></tpl>
60281 <tpl name="named_template"></tpl> (experimental)
60283 <tpl for="."></tpl> - just iterate the property..
60284 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60288 Roo.XTemplate = function()
60290 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60297 Roo.extend(Roo.XTemplate, Roo.Template, {
60300 * The various sub templates
60305 * basic tag replacing syntax
60308 * // you can fake an object call by doing this
60312 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60315 * compile the template
60317 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60320 compile: function()
60324 s = ['<tpl>', s, '</tpl>'].join('');
60326 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60327 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60328 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60329 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60330 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60335 while(true == !!(m = s.match(re))){
60336 var forMatch = m[0].match(nameRe),
60337 ifMatch = m[0].match(ifRe),
60338 execMatch = m[0].match(execRe),
60339 namedMatch = m[0].match(namedRe),
60344 name = forMatch && forMatch[1] ? forMatch[1] : '';
60347 // if - puts fn into test..
60348 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60350 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60355 // exec - calls a function... returns empty if true is returned.
60356 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60358 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60366 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60367 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60368 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60371 var uid = namedMatch ? namedMatch[1] : id;
60375 id: namedMatch ? namedMatch[1] : id,
60382 s = s.replace(m[0], '');
60384 s = s.replace(m[0], '{xtpl'+ id + '}');
60389 for(var i = tpls.length-1; i >= 0; --i){
60390 this.compileTpl(tpls[i]);
60391 this.tpls[tpls[i].id] = tpls[i];
60393 this.master = tpls[tpls.length-1];
60397 * same as applyTemplate, except it's done to one of the subTemplates
60398 * when using named templates, you can do:
60400 * var str = pl.applySubTemplate('your-name', values);
60403 * @param {Number} id of the template
60404 * @param {Object} values to apply to template
60405 * @param {Object} parent (normaly the instance of this object)
60407 applySubTemplate : function(id, values, parent)
60411 var t = this.tpls[id];
60415 if(t.test && !t.test.call(this, values, parent)){
60419 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60420 Roo.log(e.toString());
60426 if(t.exec && t.exec.call(this, values, parent)){
60430 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60431 Roo.log(e.toString());
60436 var vs = t.target ? t.target.call(this, values, parent) : values;
60437 parent = t.target ? values : parent;
60438 if(t.target && vs instanceof Array){
60440 for(var i = 0, len = vs.length; i < len; i++){
60441 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60443 return buf.join('');
60445 return t.compiled.call(this, vs, parent);
60447 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60448 Roo.log(e.toString());
60449 Roo.log(t.compiled);
60454 compileTpl : function(tpl)
60456 var fm = Roo.util.Format;
60457 var useF = this.disableFormats !== true;
60458 var sep = Roo.isGecko ? "+" : ",";
60459 var undef = function(str) {
60460 Roo.log("Property not found :" + str);
60464 var fn = function(m, name, format, args)
60466 //Roo.log(arguments);
60467 args = args ? args.replace(/\\'/g,"'") : args;
60468 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60469 if (typeof(format) == 'undefined') {
60470 format= 'htmlEncode';
60472 if (format == 'raw' ) {
60476 if(name.substr(0, 4) == 'xtpl'){
60477 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60480 // build an array of options to determine if value is undefined..
60482 // basically get 'xxxx.yyyy' then do
60483 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60484 // (function () { Roo.log("Property not found"); return ''; })() :
60489 Roo.each(name.split('.'), function(st) {
60490 lookfor += (lookfor.length ? '.': '') + st;
60491 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60494 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60497 if(format && useF){
60499 args = args ? ',' + args : "";
60501 if(format.substr(0, 5) != "this."){
60502 format = "fm." + format + '(';
60504 format = 'this.call("'+ format.substr(5) + '", ';
60508 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60512 // called with xxyx.yuu:(test,test)
60514 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60516 // raw.. - :raw modifier..
60517 return "'"+ sep + udef_st + name + ")"+sep+"'";
60521 // branched to use + in gecko and [].join() in others
60523 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60524 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60527 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60528 body.push(tpl.body.replace(/(\r\n|\n)/g,
60529 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60530 body.push("'].join('');};};");
60531 body = body.join('');
60534 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60536 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60542 applyTemplate : function(values){
60543 return this.master.compiled.call(this, values, {});
60544 //var s = this.subs;
60547 apply : function(){
60548 return this.applyTemplate.apply(this, arguments);
60553 Roo.XTemplate.from = function(el){
60554 el = Roo.getDom(el);
60555 return new Roo.XTemplate(el.value || el.innerHTML);