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 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * 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.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * 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]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1026 * Ext JS Library 1.1.1
1027 * Copyright(c) 2006-2007, Ext JS, LLC.
1029 * Originally Released Under LGPL - original licence link has changed is not relivant.
1032 * <script type="text/javascript">
1038 * The date parsing and format syntax is a subset of
1039 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1040 * supported will provide results equivalent to their PHP versions.
1042 * Following is the list of all currently supported formats:
1045 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1047 Format Output Description
1048 ------ ---------- --------------------------------------------------------------
1049 d 10 Day of the month, 2 digits with leading zeros
1050 D Wed A textual representation of a day, three letters
1051 j 10 Day of the month without leading zeros
1052 l Wednesday A full textual representation of the day of the week
1053 S th English ordinal day of month suffix, 2 chars (use with j)
1054 w 3 Numeric representation of the day of the week
1055 z 9 The julian date, or day of the year (0-365)
1056 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1057 F January A full textual representation of the month
1058 m 01 Numeric representation of a month, with leading zeros
1059 M Jan Month name abbreviation, three letters
1060 n 1 Numeric representation of a month, without leading zeros
1061 t 31 Number of days in the given month
1062 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1063 Y 2007 A full numeric representation of a year, 4 digits
1064 y 07 A two digit representation of a year
1065 a pm Lowercase Ante meridiem and Post meridiem
1066 A PM Uppercase Ante meridiem and Post meridiem
1067 g 3 12-hour format of an hour without leading zeros
1068 G 15 24-hour format of an hour without leading zeros
1069 h 03 12-hour format of an hour with leading zeros
1070 H 15 24-hour format of an hour with leading zeros
1071 i 05 Minutes with leading zeros
1072 s 01 Seconds, with leading zeros
1073 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1074 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1075 T CST Timezone setting of the machine running the code
1076 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1079 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1081 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1082 document.write(dt.format('Y-m-d')); //2007-01-10
1083 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1084 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
1087 * Here are some standard date/time patterns that you might find helpful. They
1088 * are not part of the source of Date.js, but to use them you can simply copy this
1089 * block of code into any script that is included after Date.js and they will also become
1090 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1093 ISO8601Long:"Y-m-d H:i:s",
1094 ISO8601Short:"Y-m-d",
1096 LongDate: "l, F d, Y",
1097 FullDateTime: "l, F d, Y g:i:s A",
1100 LongTime: "g:i:s A",
1101 SortableDateTime: "Y-m-d\\TH:i:s",
1102 UniversalSortableDateTime: "Y-m-d H:i:sO",
1109 var dt = new Date();
1110 document.write(dt.format(Date.patterns.ShortDate));
1115 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1116 * They generate precompiled functions from date formats instead of parsing and
1117 * processing the pattern every time you format a date. These functions are available
1118 * on every Date object (any javascript function).
1120 * The original article and download are here:
1121 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1128 Returns the number of milliseconds between this date and date
1129 @param {Date} date (optional) Defaults to now
1130 @return {Number} The diff in milliseconds
1131 @member Date getElapsed
1133 Date.prototype.getElapsed = function(date) {
1134 return Math.abs((date || new Date()).getTime()-this.getTime());
1136 // was in date file..
1140 Date.parseFunctions = {count:0};
1142 Date.parseRegexes = [];
1144 Date.formatFunctions = {count:0};
1147 Date.prototype.dateFormat = function(format) {
1148 if (Date.formatFunctions[format] == null) {
1149 Date.createNewFormat(format);
1151 var func = Date.formatFunctions[format];
1152 return this[func]();
1157 * Formats a date given the supplied format string
1158 * @param {String} format The format string
1159 * @return {String} The formatted date
1162 Date.prototype.format = Date.prototype.dateFormat;
1165 Date.createNewFormat = function(format) {
1166 var funcName = "format" + Date.formatFunctions.count++;
1167 Date.formatFunctions[format] = funcName;
1168 var code = "Date.prototype." + funcName + " = function(){return ";
1169 var special = false;
1171 for (var i = 0; i < format.length; ++i) {
1172 ch = format.charAt(i);
1173 if (!special && ch == "\\") {
1178 code += "'" + String.escape(ch) + "' + ";
1181 code += Date.getFormatCode(ch);
1184 /** eval:var:zzzzzzzzzzzzz */
1185 eval(code.substring(0, code.length - 3) + ";}");
1189 Date.getFormatCode = function(character) {
1190 switch (character) {
1192 return "String.leftPad(this.getDate(), 2, '0') + ";
1194 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1196 return "this.getDate() + ";
1198 return "Date.dayNames[this.getDay()] + ";
1200 return "this.getSuffix() + ";
1202 return "this.getDay() + ";
1204 return "this.getDayOfYear() + ";
1206 return "this.getWeekOfYear() + ";
1208 return "Date.monthNames[this.getMonth()] + ";
1210 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1212 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1214 return "(this.getMonth() + 1) + ";
1216 return "this.getDaysInMonth() + ";
1218 return "(this.isLeapYear() ? 1 : 0) + ";
1220 return "this.getFullYear() + ";
1222 return "('' + this.getFullYear()).substring(2, 4) + ";
1224 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1226 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1228 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1230 return "this.getHours() + ";
1232 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1234 return "String.leftPad(this.getHours(), 2, '0') + ";
1236 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1238 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1240 return "this.getGMTOffset() + ";
1242 return "this.getGMTColonOffset() + ";
1244 return "this.getTimezone() + ";
1246 return "(this.getTimezoneOffset() * -60) + ";
1248 return "'" + String.escape(character) + "' + ";
1253 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1254 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1255 * the date format that is not specified will default to the current date value for that part. Time parts can also
1256 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1257 * string or the parse operation will fail.
1260 //dt = Fri May 25 2007 (current date)
1261 var dt = new Date();
1263 //dt = Thu May 25 2006 (today's month/day in 2006)
1264 dt = Date.parseDate("2006", "Y");
1266 //dt = Sun Jan 15 2006 (all date parts specified)
1267 dt = Date.parseDate("2006-1-15", "Y-m-d");
1269 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1270 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1272 * @param {String} input The unparsed date as a string
1273 * @param {String} format The format the date is in
1274 * @return {Date} The parsed date
1277 Date.parseDate = function(input, format) {
1278 if (Date.parseFunctions[format] == null) {
1279 Date.createParser(format);
1281 var func = Date.parseFunctions[format];
1282 return Date[func](input);
1288 Date.createParser = function(format) {
1289 var funcName = "parse" + Date.parseFunctions.count++;
1290 var regexNum = Date.parseRegexes.length;
1291 var currentGroup = 1;
1292 Date.parseFunctions[format] = funcName;
1294 var code = "Date." + funcName + " = function(input){\n"
1295 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1296 + "var d = new Date();\n"
1297 + "y = d.getFullYear();\n"
1298 + "m = d.getMonth();\n"
1299 + "d = d.getDate();\n"
1300 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1301 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1302 + "if (results && results.length > 0) {";
1305 var special = false;
1307 for (var i = 0; i < format.length; ++i) {
1308 ch = format.charAt(i);
1309 if (!special && ch == "\\") {
1314 regex += String.escape(ch);
1317 var obj = Date.formatCodeToRegex(ch, currentGroup);
1318 currentGroup += obj.g;
1320 if (obj.g && obj.c) {
1326 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1327 + "{v = new Date(y, m, d, h, i, s);}\n"
1328 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1329 + "{v = new Date(y, m, d, h, i);}\n"
1330 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1331 + "{v = new Date(y, m, d, h);}\n"
1332 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1333 + "{v = new Date(y, m, d);}\n"
1334 + "else if (y >= 0 && m >= 0)\n"
1335 + "{v = new Date(y, m);}\n"
1336 + "else if (y >= 0)\n"
1337 + "{v = new Date(y);}\n"
1338 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1339 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1340 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1343 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1344 /** eval:var:zzzzzzzzzzzzz */
1349 Date.formatCodeToRegex = function(character, currentGroup) {
1350 switch (character) {
1354 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1357 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1358 s:"(\\d{1,2})"}; // day of month without leading zeroes
1361 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1362 s:"(\\d{2})"}; // day of month with leading zeroes
1366 s:"(?:" + Date.dayNames.join("|") + ")"};
1370 s:"(?:st|nd|rd|th)"};
1385 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1386 s:"(" + Date.monthNames.join("|") + ")"};
1389 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1390 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1393 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1394 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1397 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1398 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1409 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1413 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1414 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1418 c:"if (results[" + currentGroup + "] == 'am') {\n"
1419 + "if (h == 12) { h = 0; }\n"
1420 + "} else { if (h < 12) { h += 12; }}",
1424 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1425 + "if (h == 12) { h = 0; }\n"
1426 + "} else { if (h < 12) { h += 12; }}",
1431 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1432 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1436 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1437 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1440 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1444 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1449 "o = results[", currentGroup, "];\n",
1450 "var sn = o.substring(0,1);\n", // get + / - sign
1451 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1452 "var mn = o.substring(3,5) % 60;\n", // get minutes
1453 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1454 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1456 s:"([+\-]\\d{2,4})"};
1462 "o = results[", currentGroup, "];\n",
1463 "var sn = o.substring(0,1);\n",
1464 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1465 "var mn = o.substring(4,6) % 60;\n",
1466 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1467 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1473 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1476 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1477 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1478 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1482 s:String.escape(character)};
1487 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1488 * @return {String} The abbreviated timezone name (e.g. 'CST')
1490 Date.prototype.getTimezone = function() {
1491 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1495 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1496 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1498 Date.prototype.getGMTOffset = function() {
1499 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1500 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1501 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1505 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1506 * @return {String} 2-characters representing hours and 2-characters representing minutes
1507 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1509 Date.prototype.getGMTColonOffset = function() {
1510 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1511 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1513 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1517 * Get the numeric day number of the year, adjusted for leap year.
1518 * @return {Number} 0 through 364 (365 in leap years)
1520 Date.prototype.getDayOfYear = function() {
1522 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1523 for (var i = 0; i < this.getMonth(); ++i) {
1524 num += Date.daysInMonth[i];
1526 return num + this.getDate() - 1;
1530 * Get the string representation of the numeric week number of the year
1531 * (equivalent to the format specifier 'W').
1532 * @return {String} '00' through '52'
1534 Date.prototype.getWeekOfYear = function() {
1535 // Skip to Thursday of this week
1536 var now = this.getDayOfYear() + (4 - this.getDay());
1537 // Find the first Thursday of the year
1538 var jan1 = new Date(this.getFullYear(), 0, 1);
1539 var then = (7 - jan1.getDay() + 4);
1540 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1544 * Whether or not the current date is in a leap year.
1545 * @return {Boolean} True if the current date is in a leap year, else false
1547 Date.prototype.isLeapYear = function() {
1548 var year = this.getFullYear();
1549 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1553 * Get the first day of the current month, adjusted for leap year. The returned value
1554 * is the numeric day index within the week (0-6) which can be used in conjunction with
1555 * the {@link #monthNames} array to retrieve the textual day name.
1558 var dt = new Date('1/10/2007');
1559 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1561 * @return {Number} The day number (0-6)
1563 Date.prototype.getFirstDayOfMonth = function() {
1564 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1565 return (day < 0) ? (day + 7) : day;
1569 * Get the last day of the current month, adjusted for leap year. The returned value
1570 * is the numeric day index within the week (0-6) which can be used in conjunction with
1571 * the {@link #monthNames} array to retrieve the textual day name.
1574 var dt = new Date('1/10/2007');
1575 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1577 * @return {Number} The day number (0-6)
1579 Date.prototype.getLastDayOfMonth = function() {
1580 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1581 return (day < 0) ? (day + 7) : day;
1586 * Get the first date of this date's month
1589 Date.prototype.getFirstDateOfMonth = function() {
1590 return new Date(this.getFullYear(), this.getMonth(), 1);
1594 * Get the last date of this date's month
1597 Date.prototype.getLastDateOfMonth = function() {
1598 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1601 * Get the number of days in the current month, adjusted for leap year.
1602 * @return {Number} The number of days in the month
1604 Date.prototype.getDaysInMonth = function() {
1605 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1606 return Date.daysInMonth[this.getMonth()];
1610 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1611 * @return {String} 'st, 'nd', 'rd' or 'th'
1613 Date.prototype.getSuffix = function() {
1614 switch (this.getDate()) {
1631 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1634 * An array of textual month names.
1635 * Override these values for international dates, for example...
1636 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1655 * An array of textual day names.
1656 * Override these values for international dates, for example...
1657 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1673 Date.monthNumbers = {
1688 * Creates and returns a new Date instance with the exact same date value as the called instance.
1689 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1690 * variable will also be changed. When the intention is to create a new variable that will not
1691 * modify the original instance, you should create a clone.
1693 * Example of correctly cloning a date:
1696 var orig = new Date('10/1/2006');
1699 document.write(orig); //returns 'Thu Oct 05 2006'!
1702 var orig = new Date('10/1/2006');
1703 var copy = orig.clone();
1705 document.write(orig); //returns 'Thu Oct 01 2006'
1707 * @return {Date} The new Date instance
1709 Date.prototype.clone = function() {
1710 return new Date(this.getTime());
1714 * Clears any time information from this date
1715 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1716 @return {Date} this or the clone
1718 Date.prototype.clearTime = function(clone){
1720 return this.clone().clearTime();
1725 this.setMilliseconds(0);
1730 // safari setMonth is broken -- check that this is only donw once...
1731 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1732 Date.brokenSetMonth = Date.prototype.setMonth;
1733 Date.prototype.setMonth = function(num){
1735 var n = Math.ceil(-num);
1736 var back_year = Math.ceil(n/12);
1737 var month = (n % 12) ? 12 - n % 12 : 0 ;
1738 this.setFullYear(this.getFullYear() - back_year);
1739 return Date.brokenSetMonth.call(this, month);
1741 return Date.brokenSetMonth.apply(this, arguments);
1746 /** Date interval constant
1750 /** Date interval constant
1754 /** Date interval constant
1758 /** Date interval constant
1762 /** Date interval constant
1766 /** Date interval constant
1770 /** Date interval constant
1776 * Provides a convenient method of performing basic date arithmetic. This method
1777 * does not modify the Date instance being called - it creates and returns
1778 * a new Date instance containing the resulting date value.
1783 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1784 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1786 //Negative values will subtract correctly:
1787 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1788 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1790 //You can even chain several calls together in one line!
1791 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1792 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1795 * @param {String} interval A valid date interval enum value
1796 * @param {Number} value The amount to add to the current date
1797 * @return {Date} The new Date instance
1799 Date.prototype.add = function(interval, value){
1800 var d = this.clone();
1801 if (!interval || value === 0) { return d; }
1802 switch(interval.toLowerCase()){
1804 d.setMilliseconds(this.getMilliseconds() + value);
1807 d.setSeconds(this.getSeconds() + value);
1810 d.setMinutes(this.getMinutes() + value);
1813 d.setHours(this.getHours() + value);
1816 d.setDate(this.getDate() + value);
1819 var day = this.getDate();
1821 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1824 d.setMonth(this.getMonth() + value);
1827 d.setFullYear(this.getFullYear() + value);
1834 * Ext JS Library 1.1.1
1835 * Copyright(c) 2006-2007, Ext JS, LLC.
1837 * Originally Released Under LGPL - original licence link has changed is not relivant.
1840 * <script type="text/javascript">
1844 * @class Roo.lib.Dom
1847 * Dom utils (from YIU afaik)
1852 * Get the view width
1853 * @param {Boolean} full True will get the full document, otherwise it's the view width
1854 * @return {Number} The width
1857 getViewWidth : function(full) {
1858 return full ? this.getDocumentWidth() : this.getViewportWidth();
1861 * Get the view height
1862 * @param {Boolean} full True will get the full document, otherwise it's the view height
1863 * @return {Number} The height
1865 getViewHeight : function(full) {
1866 return full ? this.getDocumentHeight() : this.getViewportHeight();
1869 getDocumentHeight: function() {
1870 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1871 return Math.max(scrollHeight, this.getViewportHeight());
1874 getDocumentWidth: function() {
1875 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1876 return Math.max(scrollWidth, this.getViewportWidth());
1879 getViewportHeight: function() {
1880 var height = self.innerHeight;
1881 var mode = document.compatMode;
1883 if ((mode || Roo.isIE) && !Roo.isOpera) {
1884 height = (mode == "CSS1Compat") ?
1885 document.documentElement.clientHeight :
1886 document.body.clientHeight;
1892 getViewportWidth: function() {
1893 var width = self.innerWidth;
1894 var mode = document.compatMode;
1896 if (mode || Roo.isIE) {
1897 width = (mode == "CSS1Compat") ?
1898 document.documentElement.clientWidth :
1899 document.body.clientWidth;
1904 isAncestor : function(p, c) {
1911 if (p.contains && !Roo.isSafari) {
1912 return p.contains(c);
1913 } else if (p.compareDocumentPosition) {
1914 return !!(p.compareDocumentPosition(c) & 16);
1916 var parent = c.parentNode;
1921 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1924 parent = parent.parentNode;
1930 getRegion : function(el) {
1931 return Roo.lib.Region.getRegion(el);
1934 getY : function(el) {
1935 return this.getXY(el)[1];
1938 getX : function(el) {
1939 return this.getXY(el)[0];
1942 getXY : function(el) {
1943 var p, pe, b, scroll, bd = document.body;
1944 el = Roo.getDom(el);
1945 var fly = Roo.lib.AnimBase.fly;
1946 if (el.getBoundingClientRect) {
1947 b = el.getBoundingClientRect();
1948 scroll = fly(document).getScroll();
1949 return [b.left + scroll.left, b.top + scroll.top];
1955 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1962 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1969 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1970 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1977 if (p != el && pe.getStyle('overflow') != 'visible') {
1985 if (Roo.isSafari && hasAbsolute) {
1990 if (Roo.isGecko && !hasAbsolute) {
1992 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1993 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1997 while (p && p != bd) {
1998 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2010 setXY : function(el, xy) {
2011 el = Roo.fly(el, '_setXY');
2013 var pts = el.translatePoints(xy);
2014 if (xy[0] !== false) {
2015 el.dom.style.left = pts.left + "px";
2017 if (xy[1] !== false) {
2018 el.dom.style.top = pts.top + "px";
2022 setX : function(el, x) {
2023 this.setXY(el, [x, false]);
2026 setY : function(el, y) {
2027 this.setXY(el, [false, y]);
2031 * Portions of this file are based on pieces of Yahoo User Interface Library
2032 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2033 * YUI licensed under the BSD License:
2034 * http://developer.yahoo.net/yui/license.txt
2035 * <script type="text/javascript">
2039 Roo.lib.Event = function() {
2040 var loadComplete = false;
2042 var unloadListeners = [];
2044 var onAvailStack = [];
2046 var lastError = null;
2059 startInterval: function() {
2060 if (!this._interval) {
2062 var callback = function() {
2063 self._tryPreloadAttach();
2065 this._interval = setInterval(callback, this.POLL_INTERVAL);
2070 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2071 onAvailStack.push({ id: p_id,
2074 override: p_override,
2075 checkReady: false });
2077 retryCount = this.POLL_RETRYS;
2078 this.startInterval();
2082 addListener: function(el, eventName, fn) {
2083 el = Roo.getDom(el);
2088 if ("unload" == eventName) {
2089 unloadListeners[unloadListeners.length] =
2090 [el, eventName, fn];
2094 var wrappedFn = function(e) {
2095 return fn(Roo.lib.Event.getEvent(e));
2098 var li = [el, eventName, fn, wrappedFn];
2100 var index = listeners.length;
2101 listeners[index] = li;
2103 this.doAdd(el, eventName, wrappedFn, false);
2109 removeListener: function(el, eventName, fn) {
2112 el = Roo.getDom(el);
2115 return this.purgeElement(el, false, eventName);
2119 if ("unload" == eventName) {
2121 for (i = 0,len = unloadListeners.length; i < len; i++) {
2122 var li = unloadListeners[i];
2125 li[1] == eventName &&
2127 unloadListeners.splice(i, 1);
2135 var cacheItem = null;
2138 var index = arguments[3];
2140 if ("undefined" == typeof index) {
2141 index = this._getCacheIndex(el, eventName, fn);
2145 cacheItem = listeners[index];
2148 if (!el || !cacheItem) {
2152 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2154 delete listeners[index][this.WFN];
2155 delete listeners[index][this.FN];
2156 listeners.splice(index, 1);
2163 getTarget: function(ev, resolveTextNode) {
2164 ev = ev.browserEvent || ev;
2165 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2166 var t = ev.target || ev.srcElement;
2167 return this.resolveTextNode(t);
2171 resolveTextNode: function(node) {
2172 if (Roo.isSafari && node && 3 == node.nodeType) {
2173 return node.parentNode;
2180 getPageX: function(ev) {
2181 ev = ev.browserEvent || ev;
2182 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 if (!x && 0 !== x) {
2185 x = ev.clientX || 0;
2188 x += this.getScroll()[1];
2196 getPageY: function(ev) {
2197 ev = ev.browserEvent || ev;
2198 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2200 if (!y && 0 !== y) {
2201 y = ev.clientY || 0;
2204 y += this.getScroll()[0];
2213 getXY: function(ev) {
2214 ev = ev.browserEvent || ev;
2215 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2216 return [this.getPageX(ev), this.getPageY(ev)];
2220 getRelatedTarget: function(ev) {
2221 ev = ev.browserEvent || ev;
2222 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2223 var t = ev.relatedTarget;
2225 if (ev.type == "mouseout") {
2227 } else if (ev.type == "mouseover") {
2232 return this.resolveTextNode(t);
2236 getTime: function(ev) {
2237 ev = ev.browserEvent || ev;
2238 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2240 var t = new Date().getTime();
2244 this.lastError = ex;
2253 stopEvent: function(ev) {
2254 this.stopPropagation(ev);
2255 this.preventDefault(ev);
2259 stopPropagation: function(ev) {
2260 ev = ev.browserEvent || ev;
2261 if (ev.stopPropagation) {
2262 ev.stopPropagation();
2264 ev.cancelBubble = true;
2269 preventDefault: function(ev) {
2270 ev = ev.browserEvent || ev;
2271 if(ev.preventDefault) {
2272 ev.preventDefault();
2274 ev.returnValue = false;
2279 getEvent: function(e) {
2280 var ev = e || window.event;
2282 var c = this.getEvent.caller;
2284 ev = c.arguments[0];
2285 if (ev && Event == ev.constructor) {
2295 getCharCode: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 return ev.charCode || ev.keyCode || 0;
2301 _getCacheIndex: function(el, eventName, fn) {
2302 for (var i = 0,len = listeners.length; i < len; ++i) {
2303 var li = listeners[i];
2305 li[this.FN] == fn &&
2306 li[this.EL] == el &&
2307 li[this.TYPE] == eventName) {
2319 getEl: function(id) {
2320 return document.getElementById(id);
2324 clearCache: function() {
2328 _load: function(e) {
2329 loadComplete = true;
2330 var EU = Roo.lib.Event;
2334 EU.doRemove(window, "load", EU._load);
2339 _tryPreloadAttach: function() {
2348 var tryAgain = !loadComplete;
2350 tryAgain = (retryCount > 0);
2355 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2356 var item = onAvailStack[i];
2358 var el = this.getEl(item.id);
2361 if (!item.checkReady ||
2364 (document && document.body)) {
2367 if (item.override) {
2368 if (item.override === true) {
2371 scope = item.override;
2374 item.fn.call(scope, item.obj);
2375 onAvailStack[i] = null;
2378 notAvail.push(item);
2383 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2387 this.startInterval();
2389 clearInterval(this._interval);
2390 this._interval = null;
2393 this.locked = false;
2400 purgeElement: function(el, recurse, eventName) {
2401 var elListeners = this.getListeners(el, eventName);
2403 for (var i = 0,len = elListeners.length; i < len; ++i) {
2404 var l = elListeners[i];
2405 this.removeListener(el, l.type, l.fn);
2409 if (recurse && el && el.childNodes) {
2410 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2411 this.purgeElement(el.childNodes[i], recurse, eventName);
2417 getListeners: function(el, eventName) {
2418 var results = [], searchLists;
2420 searchLists = [listeners, unloadListeners];
2421 } else if (eventName == "unload") {
2422 searchLists = [unloadListeners];
2424 searchLists = [listeners];
2427 for (var j = 0; j < searchLists.length; ++j) {
2428 var searchList = searchLists[j];
2429 if (searchList && searchList.length > 0) {
2430 for (var i = 0,len = searchList.length; i < len; ++i) {
2431 var l = searchList[i];
2432 if (l && l[this.EL] === el &&
2433 (!eventName || eventName === l[this.TYPE])) {
2438 adjust: l[this.ADJ_SCOPE],
2446 return (results.length) ? results : null;
2450 _unload: function(e) {
2452 var EU = Roo.lib.Event, i, j, l, len, index;
2454 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2455 l = unloadListeners[i];
2458 if (l[EU.ADJ_SCOPE]) {
2459 if (l[EU.ADJ_SCOPE] === true) {
2462 scope = l[EU.ADJ_SCOPE];
2465 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2466 unloadListeners[i] = null;
2472 unloadListeners = null;
2474 if (listeners && listeners.length > 0) {
2475 j = listeners.length;
2478 l = listeners[index];
2480 EU.removeListener(l[EU.EL], l[EU.TYPE],
2490 EU.doRemove(window, "unload", EU._unload);
2495 getScroll: function() {
2496 var dd = document.documentElement, db = document.body;
2497 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2498 return [dd.scrollTop, dd.scrollLeft];
2500 return [db.scrollTop, db.scrollLeft];
2507 doAdd: function () {
2508 if (window.addEventListener) {
2509 return function(el, eventName, fn, capture) {
2510 el.addEventListener(eventName, fn, (capture));
2512 } else if (window.attachEvent) {
2513 return function(el, eventName, fn, capture) {
2514 el.attachEvent("on" + eventName, fn);
2523 doRemove: function() {
2524 if (window.removeEventListener) {
2525 return function (el, eventName, fn, capture) {
2526 el.removeEventListener(eventName, fn, (capture));
2528 } else if (window.detachEvent) {
2529 return function (el, eventName, fn) {
2530 el.detachEvent("on" + eventName, fn);
2542 var E = Roo.lib.Event;
2543 E.on = E.addListener;
2544 E.un = E.removeListener;
2546 if (document && document.body) {
2549 E.doAdd(window, "load", E._load);
2551 E.doAdd(window, "unload", E._unload);
2552 E._tryPreloadAttach();
2556 * Portions of this file are based on pieces of Yahoo User Interface Library
2557 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2558 * YUI licensed under the BSD License:
2559 * http://developer.yahoo.net/yui/license.txt
2560 * <script type="text/javascript">
2566 * @class Roo.lib.Ajax
2573 request : function(method, uri, cb, data, options) {
2575 var hs = options.headers;
2578 if(hs.hasOwnProperty(h)){
2579 this.initHeader(h, hs[h], false);
2583 if(options.xmlData){
2584 this.initHeader('Content-Type', 'text/xml', false);
2586 data = options.xmlData;
2590 return this.asyncRequest(method, uri, cb, data);
2593 serializeForm : function(form) {
2594 if(typeof form == 'string') {
2595 form = (document.getElementById(form) || document.forms[form]);
2598 var el, name, val, disabled, data = '', hasSubmit = false;
2599 for (var i = 0; i < form.elements.length; i++) {
2600 el = form.elements[i];
2601 disabled = form.elements[i].disabled;
2602 name = form.elements[i].name;
2603 val = form.elements[i].value;
2605 if (!disabled && name){
2609 case 'select-multiple':
2610 for (var j = 0; j < el.options.length; j++) {
2611 if (el.options[j].selected) {
2613 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2616 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2624 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2637 if(hasSubmit == false) {
2638 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2643 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2648 data = data.substr(0, data.length - 1);
2656 useDefaultHeader:true,
2658 defaultPostHeader:'application/x-www-form-urlencoded',
2660 useDefaultXhrHeader:true,
2662 defaultXhrHeader:'XMLHttpRequest',
2664 hasDefaultHeaders:true,
2676 setProgId:function(id)
2678 this.activeX.unshift(id);
2681 setDefaultPostHeader:function(b)
2683 this.useDefaultHeader = b;
2686 setDefaultXhrHeader:function(b)
2688 this.useDefaultXhrHeader = b;
2691 setPollingInterval:function(i)
2693 if (typeof i == 'number' && isFinite(i)) {
2694 this.pollInterval = i;
2698 createXhrObject:function(transactionId)
2704 http = new XMLHttpRequest();
2706 obj = { conn:http, tId:transactionId };
2710 for (var i = 0; i < this.activeX.length; ++i) {
2714 http = new ActiveXObject(this.activeX[i]);
2716 obj = { conn:http, tId:transactionId };
2729 getConnectionObject:function()
2732 var tId = this.transactionId;
2736 o = this.createXhrObject(tId);
2738 this.transactionId++;
2749 asyncRequest:function(method, uri, callback, postData)
2751 var o = this.getConnectionObject();
2757 o.conn.open(method, uri, true);
2759 if (this.useDefaultXhrHeader) {
2760 if (!this.defaultHeaders['X-Requested-With']) {
2761 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2765 if(postData && this.useDefaultHeader){
2766 this.initHeader('Content-Type', this.defaultPostHeader);
2769 if (this.hasDefaultHeaders || this.hasHeaders) {
2773 this.handleReadyState(o, callback);
2774 o.conn.send(postData || null);
2780 handleReadyState:function(o, callback)
2784 if (callback && callback.timeout) {
2786 this.timeout[o.tId] = window.setTimeout(function() {
2787 oConn.abort(o, callback, true);
2788 }, callback.timeout);
2791 this.poll[o.tId] = window.setInterval(
2793 if (o.conn && o.conn.readyState == 4) {
2794 window.clearInterval(oConn.poll[o.tId]);
2795 delete oConn.poll[o.tId];
2797 if(callback && callback.timeout) {
2798 window.clearTimeout(oConn.timeout[o.tId]);
2799 delete oConn.timeout[o.tId];
2802 oConn.handleTransactionResponse(o, callback);
2805 , this.pollInterval);
2808 handleTransactionResponse:function(o, callback, isAbort)
2812 this.releaseObject(o);
2816 var httpStatus, responseObject;
2820 if (o.conn.status !== undefined && o.conn.status != 0) {
2821 httpStatus = o.conn.status;
2833 if (httpStatus >= 200 && httpStatus < 300) {
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.success) {
2836 if (!callback.scope) {
2837 callback.success(responseObject);
2842 callback.success.apply(callback.scope, [responseObject]);
2847 switch (httpStatus) {
2855 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2856 if (callback.failure) {
2857 if (!callback.scope) {
2858 callback.failure(responseObject);
2861 callback.failure.apply(callback.scope, [responseObject]);
2866 responseObject = this.createResponseObject(o, callback.argument);
2867 if (callback.failure) {
2868 if (!callback.scope) {
2869 callback.failure(responseObject);
2872 callback.failure.apply(callback.scope, [responseObject]);
2878 this.releaseObject(o);
2879 responseObject = null;
2882 createResponseObject:function(o, callbackArg)
2889 var headerStr = o.conn.getAllResponseHeaders();
2890 var header = headerStr.split('\n');
2891 for (var i = 0; i < header.length; i++) {
2892 var delimitPos = header[i].indexOf(':');
2893 if (delimitPos != -1) {
2894 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2902 obj.status = o.conn.status;
2903 obj.statusText = o.conn.statusText;
2904 obj.getResponseHeader = headerObj;
2905 obj.getAllResponseHeaders = headerStr;
2906 obj.responseText = o.conn.responseText;
2907 obj.responseXML = o.conn.responseXML;
2909 if (typeof callbackArg !== undefined) {
2910 obj.argument = callbackArg;
2916 createExceptionObject:function(tId, callbackArg, isAbort)
2919 var COMM_ERROR = 'communication failure';
2920 var ABORT_CODE = -1;
2921 var ABORT_ERROR = 'transaction aborted';
2927 obj.status = ABORT_CODE;
2928 obj.statusText = ABORT_ERROR;
2931 obj.status = COMM_CODE;
2932 obj.statusText = COMM_ERROR;
2936 obj.argument = callbackArg;
2942 initHeader:function(label, value, isDefault)
2944 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2946 if (headerObj[label] === undefined) {
2947 headerObj[label] = value;
2952 headerObj[label] = value + "," + headerObj[label];
2956 this.hasDefaultHeaders = true;
2959 this.hasHeaders = true;
2964 setHeader:function(o)
2966 if (this.hasDefaultHeaders) {
2967 for (var prop in this.defaultHeaders) {
2968 if (this.defaultHeaders.hasOwnProperty(prop)) {
2969 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2974 if (this.hasHeaders) {
2975 for (var prop in this.headers) {
2976 if (this.headers.hasOwnProperty(prop)) {
2977 o.conn.setRequestHeader(prop, this.headers[prop]);
2981 this.hasHeaders = false;
2985 resetDefaultHeaders:function() {
2986 delete this.defaultHeaders;
2987 this.defaultHeaders = {};
2988 this.hasDefaultHeaders = false;
2991 abort:function(o, callback, isTimeout)
2993 if(this.isCallInProgress(o)) {
2995 window.clearInterval(this.poll[o.tId]);
2996 delete this.poll[o.tId];
2998 delete this.timeout[o.tId];
3001 this.handleTransactionResponse(o, callback, true);
3011 isCallInProgress:function(o)
3014 return o.conn.readyState != 4 && o.conn.readyState != 0;
3023 releaseObject:function(o)
3032 'MSXML2.XMLHTTP.3.0',
3040 * Portions of this file are based on pieces of Yahoo User Interface Library
3041 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3042 * YUI licensed under the BSD License:
3043 * http://developer.yahoo.net/yui/license.txt
3044 * <script type="text/javascript">
3048 Roo.lib.Region = function(t, r, b, l) {
3058 Roo.lib.Region.prototype = {
3059 contains : function(region) {
3060 return ( region.left >= this.left &&
3061 region.right <= this.right &&
3062 region.top >= this.top &&
3063 region.bottom <= this.bottom );
3067 getArea : function() {
3068 return ( (this.bottom - this.top) * (this.right - this.left) );
3071 intersect : function(region) {
3072 var t = Math.max(this.top, region.top);
3073 var r = Math.min(this.right, region.right);
3074 var b = Math.min(this.bottom, region.bottom);
3075 var l = Math.max(this.left, region.left);
3077 if (b >= t && r >= l) {
3078 return new Roo.lib.Region(t, r, b, l);
3083 union : function(region) {
3084 var t = Math.min(this.top, region.top);
3085 var r = Math.max(this.right, region.right);
3086 var b = Math.max(this.bottom, region.bottom);
3087 var l = Math.min(this.left, region.left);
3089 return new Roo.lib.Region(t, r, b, l);
3092 adjust : function(t, l, b, r) {
3101 Roo.lib.Region.getRegion = function(el) {
3102 var p = Roo.lib.Dom.getXY(el);
3105 var r = p[0] + el.offsetWidth;
3106 var b = p[1] + el.offsetHeight;
3109 return new Roo.lib.Region(t, r, b, l);
3112 * Portions of this file are based on pieces of Yahoo User Interface Library
3113 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3114 * YUI licensed under the BSD License:
3115 * http://developer.yahoo.net/yui/license.txt
3116 * <script type="text/javascript">
3119 //@@dep Roo.lib.Region
3122 Roo.lib.Point = function(x, y) {
3123 if (x instanceof Array) {
3127 this.x = this.right = this.left = this[0] = x;
3128 this.y = this.top = this.bottom = this[1] = y;
3131 Roo.lib.Point.prototype = new Roo.lib.Region();
3133 * Portions of this file are based on pieces of Yahoo User Interface Library
3134 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3135 * YUI licensed under the BSD License:
3136 * http://developer.yahoo.net/yui/license.txt
3137 * <script type="text/javascript">
3144 scroll : function(el, args, duration, easing, cb, scope) {
3145 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3148 motion : function(el, args, duration, easing, cb, scope) {
3149 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3152 color : function(el, args, duration, easing, cb, scope) {
3153 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3156 run : function(el, args, duration, easing, cb, scope, type) {
3157 type = type || Roo.lib.AnimBase;
3158 if (typeof easing == "string") {
3159 easing = Roo.lib.Easing[easing];
3161 var anim = new type(el, args, duration, easing);
3162 anim.animateX(function() {
3163 Roo.callback(cb, scope);
3169 * Portions of this file are based on pieces of Yahoo User Interface Library
3170 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3171 * YUI licensed under the BSD License:
3172 * http://developer.yahoo.net/yui/license.txt
3173 * <script type="text/javascript">
3181 if (!libFlyweight) {
3182 libFlyweight = new Roo.Element.Flyweight();
3184 libFlyweight.dom = el;
3185 return libFlyweight;
3188 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3192 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3194 this.init(el, attributes, duration, method);
3198 Roo.lib.AnimBase.fly = fly;
3202 Roo.lib.AnimBase.prototype = {
3204 toString: function() {
3205 var el = this.getEl();
3206 var id = el.id || el.tagName;
3207 return ("Anim " + id);
3211 noNegatives: /width|height|opacity|padding/i,
3212 offsetAttribute: /^((width|height)|(top|left))$/,
3213 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3214 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3218 doMethod: function(attr, start, end) {
3219 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3223 setAttribute: function(attr, val, unit) {
3224 if (this.patterns.noNegatives.test(attr)) {
3225 val = (val > 0) ? val : 0;
3228 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3232 getAttribute: function(attr) {
3233 var el = this.getEl();
3234 var val = fly(el).getStyle(attr);
3236 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3237 return parseFloat(val);
3240 var a = this.patterns.offsetAttribute.exec(attr) || [];
3241 var pos = !!( a[3] );
3242 var box = !!( a[2] );
3245 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3246 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3255 getDefaultUnit: function(attr) {
3256 if (this.patterns.defaultUnit.test(attr)) {
3263 animateX : function(callback, scope) {
3264 var f = function() {
3265 this.onComplete.removeListener(f);
3266 if (typeof callback == "function") {
3267 callback.call(scope || this, this);
3270 this.onComplete.addListener(f, this);
3275 setRuntimeAttribute: function(attr) {
3278 var attributes = this.attributes;
3280 this.runtimeAttributes[attr] = {};
3282 var isset = function(prop) {
3283 return (typeof prop !== 'undefined');
3286 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3290 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3293 if (isset(attributes[attr]['to'])) {
3294 end = attributes[attr]['to'];
3295 } else if (isset(attributes[attr]['by'])) {
3296 if (start.constructor == Array) {
3298 for (var i = 0, len = start.length; i < len; ++i) {
3299 end[i] = start[i] + attributes[attr]['by'][i];
3302 end = start + attributes[attr]['by'];
3306 this.runtimeAttributes[attr].start = start;
3307 this.runtimeAttributes[attr].end = end;
3310 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3314 init: function(el, attributes, duration, method) {
3316 var isAnimated = false;
3319 var startTime = null;
3322 var actualFrames = 0;
3325 el = Roo.getDom(el);
3328 this.attributes = attributes || {};
3331 this.duration = duration || 1;
3334 this.method = method || Roo.lib.Easing.easeNone;
3337 this.useSeconds = true;
3340 this.currentFrame = 0;
3343 this.totalFrames = Roo.lib.AnimMgr.fps;
3346 this.getEl = function() {
3351 this.isAnimated = function() {
3356 this.getStartTime = function() {
3360 this.runtimeAttributes = {};
3363 this.animate = function() {
3364 if (this.isAnimated()) {
3368 this.currentFrame = 0;
3370 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3372 Roo.lib.AnimMgr.registerElement(this);
3376 this.stop = function(finish) {
3378 this.currentFrame = this.totalFrames;
3379 this._onTween.fire();
3381 Roo.lib.AnimMgr.stop(this);
3384 var onStart = function() {
3385 this.onStart.fire();
3387 this.runtimeAttributes = {};
3388 for (var attr in this.attributes) {
3389 this.setRuntimeAttribute(attr);
3394 startTime = new Date();
3398 var onTween = function() {
3400 duration: new Date() - this.getStartTime(),
3401 currentFrame: this.currentFrame
3404 data.toString = function() {
3406 'duration: ' + data.duration +
3407 ', currentFrame: ' + data.currentFrame
3411 this.onTween.fire(data);
3413 var runtimeAttributes = this.runtimeAttributes;
3415 for (var attr in runtimeAttributes) {
3416 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3422 var onComplete = function() {
3423 var actual_duration = (new Date() - startTime) / 1000 ;
3426 duration: actual_duration,
3427 frames: actualFrames,
3428 fps: actualFrames / actual_duration
3431 data.toString = function() {
3433 'duration: ' + data.duration +
3434 ', frames: ' + data.frames +
3435 ', fps: ' + data.fps
3441 this.onComplete.fire(data);
3445 this._onStart = new Roo.util.Event(this);
3446 this.onStart = new Roo.util.Event(this);
3447 this.onTween = new Roo.util.Event(this);
3448 this._onTween = new Roo.util.Event(this);
3449 this.onComplete = new Roo.util.Event(this);
3450 this._onComplete = new Roo.util.Event(this);
3451 this._onStart.addListener(onStart);
3452 this._onTween.addListener(onTween);
3453 this._onComplete.addListener(onComplete);
3458 * Portions of this file are based on pieces of Yahoo User Interface Library
3459 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3460 * YUI licensed under the BSD License:
3461 * http://developer.yahoo.net/yui/license.txt
3462 * <script type="text/javascript">
3466 Roo.lib.AnimMgr = new function() {
3483 this.registerElement = function(tween) {
3484 queue[queue.length] = tween;
3486 tween._onStart.fire();
3491 this.unRegister = function(tween, index) {
3492 tween._onComplete.fire();
3493 index = index || getIndex(tween);
3495 queue.splice(index, 1);
3499 if (tweenCount <= 0) {
3505 this.start = function() {
3506 if (thread === null) {
3507 thread = setInterval(this.run, this.delay);
3512 this.stop = function(tween) {
3514 clearInterval(thread);
3516 for (var i = 0, len = queue.length; i < len; ++i) {
3517 if (queue[0].isAnimated()) {
3518 this.unRegister(queue[0], 0);
3527 this.unRegister(tween);
3532 this.run = function() {
3533 for (var i = 0, len = queue.length; i < len; ++i) {
3534 var tween = queue[i];
3535 if (!tween || !tween.isAnimated()) {
3539 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3541 tween.currentFrame += 1;
3543 if (tween.useSeconds) {
3544 correctFrame(tween);
3546 tween._onTween.fire();
3549 Roo.lib.AnimMgr.stop(tween, i);
3554 var getIndex = function(anim) {
3555 for (var i = 0, len = queue.length; i < len; ++i) {
3556 if (queue[i] == anim) {
3564 var correctFrame = function(tween) {
3565 var frames = tween.totalFrames;
3566 var frame = tween.currentFrame;
3567 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3568 var elapsed = (new Date() - tween.getStartTime());
3571 if (elapsed < tween.duration * 1000) {
3572 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3574 tweak = frames - (frame + 1);
3576 if (tweak > 0 && isFinite(tweak)) {
3577 if (tween.currentFrame + tweak >= frames) {
3578 tweak = frames - (frame + 1);
3581 tween.currentFrame += tweak;
3587 * Portions of this file are based on pieces of Yahoo User Interface Library
3588 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3589 * YUI licensed under the BSD License:
3590 * http://developer.yahoo.net/yui/license.txt
3591 * <script type="text/javascript">
3594 Roo.lib.Bezier = new function() {
3596 this.getPosition = function(points, t) {
3597 var n = points.length;
3600 for (var i = 0; i < n; ++i) {
3601 tmp[i] = [points[i][0], points[i][1]];
3604 for (var j = 1; j < n; ++j) {
3605 for (i = 0; i < n - j; ++i) {
3606 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3607 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3611 return [ tmp[0][0], tmp[0][1] ];
3615 * Portions of this file are based on pieces of Yahoo User Interface Library
3616 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3617 * YUI licensed under the BSD License:
3618 * http://developer.yahoo.net/yui/license.txt
3619 * <script type="text/javascript">
3624 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3625 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3628 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3630 var fly = Roo.lib.AnimBase.fly;
3632 var superclass = Y.ColorAnim.superclass;
3633 var proto = Y.ColorAnim.prototype;
3635 proto.toString = function() {
3636 var el = this.getEl();
3637 var id = el.id || el.tagName;
3638 return ("ColorAnim " + id);
3641 proto.patterns.color = /color$/i;
3642 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3643 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3644 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3645 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3648 proto.parseColor = function(s) {
3649 if (s.length == 3) {
3653 var c = this.patterns.hex.exec(s);
3654 if (c && c.length == 4) {
3655 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3658 c = this.patterns.rgb.exec(s);
3659 if (c && c.length == 4) {
3660 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3663 c = this.patterns.hex3.exec(s);
3664 if (c && c.length == 4) {
3665 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3670 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3671 proto.getAttribute = function(attr) {
3672 var el = this.getEl();
3673 if (this.patterns.color.test(attr)) {
3674 var val = fly(el).getStyle(attr);
3676 if (this.patterns.transparent.test(val)) {
3677 var parent = el.parentNode;
3678 val = fly(parent).getStyle(attr);
3680 while (parent && this.patterns.transparent.test(val)) {
3681 parent = parent.parentNode;
3682 val = fly(parent).getStyle(attr);
3683 if (parent.tagName.toUpperCase() == 'HTML') {
3689 val = superclass.getAttribute.call(this, attr);
3694 proto.getAttribute = function(attr) {
3695 var el = this.getEl();
3696 if (this.patterns.color.test(attr)) {
3697 var val = fly(el).getStyle(attr);
3699 if (this.patterns.transparent.test(val)) {
3700 var parent = el.parentNode;
3701 val = fly(parent).getStyle(attr);
3703 while (parent && this.patterns.transparent.test(val)) {
3704 parent = parent.parentNode;
3705 val = fly(parent).getStyle(attr);
3706 if (parent.tagName.toUpperCase() == 'HTML') {
3712 val = superclass.getAttribute.call(this, attr);
3718 proto.doMethod = function(attr, start, end) {
3721 if (this.patterns.color.test(attr)) {
3723 for (var i = 0, len = start.length; i < len; ++i) {
3724 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3727 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3730 val = superclass.doMethod.call(this, attr, start, end);
3736 proto.setRuntimeAttribute = function(attr) {
3737 superclass.setRuntimeAttribute.call(this, attr);
3739 if (this.patterns.color.test(attr)) {
3740 var attributes = this.attributes;
3741 var start = this.parseColor(this.runtimeAttributes[attr].start);
3742 var end = this.parseColor(this.runtimeAttributes[attr].end);
3744 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3745 end = this.parseColor(attributes[attr].by);
3747 for (var i = 0, len = start.length; i < len; ++i) {
3748 end[i] = start[i] + end[i];
3752 this.runtimeAttributes[attr].start = start;
3753 this.runtimeAttributes[attr].end = end;
3759 * Portions of this file are based on pieces of Yahoo User Interface Library
3760 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3761 * YUI licensed under the BSD License:
3762 * http://developer.yahoo.net/yui/license.txt
3763 * <script type="text/javascript">
3769 easeNone: function (t, b, c, d) {
3770 return c * t / d + b;
3774 easeIn: function (t, b, c, d) {
3775 return c * (t /= d) * t + b;
3779 easeOut: function (t, b, c, d) {
3780 return -c * (t /= d) * (t - 2) + b;
3784 easeBoth: function (t, b, c, d) {
3785 if ((t /= d / 2) < 1) {
3786 return c / 2 * t * t + b;
3789 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3793 easeInStrong: function (t, b, c, d) {
3794 return c * (t /= d) * t * t * t + b;
3798 easeOutStrong: function (t, b, c, d) {
3799 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3803 easeBothStrong: function (t, b, c, d) {
3804 if ((t /= d / 2) < 1) {
3805 return c / 2 * t * t * t * t + b;
3808 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3813 elasticIn: function (t, b, c, d, a, p) {
3817 if ((t /= d) == 1) {
3824 if (!a || a < Math.abs(c)) {
3829 var s = p / (2 * Math.PI) * Math.asin(c / a);
3832 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3836 elasticOut: function (t, b, c, d, a, p) {
3840 if ((t /= d) == 1) {
3847 if (!a || a < Math.abs(c)) {
3852 var s = p / (2 * Math.PI) * Math.asin(c / a);
3855 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3859 elasticBoth: function (t, b, c, d, a, p) {
3864 if ((t /= d / 2) == 2) {
3872 if (!a || a < Math.abs(c)) {
3877 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3882 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3884 return a * Math.pow(2, -10 * (t -= 1)) *
3885 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3890 backIn: function (t, b, c, d, s) {
3891 if (typeof s == 'undefined') {
3894 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3898 backOut: function (t, b, c, d, s) {
3899 if (typeof s == 'undefined') {
3902 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3906 backBoth: function (t, b, c, d, s) {
3907 if (typeof s == 'undefined') {
3911 if ((t /= d / 2 ) < 1) {
3912 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3914 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3918 bounceIn: function (t, b, c, d) {
3919 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3923 bounceOut: function (t, b, c, d) {
3924 if ((t /= d) < (1 / 2.75)) {
3925 return c * (7.5625 * t * t) + b;
3926 } else if (t < (2 / 2.75)) {
3927 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3928 } else if (t < (2.5 / 2.75)) {
3929 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3931 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3935 bounceBoth: function (t, b, c, d) {
3937 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3939 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3942 * Portions of this file are based on pieces of Yahoo User Interface Library
3943 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3944 * YUI licensed under the BSD License:
3945 * http://developer.yahoo.net/yui/license.txt
3946 * <script type="text/javascript">
3950 Roo.lib.Motion = function(el, attributes, duration, method) {
3952 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3956 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3960 var superclass = Y.Motion.superclass;
3961 var proto = Y.Motion.prototype;
3963 proto.toString = function() {
3964 var el = this.getEl();
3965 var id = el.id || el.tagName;
3966 return ("Motion " + id);
3969 proto.patterns.points = /^points$/i;
3971 proto.setAttribute = function(attr, val, unit) {
3972 if (this.patterns.points.test(attr)) {
3973 unit = unit || 'px';
3974 superclass.setAttribute.call(this, 'left', val[0], unit);
3975 superclass.setAttribute.call(this, 'top', val[1], unit);
3977 superclass.setAttribute.call(this, attr, val, unit);
3981 proto.getAttribute = function(attr) {
3982 if (this.patterns.points.test(attr)) {
3984 superclass.getAttribute.call(this, 'left'),
3985 superclass.getAttribute.call(this, 'top')
3988 val = superclass.getAttribute.call(this, attr);
3994 proto.doMethod = function(attr, start, end) {
3997 if (this.patterns.points.test(attr)) {
3998 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3999 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4001 val = superclass.doMethod.call(this, attr, start, end);
4006 proto.setRuntimeAttribute = function(attr) {
4007 if (this.patterns.points.test(attr)) {
4008 var el = this.getEl();
4009 var attributes = this.attributes;
4011 var control = attributes['points']['control'] || [];
4015 if (control.length > 0 && !(control[0] instanceof Array)) {
4016 control = [control];
4019 for (i = 0,len = control.length; i < len; ++i) {
4020 tmp[i] = control[i];
4025 Roo.fly(el).position();
4027 if (isset(attributes['points']['from'])) {
4028 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4031 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4034 start = this.getAttribute('points');
4037 if (isset(attributes['points']['to'])) {
4038 end = translateValues.call(this, attributes['points']['to'], start);
4040 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4041 for (i = 0,len = control.length; i < len; ++i) {
4042 control[i] = translateValues.call(this, control[i], start);
4046 } else if (isset(attributes['points']['by'])) {
4047 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4049 for (i = 0,len = control.length; i < len; ++i) {
4050 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4054 this.runtimeAttributes[attr] = [start];
4056 if (control.length > 0) {
4057 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4060 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4063 superclass.setRuntimeAttribute.call(this, attr);
4067 var translateValues = function(val, start) {
4068 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4069 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4074 var isset = function(prop) {
4075 return (typeof prop !== 'undefined');
4079 * Portions of this file are based on pieces of Yahoo User Interface Library
4080 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4081 * YUI licensed under the BSD License:
4082 * http://developer.yahoo.net/yui/license.txt
4083 * <script type="text/javascript">
4087 Roo.lib.Scroll = function(el, attributes, duration, method) {
4089 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4093 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4097 var superclass = Y.Scroll.superclass;
4098 var proto = Y.Scroll.prototype;
4100 proto.toString = function() {
4101 var el = this.getEl();
4102 var id = el.id || el.tagName;
4103 return ("Scroll " + id);
4106 proto.doMethod = function(attr, start, end) {
4109 if (attr == 'scroll') {
4111 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4112 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4116 val = superclass.doMethod.call(this, attr, start, end);
4121 proto.getAttribute = function(attr) {
4123 var el = this.getEl();
4125 if (attr == 'scroll') {
4126 val = [ el.scrollLeft, el.scrollTop ];
4128 val = superclass.getAttribute.call(this, attr);
4134 proto.setAttribute = function(attr, val, unit) {
4135 var el = this.getEl();
4137 if (attr == 'scroll') {
4138 el.scrollLeft = val[0];
4139 el.scrollTop = val[1];
4141 superclass.setAttribute.call(this, attr, val, unit);
4147 * Ext JS Library 1.1.1
4148 * Copyright(c) 2006-2007, Ext JS, LLC.
4150 * Originally Released Under LGPL - original licence link has changed is not relivant.
4153 * <script type="text/javascript">
4157 // nasty IE9 hack - what a pile of crap that is..
4159 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4160 Range.prototype.createContextualFragment = function (html) {
4161 var doc = window.document;
4162 var container = doc.createElement("div");
4163 container.innerHTML = html;
4164 var frag = doc.createDocumentFragment(), n;
4165 while ((n = container.firstChild)) {
4166 frag.appendChild(n);
4173 * @class Roo.DomHelper
4174 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4175 * 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>.
4178 Roo.DomHelper = function(){
4179 var tempTableEl = null;
4180 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4181 var tableRe = /^table|tbody|tr|td$/i;
4183 // build as innerHTML where available
4185 var createHtml = function(o){
4186 if(typeof o == 'string'){
4195 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4196 if(attr == "style"){
4198 if(typeof s == "function"){
4201 if(typeof s == "string"){
4202 b += ' style="' + s + '"';
4203 }else if(typeof s == "object"){
4206 if(typeof s[key] != "function"){
4207 b += key + ":" + s[key] + ";";
4214 b += ' class="' + o["cls"] + '"';
4215 }else if(attr == "htmlFor"){
4216 b += ' for="' + o["htmlFor"] + '"';
4218 b += " " + attr + '="' + o[attr] + '"';
4222 if(emptyTags.test(o.tag)){
4226 var cn = o.children || o.cn;
4228 //http://bugs.kde.org/show_bug.cgi?id=71506
4229 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4230 for(var i = 0, len = cn.length; i < len; i++) {
4231 b += createHtml(cn[i], b);
4234 b += createHtml(cn, b);
4240 b += "</" + o.tag + ">";
4247 var createDom = function(o, parentNode){
4249 // defininition craeted..
4251 if (o.ns && o.ns != 'html') {
4253 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4254 xmlns[o.ns] = o.xmlns;
4257 if (typeof(xmlns[o.ns]) == 'undefined') {
4258 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4264 if (typeof(o) == 'string') {
4265 return parentNode.appendChild(document.createTextNode(o));
4267 o.tag = o.tag || div;
4268 if (o.ns && Roo.isIE) {
4270 o.tag = o.ns + ':' + o.tag;
4273 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4274 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4277 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4278 attr == "style" || typeof o[attr] == "function") { continue; }
4280 if(attr=="cls" && Roo.isIE){
4281 el.className = o["cls"];
4283 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4289 Roo.DomHelper.applyStyles(el, o.style);
4290 var cn = o.children || o.cn;
4292 //http://bugs.kde.org/show_bug.cgi?id=71506
4293 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4294 for(var i = 0, len = cn.length; i < len; i++) {
4295 createDom(cn[i], el);
4302 el.innerHTML = o.html;
4305 parentNode.appendChild(el);
4310 var ieTable = function(depth, s, h, e){
4311 tempTableEl.innerHTML = [s, h, e].join('');
4312 var i = -1, el = tempTableEl;
4319 // kill repeat to save bytes
4323 tbe = '</tbody>'+te,
4329 * Nasty code for IE's broken table implementation
4331 var insertIntoTable = function(tag, where, el, html){
4333 tempTableEl = document.createElement('div');
4338 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4341 if(where == 'beforebegin'){
4345 before = el.nextSibling;
4348 node = ieTable(4, trs, html, tre);
4350 else if(tag == 'tr'){
4351 if(where == 'beforebegin'){
4354 node = ieTable(3, tbs, html, tbe);
4355 } else if(where == 'afterend'){
4356 before = el.nextSibling;
4358 node = ieTable(3, tbs, html, tbe);
4359 } else{ // INTO a TR
4360 if(where == 'afterbegin'){
4361 before = el.firstChild;
4363 node = ieTable(4, trs, html, tre);
4365 } else if(tag == 'tbody'){
4366 if(where == 'beforebegin'){
4369 node = ieTable(2, ts, html, te);
4370 } else if(where == 'afterend'){
4371 before = el.nextSibling;
4373 node = ieTable(2, ts, html, te);
4375 if(where == 'afterbegin'){
4376 before = el.firstChild;
4378 node = ieTable(3, tbs, html, tbe);
4381 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4384 if(where == 'afterbegin'){
4385 before = el.firstChild;
4387 node = ieTable(2, ts, html, te);
4389 el.insertBefore(node, before);
4394 /** True to force the use of DOM instead of html fragments @type Boolean */
4398 * Returns the markup for the passed Element(s) config
4399 * @param {Object} o The Dom object spec (and children)
4402 markup : function(o){
4403 return createHtml(o);
4407 * Applies a style specification to an element
4408 * @param {String/HTMLElement} el The element to apply styles to
4409 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4410 * a function which returns such a specification.
4412 applyStyles : function(el, styles){
4415 if(typeof styles == "string"){
4416 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4418 while ((matches = re.exec(styles)) != null){
4419 el.setStyle(matches[1], matches[2]);
4421 }else if (typeof styles == "object"){
4422 for (var style in styles){
4423 el.setStyle(style, styles[style]);
4425 }else if (typeof styles == "function"){
4426 Roo.DomHelper.applyStyles(el, styles.call());
4432 * Inserts an HTML fragment into the Dom
4433 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4434 * @param {HTMLElement} el The context element
4435 * @param {String} html The HTML fragmenet
4436 * @return {HTMLElement} The new node
4438 insertHtml : function(where, el, html){
4439 where = where.toLowerCase();
4440 if(el.insertAdjacentHTML){
4441 if(tableRe.test(el.tagName)){
4443 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4449 el.insertAdjacentHTML('BeforeBegin', html);
4450 return el.previousSibling;
4452 el.insertAdjacentHTML('AfterBegin', html);
4453 return el.firstChild;
4455 el.insertAdjacentHTML('BeforeEnd', html);
4456 return el.lastChild;
4458 el.insertAdjacentHTML('AfterEnd', html);
4459 return el.nextSibling;
4461 throw 'Illegal insertion point -> "' + where + '"';
4463 var range = el.ownerDocument.createRange();
4467 range.setStartBefore(el);
4468 frag = range.createContextualFragment(html);
4469 el.parentNode.insertBefore(frag, el);
4470 return el.previousSibling;
4473 range.setStartBefore(el.firstChild);
4474 frag = range.createContextualFragment(html);
4475 el.insertBefore(frag, el.firstChild);
4476 return el.firstChild;
4478 el.innerHTML = html;
4479 return el.firstChild;
4483 range.setStartAfter(el.lastChild);
4484 frag = range.createContextualFragment(html);
4485 el.appendChild(frag);
4486 return el.lastChild;
4488 el.innerHTML = html;
4489 return el.lastChild;
4492 range.setStartAfter(el);
4493 frag = range.createContextualFragment(html);
4494 el.parentNode.insertBefore(frag, el.nextSibling);
4495 return el.nextSibling;
4497 throw 'Illegal insertion point -> "' + where + '"';
4501 * Creates new Dom element(s) and inserts them before el
4502 * @param {String/HTMLElement/Element} el The context element
4503 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4504 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4505 * @return {HTMLElement/Roo.Element} The new node
4507 insertBefore : function(el, o, returnElement){
4508 return this.doInsert(el, o, returnElement, "beforeBegin");
4512 * Creates new Dom element(s) and inserts them after el
4513 * @param {String/HTMLElement/Element} el The context element
4514 * @param {Object} o The Dom object spec (and children)
4515 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4516 * @return {HTMLElement/Roo.Element} The new node
4518 insertAfter : function(el, o, returnElement){
4519 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4523 * Creates new Dom element(s) and inserts them as the first child of el
4524 * @param {String/HTMLElement/Element} el The context element
4525 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4526 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4527 * @return {HTMLElement/Roo.Element} The new node
4529 insertFirst : function(el, o, returnElement){
4530 return this.doInsert(el, o, returnElement, "afterBegin");
4534 doInsert : function(el, o, returnElement, pos, sibling){
4535 el = Roo.getDom(el);
4537 if(this.useDom || o.ns){
4538 newNode = createDom(o, null);
4539 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4541 var html = createHtml(o);
4542 newNode = this.insertHtml(pos, el, html);
4544 return returnElement ? Roo.get(newNode, true) : newNode;
4548 * Creates new Dom element(s) and appends them to el
4549 * @param {String/HTMLElement/Element} el The context element
4550 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4551 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4552 * @return {HTMLElement/Roo.Element} The new node
4554 append : function(el, o, returnElement){
4555 el = Roo.getDom(el);
4557 if(this.useDom || o.ns){
4558 newNode = createDom(o, null);
4559 el.appendChild(newNode);
4561 var html = createHtml(o);
4562 newNode = this.insertHtml("beforeEnd", el, html);
4564 return returnElement ? Roo.get(newNode, true) : newNode;
4568 * Creates new Dom element(s) and overwrites the contents of el with them
4569 * @param {String/HTMLElement/Element} el The context element
4570 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4571 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4572 * @return {HTMLElement/Roo.Element} The new node
4574 overwrite : function(el, o, returnElement){
4575 el = Roo.getDom(el);
4578 while (el.childNodes.length) {
4579 el.removeChild(el.firstChild);
4583 el.innerHTML = createHtml(o);
4586 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4590 * Creates a new Roo.DomHelper.Template from the Dom object spec
4591 * @param {Object} o The Dom object spec (and children)
4592 * @return {Roo.DomHelper.Template} The new template
4594 createTemplate : function(o){
4595 var html = createHtml(o);
4596 return new Roo.Template(html);
4602 * Ext JS Library 1.1.1
4603 * Copyright(c) 2006-2007, Ext JS, LLC.
4605 * Originally Released Under LGPL - original licence link has changed is not relivant.
4608 * <script type="text/javascript">
4612 * @class Roo.Template
4613 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4614 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4617 var t = new Roo.Template({
4618 html : '<div name="{id}">' +
4619 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4621 myformat: function (value, allValues) {
4622 return 'XX' + value;
4625 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4627 * For more information see this blog post with examples:
4628 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4629 - Create Elements using DOM, HTML fragments and Templates</a>.
4631 * @param {Object} cfg - Configuration object.
4633 Roo.Template = function(cfg){
4635 if(cfg instanceof Array){
4637 }else if(arguments.length > 1){
4638 cfg = Array.prototype.join.call(arguments, "");
4642 if (typeof(cfg) == 'object') {
4653 Roo.Template.prototype = {
4656 * @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..
4657 * it should be fixed so that template is observable...
4661 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4665 * Returns an HTML fragment of this template with the specified values applied.
4666 * @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'})
4667 * @return {String} The HTML fragment
4669 applyTemplate : function(values){
4673 return this.compiled(values);
4675 var useF = this.disableFormats !== true;
4676 var fm = Roo.util.Format, tpl = this;
4677 var fn = function(m, name, format, args){
4679 if(format.substr(0, 5) == "this."){
4680 return tpl.call(format.substr(5), values[name], values);
4683 // quoted values are required for strings in compiled templates,
4684 // but for non compiled we need to strip them
4685 // quoted reversed for jsmin
4686 var re = /^\s*['"](.*)["']\s*$/;
4687 args = args.split(',');
4688 for(var i = 0, len = args.length; i < len; i++){
4689 args[i] = args[i].replace(re, "$1");
4691 args = [values[name]].concat(args);
4693 args = [values[name]];
4695 return fm[format].apply(fm, args);
4698 return values[name] !== undefined ? values[name] : "";
4701 return this.html.replace(this.re, fn);
4719 this.loading = true;
4720 this.compiled = false;
4722 var cx = new Roo.data.Connection();
4726 success : function (response) {
4728 _t.html = response.responseText;
4732 failure : function(response) {
4733 Roo.log("Template failed to load from " + _t.url);
4740 * Sets the HTML used as the template and optionally compiles it.
4741 * @param {String} html
4742 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4743 * @return {Roo.Template} this
4745 set : function(html, compile){
4747 this.compiled = null;
4755 * True to disable format functions (defaults to false)
4758 disableFormats : false,
4761 * The regular expression used to match template variables
4765 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4768 * Compiles the template into an internal function, eliminating the RegEx overhead.
4769 * @return {Roo.Template} this
4771 compile : function(){
4772 var fm = Roo.util.Format;
4773 var useF = this.disableFormats !== true;
4774 var sep = Roo.isGecko ? "+" : ",";
4775 var fn = function(m, name, format, args){
4777 args = args ? ',' + args : "";
4778 if(format.substr(0, 5) != "this."){
4779 format = "fm." + format + '(';
4781 format = 'this.call("'+ format.substr(5) + '", ';
4785 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4787 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4790 // branched to use + in gecko and [].join() in others
4792 body = "this.compiled = function(values){ return '" +
4793 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4796 body = ["this.compiled = function(values){ return ['"];
4797 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4798 body.push("'].join('');};");
4799 body = body.join('');
4809 // private function used to call members
4810 call : function(fnName, value, allValues){
4811 return this[fnName](value, allValues);
4815 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4816 * @param {String/HTMLElement/Roo.Element} el The context element
4817 * @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'})
4818 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4819 * @return {HTMLElement/Roo.Element} The new node or Element
4821 insertFirst: function(el, values, returnElement){
4822 return this.doInsert('afterBegin', el, values, returnElement);
4826 * Applies the supplied values to the template and inserts the new node(s) before el.
4827 * @param {String/HTMLElement/Roo.Element} el The context element
4828 * @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'})
4829 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4830 * @return {HTMLElement/Roo.Element} The new node or Element
4832 insertBefore: function(el, values, returnElement){
4833 return this.doInsert('beforeBegin', el, values, returnElement);
4837 * Applies the supplied values to the template and inserts the new node(s) after el.
4838 * @param {String/HTMLElement/Roo.Element} el The context element
4839 * @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'})
4840 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4841 * @return {HTMLElement/Roo.Element} The new node or Element
4843 insertAfter : function(el, values, returnElement){
4844 return this.doInsert('afterEnd', el, values, returnElement);
4848 * Applies the supplied values to the template and appends the new node(s) to el.
4849 * @param {String/HTMLElement/Roo.Element} el The context element
4850 * @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'})
4851 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4852 * @return {HTMLElement/Roo.Element} The new node or Element
4854 append : function(el, values, returnElement){
4855 return this.doInsert('beforeEnd', el, values, returnElement);
4858 doInsert : function(where, el, values, returnEl){
4859 el = Roo.getDom(el);
4860 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4861 return returnEl ? Roo.get(newNode, true) : newNode;
4865 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4866 * @param {String/HTMLElement/Roo.Element} el The context element
4867 * @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'})
4868 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4869 * @return {HTMLElement/Roo.Element} The new node or Element
4871 overwrite : function(el, values, returnElement){
4872 el = Roo.getDom(el);
4873 el.innerHTML = this.applyTemplate(values);
4874 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4878 * Alias for {@link #applyTemplate}
4881 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4884 Roo.DomHelper.Template = Roo.Template;
4887 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4888 * @param {String/HTMLElement} el A DOM element or its id
4889 * @returns {Roo.Template} The created template
4892 Roo.Template.from = function(el){
4893 el = Roo.getDom(el);
4894 return new Roo.Template(el.value || el.innerHTML);
4897 * Ext JS Library 1.1.1
4898 * Copyright(c) 2006-2007, Ext JS, LLC.
4900 * Originally Released Under LGPL - original licence link has changed is not relivant.
4903 * <script type="text/javascript">
4908 * This is code is also distributed under MIT license for use
4909 * with jQuery and prototype JavaScript libraries.
4912 * @class Roo.DomQuery
4913 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).
4915 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>
4918 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.
4920 <h4>Element Selectors:</h4>
4922 <li> <b>*</b> any element</li>
4923 <li> <b>E</b> an element with the tag E</li>
4924 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4925 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4926 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4927 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4929 <h4>Attribute Selectors:</h4>
4930 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4932 <li> <b>E[foo]</b> has an attribute "foo"</li>
4933 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4934 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4935 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4936 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4937 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4938 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4940 <h4>Pseudo Classes:</h4>
4942 <li> <b>E:first-child</b> E is the first child of its parent</li>
4943 <li> <b>E:last-child</b> E is the last child of its parent</li>
4944 <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>
4945 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4946 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4947 <li> <b>E:only-child</b> E is the only child of its parent</li>
4948 <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>
4949 <li> <b>E:first</b> the first E in the resultset</li>
4950 <li> <b>E:last</b> the last E in the resultset</li>
4951 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4952 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4953 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4954 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4955 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4956 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4957 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4958 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4959 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4961 <h4>CSS Value Selectors:</h4>
4963 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4964 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4965 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4966 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4967 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4968 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4972 Roo.DomQuery = function(){
4973 var cache = {}, simpleCache = {}, valueCache = {};
4974 var nonSpace = /\S/;
4975 var trimRe = /^\s+|\s+$/g;
4976 var tplRe = /\{(\d+)\}/g;
4977 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4978 var tagTokenRe = /^(#)?([\w-\*]+)/;
4979 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4981 function child(p, index){
4983 var n = p.firstChild;
4985 if(n.nodeType == 1){
4996 while((n = n.nextSibling) && n.nodeType != 1);
5001 while((n = n.previousSibling) && n.nodeType != 1);
5005 function children(d){
5006 var n = d.firstChild, ni = -1;
5008 var nx = n.nextSibling;
5009 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5019 function byClassName(c, a, v){
5023 var r = [], ri = -1, cn;
5024 for(var i = 0, ci; ci = c[i]; i++){
5025 if((' '+ci.className+' ').indexOf(v) != -1){
5032 function attrValue(n, attr){
5033 if(!n.tagName && typeof n.length != "undefined"){
5042 if(attr == "class" || attr == "className"){
5045 return n.getAttribute(attr) || n[attr];
5049 function getNodes(ns, mode, tagName){
5050 var result = [], ri = -1, cs;
5054 tagName = tagName || "*";
5055 if(typeof ns.getElementsByTagName != "undefined"){
5059 for(var i = 0, ni; ni = ns[i]; i++){
5060 cs = ni.getElementsByTagName(tagName);
5061 for(var j = 0, ci; ci = cs[j]; j++){
5065 }else if(mode == "/" || mode == ">"){
5066 var utag = tagName.toUpperCase();
5067 for(var i = 0, ni, cn; ni = ns[i]; i++){
5068 cn = ni.children || ni.childNodes;
5069 for(var j = 0, cj; cj = cn[j]; j++){
5070 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5075 }else if(mode == "+"){
5076 var utag = tagName.toUpperCase();
5077 for(var i = 0, n; n = ns[i]; i++){
5078 while((n = n.nextSibling) && n.nodeType != 1);
5079 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5083 }else if(mode == "~"){
5084 for(var i = 0, n; n = ns[i]; i++){
5085 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5094 function concat(a, b){
5098 for(var i = 0, l = b.length; i < l; i++){
5104 function byTag(cs, tagName){
5105 if(cs.tagName || cs == document){
5111 var r = [], ri = -1;
5112 tagName = tagName.toLowerCase();
5113 for(var i = 0, ci; ci = cs[i]; i++){
5114 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5121 function byId(cs, attr, id){
5122 if(cs.tagName || cs == document){
5128 var r = [], ri = -1;
5129 for(var i = 0,ci; ci = cs[i]; i++){
5130 if(ci && ci.id == id){
5138 function byAttribute(cs, attr, value, op, custom){
5139 var r = [], ri = -1, st = custom=="{";
5140 var f = Roo.DomQuery.operators[op];
5141 for(var i = 0, ci; ci = cs[i]; i++){
5144 a = Roo.DomQuery.getStyle(ci, attr);
5146 else if(attr == "class" || attr == "className"){
5148 }else if(attr == "for"){
5150 }else if(attr == "href"){
5151 a = ci.getAttribute("href", 2);
5153 a = ci.getAttribute(attr);
5155 if((f && f(a, value)) || (!f && a)){
5162 function byPseudo(cs, name, value){
5163 return Roo.DomQuery.pseudos[name](cs, value);
5166 // This is for IE MSXML which does not support expandos.
5167 // IE runs the same speed using setAttribute, however FF slows way down
5168 // and Safari completely fails so they need to continue to use expandos.
5169 var isIE = window.ActiveXObject ? true : false;
5171 // this eval is stop the compressor from
5172 // renaming the variable to something shorter
5174 /** eval:var:batch */
5179 function nodupIEXml(cs){
5181 cs[0].setAttribute("_nodup", d);
5183 for(var i = 1, len = cs.length; i < len; i++){
5185 if(!c.getAttribute("_nodup") != d){
5186 c.setAttribute("_nodup", d);
5190 for(var i = 0, len = cs.length; i < len; i++){
5191 cs[i].removeAttribute("_nodup");
5200 var len = cs.length, c, i, r = cs, cj, ri = -1;
5201 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5204 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5205 return nodupIEXml(cs);
5209 for(i = 1; c = cs[i]; i++){
5214 for(var j = 0; j < i; j++){
5217 for(j = i+1; cj = cs[j]; j++){
5229 function quickDiffIEXml(c1, c2){
5231 for(var i = 0, len = c1.length; i < len; i++){
5232 c1[i].setAttribute("_qdiff", d);
5235 for(var i = 0, len = c2.length; i < len; i++){
5236 if(c2[i].getAttribute("_qdiff") != d){
5237 r[r.length] = c2[i];
5240 for(var i = 0, len = c1.length; i < len; i++){
5241 c1[i].removeAttribute("_qdiff");
5246 function quickDiff(c1, c2){
5247 var len1 = c1.length;
5251 if(isIE && c1[0].selectSingleNode){
5252 return quickDiffIEXml(c1, c2);
5255 for(var i = 0; i < len1; i++){
5259 for(var i = 0, len = c2.length; i < len; i++){
5260 if(c2[i]._qdiff != d){
5261 r[r.length] = c2[i];
5267 function quickId(ns, mode, root, id){
5269 var d = root.ownerDocument || root;
5270 return d.getElementById(id);
5272 ns = getNodes(ns, mode, "*");
5273 return byId(ns, null, id);
5277 getStyle : function(el, name){
5278 return Roo.fly(el).getStyle(name);
5281 * Compiles a selector/xpath query into a reusable function. The returned function
5282 * takes one parameter "root" (optional), which is the context node from where the query should start.
5283 * @param {String} selector The selector/xpath query
5284 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5285 * @return {Function}
5287 compile : function(path, type){
5288 type = type || "select";
5290 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5291 var q = path, mode, lq;
5292 var tk = Roo.DomQuery.matchers;
5293 var tklen = tk.length;
5296 // accept leading mode switch
5297 var lmode = q.match(modeRe);
5298 if(lmode && lmode[1]){
5299 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5300 q = q.replace(lmode[1], "");
5302 // strip leading slashes
5303 while(path.substr(0, 1)=="/"){
5304 path = path.substr(1);
5307 while(q && lq != q){
5309 var tm = q.match(tagTokenRe);
5310 if(type == "select"){
5313 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5315 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5317 q = q.replace(tm[0], "");
5318 }else if(q.substr(0, 1) != '@'){
5319 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5324 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5326 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5328 q = q.replace(tm[0], "");
5331 while(!(mm = q.match(modeRe))){
5332 var matched = false;
5333 for(var j = 0; j < tklen; j++){
5335 var m = q.match(t.re);
5337 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5340 q = q.replace(m[0], "");
5345 // prevent infinite loop on bad selector
5347 throw 'Error parsing selector, parsing failed at "' + q + '"';
5351 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5352 q = q.replace(mm[1], "");
5355 fn[fn.length] = "return nodup(n);\n}";
5358 * list of variables that need from compression as they are used by eval.
5368 * eval:var:byClassName
5370 * eval:var:byAttribute
5371 * eval:var:attrValue
5379 * Selects a group of elements.
5380 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5381 * @param {Node} root (optional) The start of the query (defaults to document).
5384 select : function(path, root, type){
5385 if(!root || root == document){
5388 if(typeof root == "string"){
5389 root = document.getElementById(root);
5391 var paths = path.split(",");
5393 for(var i = 0, len = paths.length; i < len; i++){
5394 var p = paths[i].replace(trimRe, "");
5396 cache[p] = Roo.DomQuery.compile(p);
5398 throw p + " is not a valid selector";
5401 var result = cache[p](root);
5402 if(result && result != document){
5403 results = results.concat(result);
5406 if(paths.length > 1){
5407 return nodup(results);
5413 * Selects a single element.
5414 * @param {String} selector The selector/xpath query
5415 * @param {Node} root (optional) The start of the query (defaults to document).
5418 selectNode : function(path, root){
5419 return Roo.DomQuery.select(path, root)[0];
5423 * Selects the value of a node, optionally replacing null with the defaultValue.
5424 * @param {String} selector The selector/xpath query
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5426 * @param {String} defaultValue
5428 selectValue : function(path, root, defaultValue){
5429 path = path.replace(trimRe, "");
5430 if(!valueCache[path]){
5431 valueCache[path] = Roo.DomQuery.compile(path, "select");
5433 var n = valueCache[path](root);
5434 n = n[0] ? n[0] : n;
5435 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5436 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5440 * Selects the value of a node, parsing integers and floats.
5441 * @param {String} selector The selector/xpath query
5442 * @param {Node} root (optional) The start of the query (defaults to document).
5443 * @param {Number} defaultValue
5446 selectNumber : function(path, root, defaultValue){
5447 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5448 return parseFloat(v);
5452 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5453 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5454 * @param {String} selector The simple selector to test
5457 is : function(el, ss){
5458 if(typeof el == "string"){
5459 el = document.getElementById(el);
5461 var isArray = (el instanceof Array);
5462 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5463 return isArray ? (result.length == el.length) : (result.length > 0);
5467 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5468 * @param {Array} el An array of elements to filter
5469 * @param {String} selector The simple selector to test
5470 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5471 * the selector instead of the ones that match
5474 filter : function(els, ss, nonMatches){
5475 ss = ss.replace(trimRe, "");
5476 if(!simpleCache[ss]){
5477 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5479 var result = simpleCache[ss](els);
5480 return nonMatches ? quickDiff(result, els) : result;
5484 * Collection of matching regular expressions and code snippets.
5488 select: 'n = byClassName(n, null, " {1} ");'
5490 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5491 select: 'n = byPseudo(n, "{1}", "{2}");'
5493 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5494 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5497 select: 'n = byId(n, null, "{1}");'
5500 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5505 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5506 * 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, > <.
5509 "=" : function(a, v){
5512 "!=" : function(a, v){
5515 "^=" : function(a, v){
5516 return a && a.substr(0, v.length) == v;
5518 "$=" : function(a, v){
5519 return a && a.substr(a.length-v.length) == v;
5521 "*=" : function(a, v){
5522 return a && a.indexOf(v) !== -1;
5524 "%=" : function(a, v){
5525 return (a % v) == 0;
5527 "|=" : function(a, v){
5528 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5530 "~=" : function(a, v){
5531 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5536 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5537 * and the argument (if any) supplied in the selector.
5540 "first-child" : function(c){
5541 var r = [], ri = -1, n;
5542 for(var i = 0, ci; ci = n = c[i]; i++){
5543 while((n = n.previousSibling) && n.nodeType != 1);
5551 "last-child" : function(c){
5552 var r = [], ri = -1, n;
5553 for(var i = 0, ci; ci = n = c[i]; i++){
5554 while((n = n.nextSibling) && n.nodeType != 1);
5562 "nth-child" : function(c, a) {
5563 var r = [], ri = -1;
5564 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5565 var f = (m[1] || 1) - 0, l = m[2] - 0;
5566 for(var i = 0, n; n = c[i]; i++){
5567 var pn = n.parentNode;
5568 if (batch != pn._batch) {
5570 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5571 if(cn.nodeType == 1){
5578 if (l == 0 || n.nodeIndex == l){
5581 } else if ((n.nodeIndex + l) % f == 0){
5589 "only-child" : function(c){
5590 var r = [], ri = -1;;
5591 for(var i = 0, ci; ci = c[i]; i++){
5592 if(!prev(ci) && !next(ci)){
5599 "empty" : function(c){
5600 var r = [], ri = -1;
5601 for(var i = 0, ci; ci = c[i]; i++){
5602 var cns = ci.childNodes, j = 0, cn, empty = true;
5605 if(cn.nodeType == 1 || cn.nodeType == 3){
5617 "contains" : function(c, v){
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5620 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5627 "nodeValue" : function(c, v){
5628 var r = [], ri = -1;
5629 for(var i = 0, ci; ci = c[i]; i++){
5630 if(ci.firstChild && ci.firstChild.nodeValue == v){
5637 "checked" : function(c){
5638 var r = [], ri = -1;
5639 for(var i = 0, ci; ci = c[i]; i++){
5640 if(ci.checked == true){
5647 "not" : function(c, ss){
5648 return Roo.DomQuery.filter(c, ss, true);
5651 "odd" : function(c){
5652 return this["nth-child"](c, "odd");
5655 "even" : function(c){
5656 return this["nth-child"](c, "even");
5659 "nth" : function(c, a){
5660 return c[a-1] || [];
5663 "first" : function(c){
5667 "last" : function(c){
5668 return c[c.length-1] || [];
5671 "has" : function(c, ss){
5672 var s = Roo.DomQuery.select;
5673 var r = [], ri = -1;
5674 for(var i = 0, ci; ci = c[i]; i++){
5675 if(s(ss, ci).length > 0){
5682 "next" : function(c, ss){
5683 var is = Roo.DomQuery.is;
5684 var r = [], ri = -1;
5685 for(var i = 0, ci; ci = c[i]; i++){
5694 "prev" : function(c, ss){
5695 var is = Roo.DomQuery.is;
5696 var r = [], ri = -1;
5697 for(var i = 0, ci; ci = c[i]; i++){
5710 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5711 * @param {String} path The selector/xpath query
5712 * @param {Node} root (optional) The start of the query (defaults to document).
5717 Roo.query = Roo.DomQuery.select;
5720 * Ext JS Library 1.1.1
5721 * Copyright(c) 2006-2007, Ext JS, LLC.
5723 * Originally Released Under LGPL - original licence link has changed is not relivant.
5726 * <script type="text/javascript">
5730 * @class Roo.util.Observable
5731 * Base class that provides a common interface for publishing events. Subclasses are expected to
5732 * to have a property "events" with all the events defined.<br>
5735 Employee = function(name){
5742 Roo.extend(Employee, Roo.util.Observable);
5744 * @param {Object} config properties to use (incuding events / listeners)
5747 Roo.util.Observable = function(cfg){
5750 this.addEvents(cfg.events || {});
5752 delete cfg.events; // make sure
5755 Roo.apply(this, cfg);
5758 this.on(this.listeners);
5759 delete this.listeners;
5762 Roo.util.Observable.prototype = {
5764 * @cfg {Object} listeners list of events and functions to call for this object,
5768 'click' : function(e) {
5778 * Fires the specified event with the passed parameters (minus the event name).
5779 * @param {String} eventName
5780 * @param {Object...} args Variable number of parameters are passed to handlers
5781 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5783 fireEvent : function(){
5784 var ce = this.events[arguments[0].toLowerCase()];
5785 if(typeof ce == "object"){
5786 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5793 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5796 * Appends an event handler to this component
5797 * @param {String} eventName The type of event to listen for
5798 * @param {Function} handler The method the event invokes
5799 * @param {Object} scope (optional) The scope in which to execute the handler
5800 * function. The handler function's "this" context.
5801 * @param {Object} options (optional) An object containing handler configuration
5802 * properties. This may contain any of the following properties:<ul>
5803 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5804 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5805 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5806 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5807 * by the specified number of milliseconds. If the event fires again within that time, the original
5808 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5811 * <b>Combining Options</b><br>
5812 * Using the options argument, it is possible to combine different types of listeners:<br>
5814 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5816 el.on('click', this.onClick, this, {
5823 * <b>Attaching multiple handlers in 1 call</b><br>
5824 * The method also allows for a single argument to be passed which is a config object containing properties
5825 * which specify multiple handlers.
5834 fn: this.onMouseOver,
5838 fn: this.onMouseOut,
5844 * Or a shorthand syntax which passes the same scope object to all handlers:
5847 'click': this.onClick,
5848 'mouseover': this.onMouseOver,
5849 'mouseout': this.onMouseOut,
5854 addListener : function(eventName, fn, scope, o){
5855 if(typeof eventName == "object"){
5858 if(this.filterOptRe.test(e)){
5861 if(typeof o[e] == "function"){
5863 this.addListener(e, o[e], o.scope, o);
5865 // individual options
5866 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5871 o = (!o || typeof o == "boolean") ? {} : o;
5872 eventName = eventName.toLowerCase();
5873 var ce = this.events[eventName] || true;
5874 if(typeof ce == "boolean"){
5875 ce = new Roo.util.Event(this, eventName);
5876 this.events[eventName] = ce;
5878 ce.addListener(fn, scope, o);
5882 * Removes a listener
5883 * @param {String} eventName The type of event to listen for
5884 * @param {Function} handler The handler to remove
5885 * @param {Object} scope (optional) The scope (this object) for the handler
5887 removeListener : function(eventName, fn, scope){
5888 var ce = this.events[eventName.toLowerCase()];
5889 if(typeof ce == "object"){
5890 ce.removeListener(fn, scope);
5895 * Removes all listeners for this object
5897 purgeListeners : function(){
5898 for(var evt in this.events){
5899 if(typeof this.events[evt] == "object"){
5900 this.events[evt].clearListeners();
5905 relayEvents : function(o, events){
5906 var createHandler = function(ename){
5908 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5911 for(var i = 0, len = events.length; i < len; i++){
5912 var ename = events[i];
5913 if(!this.events[ename]){ this.events[ename] = true; };
5914 o.on(ename, createHandler(ename), this);
5919 * Used to define events on this Observable
5920 * @param {Object} object The object with the events defined
5922 addEvents : function(o){
5926 Roo.applyIf(this.events, o);
5930 * Checks to see if this object has any listeners for a specified event
5931 * @param {String} eventName The name of the event to check for
5932 * @return {Boolean} True if the event is being listened for, else false
5934 hasListener : function(eventName){
5935 var e = this.events[eventName];
5936 return typeof e == "object" && e.listeners.length > 0;
5940 * Appends an event handler to this element (shorthand for addListener)
5941 * @param {String} eventName The type of event to listen for
5942 * @param {Function} handler The method the event invokes
5943 * @param {Object} scope (optional) The scope in which to execute the handler
5944 * function. The handler function's "this" context.
5945 * @param {Object} options (optional)
5948 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5950 * Removes a listener (shorthand for removeListener)
5951 * @param {String} eventName The type of event to listen for
5952 * @param {Function} handler The handler to remove
5953 * @param {Object} scope (optional) The scope (this object) for the handler
5956 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5959 * Starts capture on the specified Observable. All events will be passed
5960 * to the supplied function with the event name + standard signature of the event
5961 * <b>before</b> the event is fired. If the supplied function returns false,
5962 * the event will not fire.
5963 * @param {Observable} o The Observable to capture
5964 * @param {Function} fn The function to call
5965 * @param {Object} scope (optional) The scope (this object) for the fn
5968 Roo.util.Observable.capture = function(o, fn, scope){
5969 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5973 * Removes <b>all</b> added captures from the Observable.
5974 * @param {Observable} o The Observable to release
5977 Roo.util.Observable.releaseCapture = function(o){
5978 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5983 var createBuffered = function(h, o, scope){
5984 var task = new Roo.util.DelayedTask();
5986 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5990 var createSingle = function(h, e, fn, scope){
5992 e.removeListener(fn, scope);
5993 return h.apply(scope, arguments);
5997 var createDelayed = function(h, o, scope){
5999 var args = Array.prototype.slice.call(arguments, 0);
6000 setTimeout(function(){
6001 h.apply(scope, args);
6006 Roo.util.Event = function(obj, name){
6009 this.listeners = [];
6012 Roo.util.Event.prototype = {
6013 addListener : function(fn, scope, options){
6014 var o = options || {};
6015 scope = scope || this.obj;
6016 if(!this.isListening(fn, scope)){
6017 var l = {fn: fn, scope: scope, options: o};
6020 h = createDelayed(h, o, scope);
6023 h = createSingle(h, this, fn, scope);
6026 h = createBuffered(h, o, scope);
6029 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6030 this.listeners.push(l);
6032 this.listeners = this.listeners.slice(0);
6033 this.listeners.push(l);
6038 findListener : function(fn, scope){
6039 scope = scope || this.obj;
6040 var ls = this.listeners;
6041 for(var i = 0, len = ls.length; i < len; i++){
6043 if(l.fn == fn && l.scope == scope){
6050 isListening : function(fn, scope){
6051 return this.findListener(fn, scope) != -1;
6054 removeListener : function(fn, scope){
6056 if((index = this.findListener(fn, scope)) != -1){
6058 this.listeners.splice(index, 1);
6060 this.listeners = this.listeners.slice(0);
6061 this.listeners.splice(index, 1);
6068 clearListeners : function(){
6069 this.listeners = [];
6073 var ls = this.listeners, scope, len = ls.length;
6076 var args = Array.prototype.slice.call(arguments, 0);
6077 for(var i = 0; i < len; i++){
6079 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6080 this.firing = false;
6084 this.firing = false;
6091 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6098 * @class Roo.Document
6099 * @extends Roo.util.Observable
6100 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6102 * @param {Object} config the methods and properties of the 'base' class for the application.
6104 * Generic Page handler - implement this to start your app..
6107 * MyProject = new Roo.Document({
6109 'load' : true // your events..
6112 'ready' : function() {
6113 // fired on Roo.onReady()
6118 Roo.Document = function(cfg) {
6123 Roo.util.Observable.call(this,cfg);
6127 Roo.onReady(function() {
6128 _this.fireEvent('ready');
6134 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6136 * Ext JS Library 1.1.1
6137 * Copyright(c) 2006-2007, Ext JS, LLC.
6139 * Originally Released Under LGPL - original licence link has changed is not relivant.
6142 * <script type="text/javascript">
6146 * @class Roo.EventManager
6147 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6148 * several useful events directly.
6149 * See {@link Roo.EventObject} for more details on normalized event objects.
6152 Roo.EventManager = function(){
6153 var docReadyEvent, docReadyProcId, docReadyState = false;
6154 var resizeEvent, resizeTask, textEvent, textSize;
6155 var E = Roo.lib.Event;
6156 var D = Roo.lib.Dom;
6161 var fireDocReady = function(){
6163 docReadyState = true;
6166 clearInterval(docReadyProcId);
6168 if(Roo.isGecko || Roo.isOpera) {
6169 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6172 var defer = document.getElementById("ie-deferred-loader");
6174 defer.onreadystatechange = null;
6175 defer.parentNode.removeChild(defer);
6179 docReadyEvent.fire();
6180 docReadyEvent.clearListeners();
6185 var initDocReady = function(){
6186 docReadyEvent = new Roo.util.Event();
6187 if(Roo.isGecko || Roo.isOpera) {
6188 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6190 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6191 var defer = document.getElementById("ie-deferred-loader");
6192 defer.onreadystatechange = function(){
6193 if(this.readyState == "complete"){
6197 }else if(Roo.isSafari){
6198 docReadyProcId = setInterval(function(){
6199 var rs = document.readyState;
6200 if(rs == "complete") {
6205 // no matter what, make sure it fires on load
6206 E.on(window, "load", fireDocReady);
6209 var createBuffered = function(h, o){
6210 var task = new Roo.util.DelayedTask(h);
6212 // create new event object impl so new events don't wipe out properties
6213 e = new Roo.EventObjectImpl(e);
6214 task.delay(o.buffer, h, null, [e]);
6218 var createSingle = function(h, el, ename, fn){
6220 Roo.EventManager.removeListener(el, ename, fn);
6225 var createDelayed = function(h, o){
6227 // create new event object impl so new events don't wipe out properties
6228 e = new Roo.EventObjectImpl(e);
6229 setTimeout(function(){
6234 var transitionEndVal = false;
6236 var transitionEnd = function()
6238 if (transitionEndVal) {
6239 return transitionEndVal;
6241 var el = document.createElement('div');
6243 var transEndEventNames = {
6244 WebkitTransition : 'webkitTransitionEnd',
6245 MozTransition : 'transitionend',
6246 OTransition : 'oTransitionEnd otransitionend',
6247 transition : 'transitionend'
6250 for (var name in transEndEventNames) {
6251 if (el.style[name] !== undefined) {
6252 transitionEndVal = transEndEventNames[name];
6253 return transitionEndVal ;
6259 var listen = function(element, ename, opt, fn, scope){
6260 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6261 fn = fn || o.fn; scope = scope || o.scope;
6262 var el = Roo.getDom(element);
6266 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6269 if (ename == 'transitionend') {
6270 ename = transitionEnd();
6272 var h = function(e){
6273 e = Roo.EventObject.setEvent(e);
6276 t = e.getTarget(o.delegate, el);
6283 if(o.stopEvent === true){
6286 if(o.preventDefault === true){
6289 if(o.stopPropagation === true){
6290 e.stopPropagation();
6293 if(o.normalized === false){
6297 fn.call(scope || el, e, t, o);
6300 h = createDelayed(h, o);
6303 h = createSingle(h, el, ename, fn);
6306 h = createBuffered(h, o);
6309 fn._handlers = fn._handlers || [];
6312 fn._handlers.push([Roo.id(el), ename, h]);
6317 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6318 el.addEventListener("DOMMouseScroll", h, false);
6319 E.on(window, 'unload', function(){
6320 el.removeEventListener("DOMMouseScroll", h, false);
6323 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6324 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6329 var stopListening = function(el, ename, fn){
6330 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6332 for(var i = 0, len = hds.length; i < len; i++){
6334 if(h[0] == id && h[1] == ename){
6341 E.un(el, ename, hd);
6342 el = Roo.getDom(el);
6343 if(ename == "mousewheel" && el.addEventListener){
6344 el.removeEventListener("DOMMouseScroll", hd, false);
6346 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6347 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6351 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6358 * @scope Roo.EventManager
6363 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6364 * object with a Roo.EventObject
6365 * @param {Function} fn The method the event invokes
6366 * @param {Object} scope An object that becomes the scope of the handler
6367 * @param {boolean} override If true, the obj passed in becomes
6368 * the execution scope of the listener
6369 * @return {Function} The wrapped function
6372 wrap : function(fn, scope, override){
6374 Roo.EventObject.setEvent(e);
6375 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6380 * Appends an event handler to an element (shorthand for addListener)
6381 * @param {String/HTMLElement} element The html element or id to assign the
6382 * @param {String} eventName The type of event to listen for
6383 * @param {Function} handler The method the event invokes
6384 * @param {Object} scope (optional) The scope in which to execute the handler
6385 * function. The handler function's "this" context.
6386 * @param {Object} options (optional) An object containing handler configuration
6387 * properties. This may contain any of the following properties:<ul>
6388 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6389 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6390 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6391 * <li>preventDefault {Boolean} True to prevent the default action</li>
6392 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6393 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6394 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6395 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6396 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6397 * by the specified number of milliseconds. If the event fires again within that time, the original
6398 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6401 * <b>Combining Options</b><br>
6402 * Using the options argument, it is possible to combine different types of listeners:<br>
6404 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6406 el.on('click', this.onClick, this, {
6413 * <b>Attaching multiple handlers in 1 call</b><br>
6414 * The method also allows for a single argument to be passed which is a config object containing properties
6415 * which specify multiple handlers.
6425 fn: this.onMouseOver
6434 * Or a shorthand syntax:<br>
6437 'click' : this.onClick,
6438 'mouseover' : this.onMouseOver,
6439 'mouseout' : this.onMouseOut
6443 addListener : function(element, eventName, fn, scope, options){
6444 if(typeof eventName == "object"){
6450 if(typeof o[e] == "function"){
6452 listen(element, e, o, o[e], o.scope);
6454 // individual options
6455 listen(element, e, o[e]);
6460 return listen(element, eventName, options, fn, scope);
6464 * Removes an event handler
6466 * @param {String/HTMLElement} element The id or html element to remove the
6468 * @param {String} eventName The type of event
6469 * @param {Function} fn
6470 * @return {Boolean} True if a listener was actually removed
6472 removeListener : function(element, eventName, fn){
6473 return stopListening(element, eventName, fn);
6477 * Fires when the document is ready (before onload and before images are loaded). Can be
6478 * accessed shorthanded Roo.onReady().
6479 * @param {Function} fn The method the event invokes
6480 * @param {Object} scope An object that becomes the scope of the handler
6481 * @param {boolean} options
6483 onDocumentReady : function(fn, scope, options){
6484 if(docReadyState){ // if it already fired
6485 docReadyEvent.addListener(fn, scope, options);
6486 docReadyEvent.fire();
6487 docReadyEvent.clearListeners();
6493 docReadyEvent.addListener(fn, scope, options);
6497 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} options
6502 onWindowResize : function(fn, scope, options){
6504 resizeEvent = new Roo.util.Event();
6505 resizeTask = new Roo.util.DelayedTask(function(){
6506 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6508 E.on(window, "resize", function(){
6510 resizeTask.delay(50);
6512 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6516 resizeEvent.addListener(fn, scope, options);
6520 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6521 * @param {Function} fn The method the event invokes
6522 * @param {Object} scope An object that becomes the scope of the handler
6523 * @param {boolean} options
6525 onTextResize : function(fn, scope, options){
6527 textEvent = new Roo.util.Event();
6528 var textEl = new Roo.Element(document.createElement('div'));
6529 textEl.dom.className = 'x-text-resize';
6530 textEl.dom.innerHTML = 'X';
6531 textEl.appendTo(document.body);
6532 textSize = textEl.dom.offsetHeight;
6533 setInterval(function(){
6534 if(textEl.dom.offsetHeight != textSize){
6535 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6537 }, this.textResizeInterval);
6539 textEvent.addListener(fn, scope, options);
6543 * Removes the passed window resize listener.
6544 * @param {Function} fn The method the event invokes
6545 * @param {Object} scope The scope of handler
6547 removeResizeListener : function(fn, scope){
6549 resizeEvent.removeListener(fn, scope);
6554 fireResize : function(){
6556 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6560 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6564 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6566 textResizeInterval : 50
6571 * @scopeAlias pub=Roo.EventManager
6575 * Appends an event handler to an element (shorthand for addListener)
6576 * @param {String/HTMLElement} element The html element or id to assign the
6577 * @param {String} eventName The type of event to listen for
6578 * @param {Function} handler The method the event invokes
6579 * @param {Object} scope (optional) The scope in which to execute the handler
6580 * function. The handler function's "this" context.
6581 * @param {Object} options (optional) An object containing handler configuration
6582 * properties. This may contain any of the following properties:<ul>
6583 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6584 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6585 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6586 * <li>preventDefault {Boolean} True to prevent the default action</li>
6587 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6588 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6589 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6590 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6591 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6592 * by the specified number of milliseconds. If the event fires again within that time, the original
6593 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6596 * <b>Combining Options</b><br>
6597 * Using the options argument, it is possible to combine different types of listeners:<br>
6599 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6601 el.on('click', this.onClick, this, {
6608 * <b>Attaching multiple handlers in 1 call</b><br>
6609 * The method also allows for a single argument to be passed which is a config object containing properties
6610 * which specify multiple handlers.
6620 fn: this.onMouseOver
6629 * Or a shorthand syntax:<br>
6632 'click' : this.onClick,
6633 'mouseover' : this.onMouseOver,
6634 'mouseout' : this.onMouseOut
6638 pub.on = pub.addListener;
6639 pub.un = pub.removeListener;
6641 pub.stoppedMouseDownEvent = new Roo.util.Event();
6645 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6646 * @param {Function} fn The method the event invokes
6647 * @param {Object} scope An object that becomes the scope of the handler
6648 * @param {boolean} override If true, the obj passed in becomes
6649 * the execution scope of the listener
6653 Roo.onReady = Roo.EventManager.onDocumentReady;
6655 Roo.onReady(function(){
6656 var bd = Roo.get(document.body);
6661 : Roo.isIE11 ? "roo-ie11"
6662 : Roo.isEdge ? "roo-edge"
6663 : Roo.isGecko ? "roo-gecko"
6664 : Roo.isOpera ? "roo-opera"
6665 : Roo.isSafari ? "roo-safari" : ""];
6668 cls.push("roo-mac");
6671 cls.push("roo-linux");
6674 cls.push("roo-ios");
6677 cls.push("roo-touch");
6679 if(Roo.isBorderBox){
6680 cls.push('roo-border-box');
6682 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6683 var p = bd.dom.parentNode;
6685 p.className += ' roo-strict';
6688 bd.addClass(cls.join(' '));
6692 * @class Roo.EventObject
6693 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6694 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6697 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6699 var target = e.getTarget();
6702 var myDiv = Roo.get("myDiv");
6703 myDiv.on("click", handleClick);
6705 Roo.EventManager.on("myDiv", 'click', handleClick);
6706 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6710 Roo.EventObject = function(){
6712 var E = Roo.lib.Event;
6714 // safari keypress events for special keys return bad keycodes
6717 63235 : 39, // right
6720 63276 : 33, // page up
6721 63277 : 34, // page down
6722 63272 : 46, // delete
6727 // normalize button clicks
6728 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6729 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6731 Roo.EventObjectImpl = function(e){
6733 this.setEvent(e.browserEvent || e);
6736 Roo.EventObjectImpl.prototype = {
6738 * Used to fix doc tools.
6739 * @scope Roo.EventObject.prototype
6745 /** The normal browser event */
6746 browserEvent : null,
6747 /** The button pressed in a mouse event */
6749 /** True if the shift key was down during the event */
6751 /** True if the control key was down during the event */
6753 /** True if the alt key was down during the event */
6812 setEvent : function(e){
6813 if(e == this || (e && e.browserEvent)){ // already wrapped
6816 this.browserEvent = e;
6818 // normalize buttons
6819 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6820 if(e.type == 'click' && this.button == -1){
6824 this.shiftKey = e.shiftKey;
6825 // mac metaKey behaves like ctrlKey
6826 this.ctrlKey = e.ctrlKey || e.metaKey;
6827 this.altKey = e.altKey;
6828 // in getKey these will be normalized for the mac
6829 this.keyCode = e.keyCode;
6830 // keyup warnings on firefox.
6831 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6832 // cache the target for the delayed and or buffered events
6833 this.target = E.getTarget(e);
6835 this.xy = E.getXY(e);
6838 this.shiftKey = false;
6839 this.ctrlKey = false;
6840 this.altKey = false;
6850 * Stop the event (preventDefault and stopPropagation)
6852 stopEvent : function(){
6853 if(this.browserEvent){
6854 if(this.browserEvent.type == 'mousedown'){
6855 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6857 E.stopEvent(this.browserEvent);
6862 * Prevents the browsers default handling of the event.
6864 preventDefault : function(){
6865 if(this.browserEvent){
6866 E.preventDefault(this.browserEvent);
6871 isNavKeyPress : function(){
6872 var k = this.keyCode;
6873 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6874 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6877 isSpecialKey : function(){
6878 var k = this.keyCode;
6879 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6880 (k == 16) || (k == 17) ||
6881 (k >= 18 && k <= 20) ||
6882 (k >= 33 && k <= 35) ||
6883 (k >= 36 && k <= 39) ||
6884 (k >= 44 && k <= 45);
6887 * Cancels bubbling of the event.
6889 stopPropagation : function(){
6890 if(this.browserEvent){
6891 if(this.type == 'mousedown'){
6892 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6894 E.stopPropagation(this.browserEvent);
6899 * Gets the key code for the event.
6902 getCharCode : function(){
6903 return this.charCode || this.keyCode;
6907 * Returns a normalized keyCode for the event.
6908 * @return {Number} The key code
6910 getKey : function(){
6911 var k = this.keyCode || this.charCode;
6912 return Roo.isSafari ? (safariKeys[k] || k) : k;
6916 * Gets the x coordinate of the event.
6919 getPageX : function(){
6924 * Gets the y coordinate of the event.
6927 getPageY : function(){
6932 * Gets the time of the event.
6935 getTime : function(){
6936 if(this.browserEvent){
6937 return E.getTime(this.browserEvent);
6943 * Gets the page coordinates of the event.
6944 * @return {Array} The xy values like [x, y]
6951 * Gets the target for the event.
6952 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6953 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6954 search as a number or element (defaults to 10 || document.body)
6955 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6956 * @return {HTMLelement}
6958 getTarget : function(selector, maxDepth, returnEl){
6959 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6962 * Gets the related target.
6963 * @return {HTMLElement}
6965 getRelatedTarget : function(){
6966 if(this.browserEvent){
6967 return E.getRelatedTarget(this.browserEvent);
6973 * Normalizes mouse wheel delta across browsers
6974 * @return {Number} The delta
6976 getWheelDelta : function(){
6977 var e = this.browserEvent;
6979 if(e.wheelDelta){ /* IE/Opera. */
6980 delta = e.wheelDelta/120;
6981 }else if(e.detail){ /* Mozilla case. */
6982 delta = -e.detail/3;
6988 * Returns true if the control, meta, shift or alt key was pressed during this event.
6991 hasModifier : function(){
6992 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6996 * Returns true if the target of this event equals el or is a child of el
6997 * @param {String/HTMLElement/Element} el
6998 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7001 within : function(el, related){
7002 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7003 return t && Roo.fly(el).contains(t);
7006 getPoint : function(){
7007 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7011 return new Roo.EventObjectImpl();
7016 * Ext JS Library 1.1.1
7017 * Copyright(c) 2006-2007, Ext JS, LLC.
7019 * Originally Released Under LGPL - original licence link has changed is not relivant.
7022 * <script type="text/javascript">
7026 // was in Composite Element!??!?!
7029 var D = Roo.lib.Dom;
7030 var E = Roo.lib.Event;
7031 var A = Roo.lib.Anim;
7033 // local style camelizing for speed
7035 var camelRe = /(-[a-z])/gi;
7036 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7037 var view = document.defaultView;
7040 * @class Roo.Element
7041 * Represents an Element in the DOM.<br><br>
7044 var el = Roo.get("my-div");
7047 var el = getEl("my-div");
7049 // or with a DOM element
7050 var el = Roo.get(myDivElement);
7052 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7053 * each call instead of constructing a new one.<br><br>
7054 * <b>Animations</b><br />
7055 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7056 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7058 Option Default Description
7059 --------- -------- ---------------------------------------------
7060 duration .35 The duration of the animation in seconds
7061 easing easeOut The YUI easing method
7062 callback none A function to execute when the anim completes
7063 scope this The scope (this) of the callback function
7065 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7066 * manipulate the animation. Here's an example:
7068 var el = Roo.get("my-div");
7073 // default animation
7074 el.setWidth(100, true);
7076 // animation with some options set
7083 // using the "anim" property to get the Anim object
7089 el.setWidth(100, opt);
7091 if(opt.anim.isAnimated()){
7095 * <b> Composite (Collections of) Elements</b><br />
7096 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7097 * @constructor Create a new Element directly.
7098 * @param {String/HTMLElement} element
7099 * @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).
7101 Roo.Element = function(element, forceNew){
7102 var dom = typeof element == "string" ?
7103 document.getElementById(element) : element;
7104 if(!dom){ // invalid id/element
7108 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7109 return Roo.Element.cache[id];
7119 * The DOM element ID
7122 this.id = id || Roo.id(dom);
7125 var El = Roo.Element;
7129 * The element's default display mode (defaults to "")
7132 originalDisplay : "",
7136 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7142 * Sets the element's visibility mode. When setVisible() is called it
7143 * will use this to determine whether to set the visibility or the display property.
7144 * @param visMode Element.VISIBILITY or Element.DISPLAY
7145 * @return {Roo.Element} this
7147 setVisibilityMode : function(visMode){
7148 this.visibilityMode = visMode;
7152 * Convenience method for setVisibilityMode(Element.DISPLAY)
7153 * @param {String} display (optional) What to set display to when visible
7154 * @return {Roo.Element} this
7156 enableDisplayMode : function(display){
7157 this.setVisibilityMode(El.DISPLAY);
7158 if(typeof display != "undefined") { this.originalDisplay = display; }
7163 * 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)
7164 * @param {String} selector The simple selector to test
7165 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7166 search as a number or element (defaults to 10 || document.body)
7167 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7168 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7170 findParent : function(simpleSelector, maxDepth, returnEl){
7171 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7172 maxDepth = maxDepth || 50;
7173 if(typeof maxDepth != "number"){
7174 stopEl = Roo.getDom(maxDepth);
7177 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7178 if(dq.is(p, simpleSelector)){
7179 return returnEl ? Roo.get(p) : p;
7189 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7190 * @param {String} selector The simple selector to test
7191 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7192 search as a number or element (defaults to 10 || document.body)
7193 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7194 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7196 findParentNode : function(simpleSelector, maxDepth, returnEl){
7197 var p = Roo.fly(this.dom.parentNode, '_internal');
7198 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7202 * Looks at the scrollable parent element
7204 findScrollableParent : function()
7206 var overflowRegex = /(auto|scroll)/;
7208 if(this.getStyle('position') === 'fixed'){
7209 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7212 var excludeStaticParent = this.getStyle('position') === "absolute";
7214 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7216 if (excludeStaticParent && parent.getStyle('position') === "static") {
7220 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7224 if(parent.dom.nodeName.toLowerCase() == 'body'){
7225 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7229 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7233 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7234 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7235 * @param {String} selector The simple selector to test
7236 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7237 search as a number or element (defaults to 10 || document.body)
7238 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7240 up : function(simpleSelector, maxDepth){
7241 return this.findParentNode(simpleSelector, maxDepth, true);
7247 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7248 * @param {String} selector The simple selector to test
7249 * @return {Boolean} True if this element matches the selector, else false
7251 is : function(simpleSelector){
7252 return Roo.DomQuery.is(this.dom, simpleSelector);
7256 * Perform animation on this element.
7257 * @param {Object} args The YUI animation control args
7258 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7259 * @param {Function} onComplete (optional) Function to call when animation completes
7260 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7261 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7262 * @return {Roo.Element} this
7264 animate : function(args, duration, onComplete, easing, animType){
7265 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7270 * @private Internal animation call
7272 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7273 animType = animType || 'run';
7275 var anim = Roo.lib.Anim[animType](
7277 (opt.duration || defaultDur) || .35,
7278 (opt.easing || defaultEase) || 'easeOut',
7280 Roo.callback(cb, this);
7281 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7289 // private legacy anim prep
7290 preanim : function(a, i){
7291 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7295 * Removes worthless text nodes
7296 * @param {Boolean} forceReclean (optional) By default the element
7297 * keeps track if it has been cleaned already so
7298 * you can call this over and over. However, if you update the element and
7299 * need to force a reclean, you can pass true.
7301 clean : function(forceReclean){
7302 if(this.isCleaned && forceReclean !== true){
7306 var d = this.dom, n = d.firstChild, ni = -1;
7308 var nx = n.nextSibling;
7309 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7316 this.isCleaned = true;
7321 calcOffsetsTo : function(el){
7324 var restorePos = false;
7325 if(el.getStyle('position') == 'static'){
7326 el.position('relative');
7331 while(op && op != d && op.tagName != 'HTML'){
7334 op = op.offsetParent;
7337 el.position('static');
7343 * Scrolls this element into view within the passed container.
7344 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7345 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7346 * @return {Roo.Element} this
7348 scrollIntoView : function(container, hscroll){
7349 var c = Roo.getDom(container) || document.body;
7352 var o = this.calcOffsetsTo(c),
7355 b = t+el.offsetHeight,
7356 r = l+el.offsetWidth;
7358 var ch = c.clientHeight;
7359 var ct = parseInt(c.scrollTop, 10);
7360 var cl = parseInt(c.scrollLeft, 10);
7362 var cr = cl + c.clientWidth;
7370 if(hscroll !== false){
7374 c.scrollLeft = r-c.clientWidth;
7381 scrollChildIntoView : function(child, hscroll){
7382 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7386 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7387 * the new height may not be available immediately.
7388 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7389 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7390 * @param {Function} onComplete (optional) Function to call when animation completes
7391 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7392 * @return {Roo.Element} this
7394 autoHeight : function(animate, duration, onComplete, easing){
7395 var oldHeight = this.getHeight();
7397 this.setHeight(1); // force clipping
7398 setTimeout(function(){
7399 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7401 this.setHeight(height);
7403 if(typeof onComplete == "function"){
7407 this.setHeight(oldHeight); // restore original height
7408 this.setHeight(height, animate, duration, function(){
7410 if(typeof onComplete == "function") { onComplete(); }
7411 }.createDelegate(this), easing);
7413 }.createDelegate(this), 0);
7418 * Returns true if this element is an ancestor of the passed element
7419 * @param {HTMLElement/String} el The element to check
7420 * @return {Boolean} True if this element is an ancestor of el, else false
7422 contains : function(el){
7423 if(!el){return false;}
7424 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7428 * Checks whether the element is currently visible using both visibility and display properties.
7429 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7430 * @return {Boolean} True if the element is currently visible, else false
7432 isVisible : function(deep) {
7433 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7434 if(deep !== true || !vis){
7437 var p = this.dom.parentNode;
7438 while(p && p.tagName.toLowerCase() != "body"){
7439 if(!Roo.fly(p, '_isVisible').isVisible()){
7448 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7449 * @param {String} selector The CSS selector
7450 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7451 * @return {CompositeElement/CompositeElementLite} The composite element
7453 select : function(selector, unique){
7454 return El.select(selector, unique, this.dom);
7458 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7459 * @param {String} selector The CSS selector
7460 * @return {Array} An array of the matched nodes
7462 query : function(selector, unique){
7463 return Roo.DomQuery.select(selector, this.dom);
7467 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7468 * @param {String} selector The CSS selector
7469 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7470 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7472 child : function(selector, returnDom){
7473 var n = Roo.DomQuery.selectNode(selector, this.dom);
7474 return returnDom ? n : Roo.get(n);
7478 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7479 * @param {String} selector The CSS selector
7480 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7481 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7483 down : function(selector, returnDom){
7484 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7485 return returnDom ? n : Roo.get(n);
7489 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7490 * @param {String} group The group the DD object is member of
7491 * @param {Object} config The DD config object
7492 * @param {Object} overrides An object containing methods to override/implement on the DD object
7493 * @return {Roo.dd.DD} The DD object
7495 initDD : function(group, config, overrides){
7496 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7497 return Roo.apply(dd, overrides);
7501 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7502 * @param {String} group The group the DDProxy object is member of
7503 * @param {Object} config The DDProxy config object
7504 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7505 * @return {Roo.dd.DDProxy} The DDProxy object
7507 initDDProxy : function(group, config, overrides){
7508 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7509 return Roo.apply(dd, overrides);
7513 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7514 * @param {String} group The group the DDTarget object is member of
7515 * @param {Object} config The DDTarget config object
7516 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7517 * @return {Roo.dd.DDTarget} The DDTarget object
7519 initDDTarget : function(group, config, overrides){
7520 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7521 return Roo.apply(dd, overrides);
7525 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7526 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7527 * @param {Boolean} visible Whether the element is visible
7528 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7529 * @return {Roo.Element} this
7531 setVisible : function(visible, animate){
7533 if(this.visibilityMode == El.DISPLAY){
7534 this.setDisplayed(visible);
7537 this.dom.style.visibility = visible ? "visible" : "hidden";
7540 // closure for composites
7542 var visMode = this.visibilityMode;
7544 this.setOpacity(.01);
7545 this.setVisible(true);
7547 this.anim({opacity: { to: (visible?1:0) }},
7548 this.preanim(arguments, 1),
7549 null, .35, 'easeIn', function(){
7551 if(visMode == El.DISPLAY){
7552 dom.style.display = "none";
7554 dom.style.visibility = "hidden";
7556 Roo.get(dom).setOpacity(1);
7564 * Returns true if display is not "none"
7567 isDisplayed : function() {
7568 return this.getStyle("display") != "none";
7572 * Toggles the element's visibility or display, depending on visibility mode.
7573 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7574 * @return {Roo.Element} this
7576 toggle : function(animate){
7577 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7582 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7583 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7584 * @return {Roo.Element} this
7586 setDisplayed : function(value) {
7587 if(typeof value == "boolean"){
7588 value = value ? this.originalDisplay : "none";
7590 this.setStyle("display", value);
7595 * Tries to focus the element. Any exceptions are caught and ignored.
7596 * @return {Roo.Element} this
7598 focus : function() {
7606 * Tries to blur the element. Any exceptions are caught and ignored.
7607 * @return {Roo.Element} this
7617 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7618 * @param {String/Array} className The CSS class to add, or an array of classes
7619 * @return {Roo.Element} this
7621 addClass : function(className){
7622 if(className instanceof Array){
7623 for(var i = 0, len = className.length; i < len; i++) {
7624 this.addClass(className[i]);
7627 if(className && !this.hasClass(className)){
7628 this.dom.className = this.dom.className + " " + className;
7635 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7636 * @param {String/Array} className The CSS class to add, or an array of classes
7637 * @return {Roo.Element} this
7639 radioClass : function(className){
7640 var siblings = this.dom.parentNode.childNodes;
7641 for(var i = 0; i < siblings.length; i++) {
7642 var s = siblings[i];
7643 if(s.nodeType == 1){
7644 Roo.get(s).removeClass(className);
7647 this.addClass(className);
7652 * Removes one or more CSS classes from the element.
7653 * @param {String/Array} className The CSS class to remove, or an array of classes
7654 * @return {Roo.Element} this
7656 removeClass : function(className){
7657 if(!className || !this.dom.className){
7660 if(className instanceof Array){
7661 for(var i = 0, len = className.length; i < len; i++) {
7662 this.removeClass(className[i]);
7665 if(this.hasClass(className)){
7666 var re = this.classReCache[className];
7668 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7669 this.classReCache[className] = re;
7671 this.dom.className =
7672 this.dom.className.replace(re, " ");
7682 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7683 * @param {String} className The CSS class to toggle
7684 * @return {Roo.Element} this
7686 toggleClass : function(className){
7687 if(this.hasClass(className)){
7688 this.removeClass(className);
7690 this.addClass(className);
7696 * Checks if the specified CSS class exists on this element's DOM node.
7697 * @param {String} className The CSS class to check for
7698 * @return {Boolean} True if the class exists, else false
7700 hasClass : function(className){
7701 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7705 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7706 * @param {String} oldClassName The CSS class to replace
7707 * @param {String} newClassName The replacement CSS class
7708 * @return {Roo.Element} this
7710 replaceClass : function(oldClassName, newClassName){
7711 this.removeClass(oldClassName);
7712 this.addClass(newClassName);
7717 * Returns an object with properties matching the styles requested.
7718 * For example, el.getStyles('color', 'font-size', 'width') might return
7719 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7720 * @param {String} style1 A style name
7721 * @param {String} style2 A style name
7722 * @param {String} etc.
7723 * @return {Object} The style object
7725 getStyles : function(){
7726 var a = arguments, len = a.length, r = {};
7727 for(var i = 0; i < len; i++){
7728 r[a[i]] = this.getStyle(a[i]);
7734 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7735 * @param {String} property The style property whose value is returned.
7736 * @return {String} The current value of the style property for this element.
7738 getStyle : function(){
7739 return view && view.getComputedStyle ?
7741 var el = this.dom, v, cs, camel;
7742 if(prop == 'float'){
7745 if(el.style && (v = el.style[prop])){
7748 if(cs = view.getComputedStyle(el, "")){
7749 if(!(camel = propCache[prop])){
7750 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7757 var el = this.dom, v, cs, camel;
7758 if(prop == 'opacity'){
7759 if(typeof el.style.filter == 'string'){
7760 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7762 var fv = parseFloat(m[1]);
7764 return fv ? fv / 100 : 0;
7769 }else if(prop == 'float'){
7770 prop = "styleFloat";
7772 if(!(camel = propCache[prop])){
7773 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7775 if(v = el.style[camel]){
7778 if(cs = el.currentStyle){
7786 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7787 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7788 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7789 * @return {Roo.Element} this
7791 setStyle : function(prop, value){
7792 if(typeof prop == "string"){
7794 if (prop == 'float') {
7795 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7800 if(!(camel = propCache[prop])){
7801 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7804 if(camel == 'opacity') {
7805 this.setOpacity(value);
7807 this.dom.style[camel] = value;
7810 for(var style in prop){
7811 if(typeof prop[style] != "function"){
7812 this.setStyle(style, prop[style]);
7820 * More flexible version of {@link #setStyle} for setting style properties.
7821 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7822 * a function which returns such a specification.
7823 * @return {Roo.Element} this
7825 applyStyles : function(style){
7826 Roo.DomHelper.applyStyles(this.dom, style);
7831 * 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).
7832 * @return {Number} The X position of the element
7835 return D.getX(this.dom);
7839 * 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).
7840 * @return {Number} The Y position of the element
7843 return D.getY(this.dom);
7847 * 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).
7848 * @return {Array} The XY position of the element
7851 return D.getXY(this.dom);
7855 * 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).
7856 * @param {Number} The X position of the element
7857 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7858 * @return {Roo.Element} this
7860 setX : function(x, animate){
7862 D.setX(this.dom, x);
7864 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7870 * 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).
7871 * @param {Number} The Y position of the element
7872 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7873 * @return {Roo.Element} this
7875 setY : function(y, animate){
7877 D.setY(this.dom, y);
7879 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7885 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7886 * @param {String} left The left CSS property value
7887 * @return {Roo.Element} this
7889 setLeft : function(left){
7890 this.setStyle("left", this.addUnits(left));
7895 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7896 * @param {String} top The top CSS property value
7897 * @return {Roo.Element} this
7899 setTop : function(top){
7900 this.setStyle("top", this.addUnits(top));
7905 * Sets the element's CSS right style.
7906 * @param {String} right The right CSS property value
7907 * @return {Roo.Element} this
7909 setRight : function(right){
7910 this.setStyle("right", this.addUnits(right));
7915 * Sets the element's CSS bottom style.
7916 * @param {String} bottom The bottom CSS property value
7917 * @return {Roo.Element} this
7919 setBottom : function(bottom){
7920 this.setStyle("bottom", this.addUnits(bottom));
7925 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7926 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7927 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7928 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7929 * @return {Roo.Element} this
7931 setXY : function(pos, animate){
7933 D.setXY(this.dom, pos);
7935 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7941 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7942 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7943 * @param {Number} x X value for new position (coordinates are page-based)
7944 * @param {Number} y Y value for new position (coordinates are page-based)
7945 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7946 * @return {Roo.Element} this
7948 setLocation : function(x, y, animate){
7949 this.setXY([x, y], this.preanim(arguments, 2));
7954 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7955 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 moveTo : function(x, y, animate){
7962 this.setXY([x, y], this.preanim(arguments, 2));
7967 * Returns the region of the given element.
7968 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7969 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7971 getRegion : function(){
7972 return D.getRegion(this.dom);
7976 * Returns the offset height of the element
7977 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7978 * @return {Number} The element's height
7980 getHeight : function(contentHeight){
7981 var h = this.dom.offsetHeight || 0;
7982 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7986 * Returns the offset width of the element
7987 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7988 * @return {Number} The element's width
7990 getWidth : function(contentWidth){
7991 var w = this.dom.offsetWidth || 0;
7992 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7996 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7997 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7998 * if a height has not been set using CSS.
8001 getComputedHeight : function(){
8002 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8004 h = parseInt(this.getStyle('height'), 10) || 0;
8005 if(!this.isBorderBox()){
8006 h += this.getFrameWidth('tb');
8013 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8014 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8015 * if a width has not been set using CSS.
8018 getComputedWidth : function(){
8019 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8021 w = parseInt(this.getStyle('width'), 10) || 0;
8022 if(!this.isBorderBox()){
8023 w += this.getFrameWidth('lr');
8030 * Returns the size of the element.
8031 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8032 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8034 getSize : function(contentSize){
8035 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8039 * Returns the width and height of the viewport.
8040 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8042 getViewSize : function(){
8043 var d = this.dom, doc = document, aw = 0, ah = 0;
8044 if(d == doc || d == doc.body){
8045 return {width : D.getViewWidth(), height: D.getViewHeight()};
8048 width : d.clientWidth,
8049 height: d.clientHeight
8055 * Returns the value of the "value" attribute
8056 * @param {Boolean} asNumber true to parse the value as a number
8057 * @return {String/Number}
8059 getValue : function(asNumber){
8060 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8064 adjustWidth : function(width){
8065 if(typeof width == "number"){
8066 if(this.autoBoxAdjust && !this.isBorderBox()){
8067 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8077 adjustHeight : function(height){
8078 if(typeof height == "number"){
8079 if(this.autoBoxAdjust && !this.isBorderBox()){
8080 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8090 * Set the width of the element
8091 * @param {Number} width The new width
8092 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8093 * @return {Roo.Element} this
8095 setWidth : function(width, animate){
8096 width = this.adjustWidth(width);
8098 this.dom.style.width = this.addUnits(width);
8100 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8106 * Set the height of the element
8107 * @param {Number} height The new height
8108 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8109 * @return {Roo.Element} this
8111 setHeight : function(height, animate){
8112 height = this.adjustHeight(height);
8114 this.dom.style.height = this.addUnits(height);
8116 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8122 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8123 * @param {Number} width The new width
8124 * @param {Number} height The new height
8125 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8126 * @return {Roo.Element} this
8128 setSize : function(width, height, animate){
8129 if(typeof width == "object"){ // in case of object from getSize()
8130 height = width.height; width = width.width;
8132 width = this.adjustWidth(width); height = this.adjustHeight(height);
8134 this.dom.style.width = this.addUnits(width);
8135 this.dom.style.height = this.addUnits(height);
8137 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8143 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8144 * @param {Number} x X value for new position (coordinates are page-based)
8145 * @param {Number} y Y value for new position (coordinates are page-based)
8146 * @param {Number} width The new width
8147 * @param {Number} height The new height
8148 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8149 * @return {Roo.Element} this
8151 setBounds : function(x, y, width, height, animate){
8153 this.setSize(width, height);
8154 this.setLocation(x, y);
8156 width = this.adjustWidth(width); height = this.adjustHeight(height);
8157 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8158 this.preanim(arguments, 4), 'motion');
8164 * 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.
8165 * @param {Roo.lib.Region} region The region to fill
8166 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8167 * @return {Roo.Element} this
8169 setRegion : function(region, animate){
8170 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8175 * Appends an event handler
8177 * @param {String} eventName The type of event to append
8178 * @param {Function} fn The method the event invokes
8179 * @param {Object} scope (optional) The scope (this object) of the fn
8180 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8182 addListener : function(eventName, fn, scope, options){
8184 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8189 * Removes an event handler from this element
8190 * @param {String} eventName the type of event to remove
8191 * @param {Function} fn the method the event invokes
8192 * @return {Roo.Element} this
8194 removeListener : function(eventName, fn){
8195 Roo.EventManager.removeListener(this.dom, eventName, fn);
8200 * Removes all previous added listeners from this element
8201 * @return {Roo.Element} this
8203 removeAllListeners : function(){
8204 E.purgeElement(this.dom);
8208 relayEvent : function(eventName, observable){
8209 this.on(eventName, function(e){
8210 observable.fireEvent(eventName, e);
8215 * Set the opacity of the element
8216 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8217 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8218 * @return {Roo.Element} this
8220 setOpacity : function(opacity, animate){
8222 var s = this.dom.style;
8225 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8226 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8228 s.opacity = opacity;
8231 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8237 * Gets the left X coordinate
8238 * @param {Boolean} local True to get the local css position instead of page coordinate
8241 getLeft : function(local){
8245 return parseInt(this.getStyle("left"), 10) || 0;
8250 * Gets the right X coordinate of the element (element X position + element width)
8251 * @param {Boolean} local True to get the local css position instead of page coordinate
8254 getRight : function(local){
8256 return this.getX() + this.getWidth();
8258 return (this.getLeft(true) + this.getWidth()) || 0;
8263 * Gets the top Y coordinate
8264 * @param {Boolean} local True to get the local css position instead of page coordinate
8267 getTop : function(local) {
8271 return parseInt(this.getStyle("top"), 10) || 0;
8276 * Gets the bottom Y coordinate of the element (element Y position + element height)
8277 * @param {Boolean} local True to get the local css position instead of page coordinate
8280 getBottom : function(local){
8282 return this.getY() + this.getHeight();
8284 return (this.getTop(true) + this.getHeight()) || 0;
8289 * Initializes positioning on this element. If a desired position is not passed, it will make the
8290 * the element positioned relative IF it is not already positioned.
8291 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8292 * @param {Number} zIndex (optional) The zIndex to apply
8293 * @param {Number} x (optional) Set the page X position
8294 * @param {Number} y (optional) Set the page Y position
8296 position : function(pos, zIndex, x, y){
8298 if(this.getStyle('position') == 'static'){
8299 this.setStyle('position', 'relative');
8302 this.setStyle("position", pos);
8305 this.setStyle("z-index", zIndex);
8307 if(x !== undefined && y !== undefined){
8309 }else if(x !== undefined){
8311 }else if(y !== undefined){
8317 * Clear positioning back to the default when the document was loaded
8318 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8319 * @return {Roo.Element} this
8321 clearPositioning : function(value){
8329 "position" : "static"
8335 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8336 * snapshot before performing an update and then restoring the element.
8339 getPositioning : function(){
8340 var l = this.getStyle("left");
8341 var t = this.getStyle("top");
8343 "position" : this.getStyle("position"),
8345 "right" : l ? "" : this.getStyle("right"),
8347 "bottom" : t ? "" : this.getStyle("bottom"),
8348 "z-index" : this.getStyle("z-index")
8353 * Gets the width of the border(s) for the specified side(s)
8354 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8355 * passing lr would get the border (l)eft width + the border (r)ight width.
8356 * @return {Number} The width of the sides passed added together
8358 getBorderWidth : function(side){
8359 return this.addStyles(side, El.borders);
8363 * Gets the width of the padding(s) for the specified side(s)
8364 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8365 * passing lr would get the padding (l)eft + the padding (r)ight.
8366 * @return {Number} The padding of the sides passed added together
8368 getPadding : function(side){
8369 return this.addStyles(side, El.paddings);
8373 * Set positioning with an object returned by getPositioning().
8374 * @param {Object} posCfg
8375 * @return {Roo.Element} this
8377 setPositioning : function(pc){
8378 this.applyStyles(pc);
8379 if(pc.right == "auto"){
8380 this.dom.style.right = "";
8382 if(pc.bottom == "auto"){
8383 this.dom.style.bottom = "";
8389 fixDisplay : function(){
8390 if(this.getStyle("display") == "none"){
8391 this.setStyle("visibility", "hidden");
8392 this.setStyle("display", this.originalDisplay); // first try reverting to default
8393 if(this.getStyle("display") == "none"){ // if that fails, default to block
8394 this.setStyle("display", "block");
8400 * Quick set left and top adding default units
8401 * @param {String} left The left CSS property value
8402 * @param {String} top The top CSS property value
8403 * @return {Roo.Element} this
8405 setLeftTop : function(left, top){
8406 this.dom.style.left = this.addUnits(left);
8407 this.dom.style.top = this.addUnits(top);
8412 * Move this element relative to its current position.
8413 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8414 * @param {Number} distance How far to move the element in pixels
8415 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8416 * @return {Roo.Element} this
8418 move : function(direction, distance, animate){
8419 var xy = this.getXY();
8420 direction = direction.toLowerCase();
8424 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8428 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8433 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8438 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8445 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8446 * @return {Roo.Element} this
8449 if(!this.isClipped){
8450 this.isClipped = true;
8451 this.originalClip = {
8452 "o": this.getStyle("overflow"),
8453 "x": this.getStyle("overflow-x"),
8454 "y": this.getStyle("overflow-y")
8456 this.setStyle("overflow", "hidden");
8457 this.setStyle("overflow-x", "hidden");
8458 this.setStyle("overflow-y", "hidden");
8464 * Return clipping (overflow) to original clipping before clip() was called
8465 * @return {Roo.Element} this
8467 unclip : function(){
8469 this.isClipped = false;
8470 var o = this.originalClip;
8471 if(o.o){this.setStyle("overflow", o.o);}
8472 if(o.x){this.setStyle("overflow-x", o.x);}
8473 if(o.y){this.setStyle("overflow-y", o.y);}
8480 * Gets the x,y coordinates specified by the anchor position on the element.
8481 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8482 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8483 * {width: (target width), height: (target height)} (defaults to the element's current size)
8484 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8485 * @return {Array} [x, y] An array containing the element's x and y coordinates
8487 getAnchorXY : function(anchor, local, s){
8488 //Passing a different size is useful for pre-calculating anchors,
8489 //especially for anchored animations that change the el size.
8491 var w, h, vp = false;
8494 if(d == document.body || d == document){
8496 w = D.getViewWidth(); h = D.getViewHeight();
8498 w = this.getWidth(); h = this.getHeight();
8501 w = s.width; h = s.height;
8503 var x = 0, y = 0, r = Math.round;
8504 switch((anchor || "tl").toLowerCase()){
8546 var sc = this.getScroll();
8547 return [x + sc.left, y + sc.top];
8549 //Add the element's offset xy
8550 var o = this.getXY();
8551 return [x+o[0], y+o[1]];
8555 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8556 * supported position values.
8557 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8558 * @param {String} position The position to align to.
8559 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8560 * @return {Array} [x, y]
8562 getAlignToXY : function(el, p, o){
8566 throw "Element.alignTo with an element that doesn't exist";
8568 var c = false; //constrain to viewport
8569 var p1 = "", p2 = "";
8576 }else if(p.indexOf("-") == -1){
8579 p = p.toLowerCase();
8580 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8582 throw "Element.alignTo with an invalid alignment " + p;
8584 p1 = m[1]; p2 = m[2]; c = !!m[3];
8586 //Subtract the aligned el's internal xy from the target's offset xy
8587 //plus custom offset to get the aligned el's new offset xy
8588 var a1 = this.getAnchorXY(p1, true);
8589 var a2 = el.getAnchorXY(p2, false);
8590 var x = a2[0] - a1[0] + o[0];
8591 var y = a2[1] - a1[1] + o[1];
8593 //constrain the aligned el to viewport if necessary
8594 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8595 // 5px of margin for ie
8596 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8598 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8599 //perpendicular to the vp border, allow the aligned el to slide on that border,
8600 //otherwise swap the aligned el to the opposite border of the target.
8601 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8602 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8603 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8604 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8607 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8608 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8610 if((x+w) > dw + scrollX){
8611 x = swapX ? r.left-w : dw+scrollX-w;
8614 x = swapX ? r.right : scrollX;
8616 if((y+h) > dh + scrollY){
8617 y = swapY ? r.top-h : dh+scrollY-h;
8620 y = swapY ? r.bottom : scrollY;
8627 getConstrainToXY : function(){
8628 var os = {top:0, left:0, bottom:0, right: 0};
8630 return function(el, local, offsets, proposedXY){
8632 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8634 var vw, vh, vx = 0, vy = 0;
8635 if(el.dom == document.body || el.dom == document){
8636 vw = Roo.lib.Dom.getViewWidth();
8637 vh = Roo.lib.Dom.getViewHeight();
8639 vw = el.dom.clientWidth;
8640 vh = el.dom.clientHeight;
8642 var vxy = el.getXY();
8648 var s = el.getScroll();
8650 vx += offsets.left + s.left;
8651 vy += offsets.top + s.top;
8653 vw -= offsets.right;
8654 vh -= offsets.bottom;
8659 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8660 var x = xy[0], y = xy[1];
8661 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8663 // only move it if it needs it
8666 // first validate right/bottom
8675 // then make sure top/left isn't negative
8684 return moved ? [x, y] : false;
8689 adjustForConstraints : function(xy, parent, offsets){
8690 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8694 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8695 * document it aligns it to the viewport.
8696 * The position parameter is optional, and can be specified in any one of the following formats:
8698 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8699 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8700 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8701 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8702 * <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
8703 * element's anchor point, and the second value is used as the target's anchor point.</li>
8705 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8706 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8707 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8708 * that specified in order to enforce the viewport constraints.
8709 * Following are all of the supported anchor positions:
8712 ----- -----------------------------
8713 tl The top left corner (default)
8714 t The center of the top edge
8715 tr The top right corner
8716 l The center of the left edge
8717 c In the center of the element
8718 r The center of the right edge
8719 bl The bottom left corner
8720 b The center of the bottom edge
8721 br The bottom right corner
8725 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8726 el.alignTo("other-el");
8728 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8729 el.alignTo("other-el", "tr?");
8731 // align the bottom right corner of el with the center left edge of other-el
8732 el.alignTo("other-el", "br-l?");
8734 // align the center of el with the bottom left corner of other-el and
8735 // adjust the x position by -6 pixels (and the y position by 0)
8736 el.alignTo("other-el", "c-bl", [-6, 0]);
8738 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8739 * @param {String} position The position to align to.
8740 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8741 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8742 * @return {Roo.Element} this
8744 alignTo : function(element, position, offsets, animate){
8745 var xy = this.getAlignToXY(element, position, offsets);
8746 this.setXY(xy, this.preanim(arguments, 3));
8751 * Anchors an element to another element and realigns it when the window is resized.
8752 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8753 * @param {String} position The position to align to.
8754 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8755 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8756 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8757 * is a number, it is used as the buffer delay (defaults to 50ms).
8758 * @param {Function} callback The function to call after the animation finishes
8759 * @return {Roo.Element} this
8761 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8762 var action = function(){
8763 this.alignTo(el, alignment, offsets, animate);
8764 Roo.callback(callback, this);
8766 Roo.EventManager.onWindowResize(action, this);
8767 var tm = typeof monitorScroll;
8768 if(tm != 'undefined'){
8769 Roo.EventManager.on(window, 'scroll', action, this,
8770 {buffer: tm == 'number' ? monitorScroll : 50});
8772 action.call(this); // align immediately
8776 * Clears any opacity settings from this element. Required in some cases for IE.
8777 * @return {Roo.Element} this
8779 clearOpacity : function(){
8780 if (window.ActiveXObject) {
8781 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8782 this.dom.style.filter = "";
8785 this.dom.style.opacity = "";
8786 this.dom.style["-moz-opacity"] = "";
8787 this.dom.style["-khtml-opacity"] = "";
8793 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8794 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8795 * @return {Roo.Element} this
8797 hide : function(animate){
8798 this.setVisible(false, this.preanim(arguments, 0));
8803 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8804 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8805 * @return {Roo.Element} this
8807 show : function(animate){
8808 this.setVisible(true, this.preanim(arguments, 0));
8813 * @private Test if size has a unit, otherwise appends the default
8815 addUnits : function(size){
8816 return Roo.Element.addUnits(size, this.defaultUnit);
8820 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8821 * @return {Roo.Element} this
8823 beginMeasure : function(){
8825 if(el.offsetWidth || el.offsetHeight){
8826 return this; // offsets work already
8829 var p = this.dom, b = document.body; // start with this element
8830 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8831 var pe = Roo.get(p);
8832 if(pe.getStyle('display') == 'none'){
8833 changed.push({el: p, visibility: pe.getStyle("visibility")});
8834 p.style.visibility = "hidden";
8835 p.style.display = "block";
8839 this._measureChanged = changed;
8845 * Restores displays to before beginMeasure was called
8846 * @return {Roo.Element} this
8848 endMeasure : function(){
8849 var changed = this._measureChanged;
8851 for(var i = 0, len = changed.length; i < len; i++) {
8853 r.el.style.visibility = r.visibility;
8854 r.el.style.display = "none";
8856 this._measureChanged = null;
8862 * Update the innerHTML of this element, optionally searching for and processing scripts
8863 * @param {String} html The new HTML
8864 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8865 * @param {Function} callback For async script loading you can be noticed when the update completes
8866 * @return {Roo.Element} this
8868 update : function(html, loadScripts, callback){
8869 if(typeof html == "undefined"){
8872 if(loadScripts !== true){
8873 this.dom.innerHTML = html;
8874 if(typeof callback == "function"){
8882 html += '<span id="' + id + '"></span>';
8884 E.onAvailable(id, function(){
8885 var hd = document.getElementsByTagName("head")[0];
8886 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8887 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8888 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8891 while(match = re.exec(html)){
8892 var attrs = match[1];
8893 var srcMatch = attrs ? attrs.match(srcRe) : false;
8894 if(srcMatch && srcMatch[2]){
8895 var s = document.createElement("script");
8896 s.src = srcMatch[2];
8897 var typeMatch = attrs.match(typeRe);
8898 if(typeMatch && typeMatch[2]){
8899 s.type = typeMatch[2];
8902 }else if(match[2] && match[2].length > 0){
8903 if(window.execScript) {
8904 window.execScript(match[2]);
8912 window.eval(match[2]);
8916 var el = document.getElementById(id);
8917 if(el){el.parentNode.removeChild(el);}
8918 if(typeof callback == "function"){
8922 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8927 * Direct access to the UpdateManager update() method (takes the same parameters).
8928 * @param {String/Function} url The url for this request or a function to call to get the url
8929 * @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}
8930 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8931 * @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.
8932 * @return {Roo.Element} this
8935 var um = this.getUpdateManager();
8936 um.update.apply(um, arguments);
8941 * Gets this element's UpdateManager
8942 * @return {Roo.UpdateManager} The UpdateManager
8944 getUpdateManager : function(){
8945 if(!this.updateManager){
8946 this.updateManager = new Roo.UpdateManager(this);
8948 return this.updateManager;
8952 * Disables text selection for this element (normalized across browsers)
8953 * @return {Roo.Element} this
8955 unselectable : function(){
8956 this.dom.unselectable = "on";
8957 this.swallowEvent("selectstart", true);
8958 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8959 this.addClass("x-unselectable");
8964 * Calculates the x, y to center this element on the screen
8965 * @return {Array} The x, y values [x, y]
8967 getCenterXY : function(){
8968 return this.getAlignToXY(document, 'c-c');
8972 * Centers the Element in either the viewport, or another Element.
8973 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8975 center : function(centerIn){
8976 this.alignTo(centerIn || document, 'c-c');
8981 * Tests various css rules/browsers to determine if this element uses a border box
8984 isBorderBox : function(){
8985 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8989 * Return a box {x, y, width, height} that can be used to set another elements
8990 * size/location to match this element.
8991 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8992 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8993 * @return {Object} box An object in the format {x, y, width, height}
8995 getBox : function(contentBox, local){
9000 var left = parseInt(this.getStyle("left"), 10) || 0;
9001 var top = parseInt(this.getStyle("top"), 10) || 0;
9004 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9006 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9008 var l = this.getBorderWidth("l")+this.getPadding("l");
9009 var r = this.getBorderWidth("r")+this.getPadding("r");
9010 var t = this.getBorderWidth("t")+this.getPadding("t");
9011 var b = this.getBorderWidth("b")+this.getPadding("b");
9012 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)};
9014 bx.right = bx.x + bx.width;
9015 bx.bottom = bx.y + bx.height;
9020 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9021 for more information about the sides.
9022 * @param {String} sides
9025 getFrameWidth : function(sides, onlyContentBox){
9026 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9030 * 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.
9031 * @param {Object} box The box to fill {x, y, width, height}
9032 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9033 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9034 * @return {Roo.Element} this
9036 setBox : function(box, adjust, animate){
9037 var w = box.width, h = box.height;
9038 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9039 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9040 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9042 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9047 * Forces the browser to repaint this element
9048 * @return {Roo.Element} this
9050 repaint : function(){
9052 this.addClass("x-repaint");
9053 setTimeout(function(){
9054 Roo.get(dom).removeClass("x-repaint");
9060 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9061 * then it returns the calculated width of the sides (see getPadding)
9062 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9063 * @return {Object/Number}
9065 getMargins : function(side){
9068 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9069 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9070 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9071 right: parseInt(this.getStyle("margin-right"), 10) || 0
9074 return this.addStyles(side, El.margins);
9079 addStyles : function(sides, styles){
9081 for(var i = 0, len = sides.length; i < len; i++){
9082 v = this.getStyle(styles[sides.charAt(i)]);
9084 w = parseInt(v, 10);
9092 * Creates a proxy element of this element
9093 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9094 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9095 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9096 * @return {Roo.Element} The new proxy element
9098 createProxy : function(config, renderTo, matchBox){
9100 renderTo = Roo.getDom(renderTo);
9102 renderTo = document.body;
9104 config = typeof config == "object" ?
9105 config : {tag : "div", cls: config};
9106 var proxy = Roo.DomHelper.append(renderTo, config, true);
9108 proxy.setBox(this.getBox());
9114 * Puts a mask over this element to disable user interaction. Requires core.css.
9115 * This method can only be applied to elements which accept child nodes.
9116 * @param {String} msg (optional) A message to display in the mask
9117 * @param {String} msgCls (optional) A css class to apply to the msg element
9118 * @return {Element} The mask element
9120 mask : function(msg, msgCls)
9122 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9123 this.setStyle("position", "relative");
9126 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9128 this.addClass("x-masked");
9129 this._mask.setDisplayed(true);
9134 while (dom && dom.style) {
9135 if (!isNaN(parseInt(dom.style.zIndex))) {
9136 z = Math.max(z, parseInt(dom.style.zIndex));
9138 dom = dom.parentNode;
9140 // if we are masking the body - then it hides everything..
9141 if (this.dom == document.body) {
9143 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9144 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9147 if(typeof msg == 'string'){
9149 this._maskMsg = Roo.DomHelper.append(this.dom, {
9150 cls: "roo-el-mask-msg",
9154 cls: 'fa fa-spinner fa-spin'
9162 var mm = this._maskMsg;
9163 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9164 if (mm.dom.lastChild) { // weird IE issue?
9165 mm.dom.lastChild.innerHTML = msg;
9167 mm.setDisplayed(true);
9169 mm.setStyle('z-index', z + 102);
9171 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9172 this._mask.setHeight(this.getHeight());
9174 this._mask.setStyle('z-index', z + 100);
9180 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9181 * it is cached for reuse.
9183 unmask : function(removeEl){
9185 if(removeEl === true){
9186 this._mask.remove();
9189 this._maskMsg.remove();
9190 delete this._maskMsg;
9193 this._mask.setDisplayed(false);
9195 this._maskMsg.setDisplayed(false);
9199 this.removeClass("x-masked");
9203 * Returns true if this element is masked
9206 isMasked : function(){
9207 return this._mask && this._mask.isVisible();
9211 * Creates an iframe shim for this element to keep selects and other windowed objects from
9213 * @return {Roo.Element} The new shim element
9215 createShim : function(){
9216 var el = document.createElement('iframe');
9217 el.frameBorder = 'no';
9218 el.className = 'roo-shim';
9219 if(Roo.isIE && Roo.isSecure){
9220 el.src = Roo.SSL_SECURE_URL;
9222 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9223 shim.autoBoxAdjust = false;
9228 * Removes this element from the DOM and deletes it from the cache
9230 remove : function(){
9231 if(this.dom.parentNode){
9232 this.dom.parentNode.removeChild(this.dom);
9234 delete El.cache[this.dom.id];
9238 * Sets up event handlers to add and remove a css class when the mouse is over this element
9239 * @param {String} className
9240 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9241 * mouseout events for children elements
9242 * @return {Roo.Element} this
9244 addClassOnOver : function(className, preventFlicker){
9245 this.on("mouseover", function(){
9246 Roo.fly(this, '_internal').addClass(className);
9248 var removeFn = function(e){
9249 if(preventFlicker !== true || !e.within(this, true)){
9250 Roo.fly(this, '_internal').removeClass(className);
9253 this.on("mouseout", removeFn, this.dom);
9258 * Sets up event handlers to add and remove a css class when this element has the focus
9259 * @param {String} className
9260 * @return {Roo.Element} this
9262 addClassOnFocus : function(className){
9263 this.on("focus", function(){
9264 Roo.fly(this, '_internal').addClass(className);
9266 this.on("blur", function(){
9267 Roo.fly(this, '_internal').removeClass(className);
9272 * 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)
9273 * @param {String} className
9274 * @return {Roo.Element} this
9276 addClassOnClick : function(className){
9278 this.on("mousedown", function(){
9279 Roo.fly(dom, '_internal').addClass(className);
9280 var d = Roo.get(document);
9281 var fn = function(){
9282 Roo.fly(dom, '_internal').removeClass(className);
9283 d.removeListener("mouseup", fn);
9285 d.on("mouseup", fn);
9291 * Stops the specified event from bubbling and optionally prevents the default action
9292 * @param {String} eventName
9293 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9294 * @return {Roo.Element} this
9296 swallowEvent : function(eventName, preventDefault){
9297 var fn = function(e){
9298 e.stopPropagation();
9303 if(eventName instanceof Array){
9304 for(var i = 0, len = eventName.length; i < len; i++){
9305 this.on(eventName[i], fn);
9309 this.on(eventName, fn);
9316 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9319 * Sizes this element to its parent element's dimensions performing
9320 * neccessary box adjustments.
9321 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9322 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9323 * @return {Roo.Element} this
9325 fitToParent : function(monitorResize, targetParent) {
9326 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9327 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9328 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9331 var p = Roo.get(targetParent || this.dom.parentNode);
9332 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9333 if (monitorResize === true) {
9334 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9335 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9341 * Gets the next sibling, skipping text nodes
9342 * @return {HTMLElement} The next sibling or null
9344 getNextSibling : function(){
9345 var n = this.dom.nextSibling;
9346 while(n && n.nodeType != 1){
9353 * Gets the previous sibling, skipping text nodes
9354 * @return {HTMLElement} The previous sibling or null
9356 getPrevSibling : function(){
9357 var n = this.dom.previousSibling;
9358 while(n && n.nodeType != 1){
9359 n = n.previousSibling;
9366 * Appends the passed element(s) to this element
9367 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9368 * @return {Roo.Element} this
9370 appendChild: function(el){
9377 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9378 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9379 * automatically generated with the specified attributes.
9380 * @param {HTMLElement} insertBefore (optional) a child element of this element
9381 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9382 * @return {Roo.Element} The new child element
9384 createChild: function(config, insertBefore, returnDom){
9385 config = config || {tag:'div'};
9387 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9389 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9393 * Appends this element to the passed element
9394 * @param {String/HTMLElement/Element} el The new parent element
9395 * @return {Roo.Element} this
9397 appendTo: function(el){
9398 el = Roo.getDom(el);
9399 el.appendChild(this.dom);
9404 * Inserts this element before the passed element in the DOM
9405 * @param {String/HTMLElement/Element} el The element to insert before
9406 * @return {Roo.Element} this
9408 insertBefore: function(el){
9409 el = Roo.getDom(el);
9410 el.parentNode.insertBefore(this.dom, el);
9415 * Inserts this element after the passed element in the DOM
9416 * @param {String/HTMLElement/Element} el The element to insert after
9417 * @return {Roo.Element} this
9419 insertAfter: function(el){
9420 el = Roo.getDom(el);
9421 el.parentNode.insertBefore(this.dom, el.nextSibling);
9426 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9427 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9428 * @return {Roo.Element} The new child
9430 insertFirst: function(el, returnDom){
9432 if(typeof el == 'object' && !el.nodeType){ // dh config
9433 return this.createChild(el, this.dom.firstChild, returnDom);
9435 el = Roo.getDom(el);
9436 this.dom.insertBefore(el, this.dom.firstChild);
9437 return !returnDom ? Roo.get(el) : el;
9442 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9443 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9444 * @param {String} where (optional) 'before' or 'after' defaults to before
9445 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9446 * @return {Roo.Element} the inserted Element
9448 insertSibling: function(el, where, returnDom){
9449 where = where ? where.toLowerCase() : 'before';
9451 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9453 if(typeof el == 'object' && !el.nodeType){ // dh config
9454 if(where == 'after' && !this.dom.nextSibling){
9455 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9457 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9461 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9462 where == 'before' ? this.dom : this.dom.nextSibling);
9471 * Creates and wraps this element with another element
9472 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9473 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9474 * @return {HTMLElement/Element} The newly created wrapper element
9476 wrap: function(config, returnDom){
9478 config = {tag: "div"};
9480 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9481 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9486 * Replaces the passed element with this element
9487 * @param {String/HTMLElement/Element} el The element to replace
9488 * @return {Roo.Element} this
9490 replace: function(el){
9492 this.insertBefore(el);
9498 * Inserts an html fragment into this element
9499 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9500 * @param {String} html The HTML fragment
9501 * @param {Boolean} returnEl True to return an Roo.Element
9502 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9504 insertHtml : function(where, html, returnEl){
9505 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9506 return returnEl ? Roo.get(el) : el;
9510 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9511 * @param {Object} o The object with the attributes
9512 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9513 * @return {Roo.Element} this
9515 set : function(o, useSet){
9517 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9519 if(attr == "style" || typeof o[attr] == "function") { continue; }
9521 el.className = o["cls"];
9524 el.setAttribute(attr, o[attr]);
9531 Roo.DomHelper.applyStyles(el, o.style);
9537 * Convenience method for constructing a KeyMap
9538 * @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:
9539 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9540 * @param {Function} fn The function to call
9541 * @param {Object} scope (optional) The scope of the function
9542 * @return {Roo.KeyMap} The KeyMap created
9544 addKeyListener : function(key, fn, scope){
9546 if(typeof key != "object" || key instanceof Array){
9562 return new Roo.KeyMap(this, config);
9566 * Creates a KeyMap for this element
9567 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9568 * @return {Roo.KeyMap} The KeyMap created
9570 addKeyMap : function(config){
9571 return new Roo.KeyMap(this, config);
9575 * Returns true if this element is scrollable.
9578 isScrollable : function(){
9580 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9584 * 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().
9585 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9586 * @param {Number} value The new scroll value
9587 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9588 * @return {Element} this
9591 scrollTo : function(side, value, animate){
9592 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9594 this.dom[prop] = value;
9596 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9597 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9603 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9604 * within this element's scrollable range.
9605 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9606 * @param {Number} distance How far to scroll the element in pixels
9607 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9608 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9609 * was scrolled as far as it could go.
9611 scroll : function(direction, distance, animate){
9612 if(!this.isScrollable()){
9616 var l = el.scrollLeft, t = el.scrollTop;
9617 var w = el.scrollWidth, h = el.scrollHeight;
9618 var cw = el.clientWidth, ch = el.clientHeight;
9619 direction = direction.toLowerCase();
9620 var scrolled = false;
9621 var a = this.preanim(arguments, 2);
9626 var v = Math.min(l + distance, w-cw);
9627 this.scrollTo("left", v, a);
9634 var v = Math.max(l - distance, 0);
9635 this.scrollTo("left", v, a);
9643 var v = Math.max(t - distance, 0);
9644 this.scrollTo("top", v, a);
9652 var v = Math.min(t + distance, h-ch);
9653 this.scrollTo("top", v, a);
9662 * Translates the passed page coordinates into left/top css values for this element
9663 * @param {Number/Array} x The page x or an array containing [x, y]
9664 * @param {Number} y The page y
9665 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9667 translatePoints : function(x, y){
9668 if(typeof x == 'object' || x instanceof Array){
9671 var p = this.getStyle('position');
9672 var o = this.getXY();
9674 var l = parseInt(this.getStyle('left'), 10);
9675 var t = parseInt(this.getStyle('top'), 10);
9678 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9681 t = (p == "relative") ? 0 : this.dom.offsetTop;
9684 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9688 * Returns the current scroll position of the element.
9689 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9691 getScroll : function(){
9692 var d = this.dom, doc = document;
9693 if(d == doc || d == doc.body){
9694 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9695 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9696 return {left: l, top: t};
9698 return {left: d.scrollLeft, top: d.scrollTop};
9703 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9704 * are convert to standard 6 digit hex color.
9705 * @param {String} attr The css attribute
9706 * @param {String} defaultValue The default value to use when a valid color isn't found
9707 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9710 getColor : function(attr, defaultValue, prefix){
9711 var v = this.getStyle(attr);
9712 if(!v || v == "transparent" || v == "inherit") {
9713 return defaultValue;
9715 var color = typeof prefix == "undefined" ? "#" : prefix;
9716 if(v.substr(0, 4) == "rgb("){
9717 var rvs = v.slice(4, v.length -1).split(",");
9718 for(var i = 0; i < 3; i++){
9719 var h = parseInt(rvs[i]).toString(16);
9726 if(v.substr(0, 1) == "#"){
9728 for(var i = 1; i < 4; i++){
9729 var c = v.charAt(i);
9732 }else if(v.length == 7){
9733 color += v.substr(1);
9737 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9741 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9742 * gradient background, rounded corners and a 4-way shadow.
9743 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9744 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9745 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9746 * @return {Roo.Element} this
9748 boxWrap : function(cls){
9749 cls = cls || 'x-box';
9750 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9751 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9756 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9757 * @param {String} namespace The namespace in which to look for the attribute
9758 * @param {String} name The attribute name
9759 * @return {String} The attribute value
9761 getAttributeNS : Roo.isIE ? function(ns, name){
9763 var type = typeof d[ns+":"+name];
9764 if(type != 'undefined' && type != 'unknown'){
9765 return d[ns+":"+name];
9768 } : function(ns, name){
9770 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9775 * Sets or Returns the value the dom attribute value
9776 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9777 * @param {String} value (optional) The value to set the attribute to
9778 * @return {String} The attribute value
9780 attr : function(name){
9781 if (arguments.length > 1) {
9782 this.dom.setAttribute(name, arguments[1]);
9783 return arguments[1];
9785 if (typeof(name) == 'object') {
9786 for(var i in name) {
9787 this.attr(i, name[i]);
9793 if (!this.dom.hasAttribute(name)) {
9796 return this.dom.getAttribute(name);
9803 var ep = El.prototype;
9806 * Appends an event handler (Shorthand for addListener)
9807 * @param {String} eventName The type of event to append
9808 * @param {Function} fn The method the event invokes
9809 * @param {Object} scope (optional) The scope (this object) of the fn
9810 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9813 ep.on = ep.addListener;
9815 ep.mon = ep.addListener;
9818 * Removes an event handler from this element (shorthand for removeListener)
9819 * @param {String} eventName the type of event to remove
9820 * @param {Function} fn the method the event invokes
9821 * @return {Roo.Element} this
9824 ep.un = ep.removeListener;
9827 * true to automatically adjust width and height settings for box-model issues (default to true)
9829 ep.autoBoxAdjust = true;
9832 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9835 El.addUnits = function(v, defaultUnit){
9836 if(v === "" || v == "auto"){
9839 if(v === undefined){
9842 if(typeof v == "number" || !El.unitPattern.test(v)){
9843 return v + (defaultUnit || 'px');
9848 // special markup used throughout Roo when box wrapping elements
9849 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>';
9851 * Visibility mode constant - Use visibility to hide element
9857 * Visibility mode constant - Use display to hide element
9863 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9864 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9865 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9877 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9878 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9879 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9880 * @return {Element} The Element object
9883 El.get = function(el){
9885 if(!el){ return null; }
9886 if(typeof el == "string"){ // element id
9887 if(!(elm = document.getElementById(el))){
9890 if(ex = El.cache[el]){
9893 ex = El.cache[el] = new El(elm);
9896 }else if(el.tagName){ // dom element
9900 if(ex = El.cache[id]){
9903 ex = El.cache[id] = new El(el);
9906 }else if(el instanceof El){
9908 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9909 // catch case where it hasn't been appended
9910 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9913 }else if(el.isComposite){
9915 }else if(el instanceof Array){
9916 return El.select(el);
9917 }else if(el == document){
9918 // create a bogus element object representing the document object
9920 var f = function(){};
9921 f.prototype = El.prototype;
9923 docEl.dom = document;
9931 El.uncache = function(el){
9932 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9934 delete El.cache[a[i].id || a[i]];
9940 // Garbage collection - uncache elements/purge listeners on orphaned elements
9941 // so we don't hold a reference and cause the browser to retain them
9942 El.garbageCollect = function(){
9943 if(!Roo.enableGarbageCollector){
9944 clearInterval(El.collectorThread);
9947 for(var eid in El.cache){
9948 var el = El.cache[eid], d = el.dom;
9949 // -------------------------------------------------------
9950 // Determining what is garbage:
9951 // -------------------------------------------------------
9953 // dom node is null, definitely garbage
9954 // -------------------------------------------------------
9956 // no parentNode == direct orphan, definitely garbage
9957 // -------------------------------------------------------
9958 // !d.offsetParent && !document.getElementById(eid)
9959 // display none elements have no offsetParent so we will
9960 // also try to look it up by it's id. However, check
9961 // offsetParent first so we don't do unneeded lookups.
9962 // This enables collection of elements that are not orphans
9963 // directly, but somewhere up the line they have an orphan
9965 // -------------------------------------------------------
9966 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9967 delete El.cache[eid];
9968 if(d && Roo.enableListenerCollection){
9974 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9978 El.Flyweight = function(dom){
9981 El.Flyweight.prototype = El.prototype;
9983 El._flyweights = {};
9985 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9986 * the dom node can be overwritten by other code.
9987 * @param {String/HTMLElement} el The dom node or id
9988 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9989 * prevent conflicts (e.g. internally Roo uses "_internal")
9991 * @return {Element} The shared Element object
9993 El.fly = function(el, named){
9994 named = named || '_global';
9995 el = Roo.getDom(el);
9999 if(!El._flyweights[named]){
10000 El._flyweights[named] = new El.Flyweight();
10002 El._flyweights[named].dom = el;
10003 return El._flyweights[named];
10007 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10008 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10009 * Shorthand of {@link Roo.Element#get}
10010 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10011 * @return {Element} The Element object
10017 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10018 * the dom node can be overwritten by other code.
10019 * Shorthand of {@link Roo.Element#fly}
10020 * @param {String/HTMLElement} el The dom node or id
10021 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10022 * prevent conflicts (e.g. internally Roo uses "_internal")
10024 * @return {Element} The shared Element object
10030 // speedy lookup for elements never to box adjust
10031 var noBoxAdjust = Roo.isStrict ? {
10034 input:1, select:1, textarea:1
10036 if(Roo.isIE || Roo.isGecko){
10037 noBoxAdjust['button'] = 1;
10041 Roo.EventManager.on(window, 'unload', function(){
10043 delete El._flyweights;
10051 Roo.Element.selectorFunction = Roo.DomQuery.select;
10054 Roo.Element.select = function(selector, unique, root){
10056 if(typeof selector == "string"){
10057 els = Roo.Element.selectorFunction(selector, root);
10058 }else if(selector.length !== undefined){
10061 throw "Invalid selector";
10063 if(unique === true){
10064 return new Roo.CompositeElement(els);
10066 return new Roo.CompositeElementLite(els);
10070 * Selects elements based on the passed CSS selector to enable working on them as 1.
10071 * @param {String/Array} selector The CSS selector or an array of elements
10072 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10073 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10074 * @return {CompositeElementLite/CompositeElement}
10078 Roo.select = Roo.Element.select;
10095 * Ext JS Library 1.1.1
10096 * Copyright(c) 2006-2007, Ext JS, LLC.
10098 * Originally Released Under LGPL - original licence link has changed is not relivant.
10101 * <script type="text/javascript">
10106 //Notifies Element that fx methods are available
10107 Roo.enableFx = true;
10111 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10112 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10113 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10114 * Element effects to work.</p><br/>
10116 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10117 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10118 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10119 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10120 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10121 * expected results and should be done with care.</p><br/>
10123 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10124 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10127 ----- -----------------------------
10128 tl The top left corner
10129 t The center of the top edge
10130 tr The top right corner
10131 l The center of the left edge
10132 r The center of the right edge
10133 bl The bottom left corner
10134 b The center of the bottom edge
10135 br The bottom right corner
10137 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10138 * below are common options that can be passed to any Fx method.</b>
10139 * @cfg {Function} callback A function called when the effect is finished
10140 * @cfg {Object} scope The scope of the effect function
10141 * @cfg {String} easing A valid Easing value for the effect
10142 * @cfg {String} afterCls A css class to apply after the effect
10143 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10144 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10145 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10146 * effects that end with the element being visually hidden, ignored otherwise)
10147 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10148 * a function which returns such a specification that will be applied to the Element after the effect finishes
10149 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10150 * @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
10151 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10155 * Slides the element into view. An anchor point can be optionally passed to set the point of
10156 * origin for the slide effect. This function automatically handles wrapping the element with
10157 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10160 // default: slide the element in from the top
10163 // custom: slide the element in from the right with a 2-second duration
10164 el.slideIn('r', { duration: 2 });
10166 // common config options shown with default values
10172 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10173 * @param {Object} options (optional) Object literal with any of the Fx config options
10174 * @return {Roo.Element} The Element
10176 slideIn : function(anchor, o){
10177 var el = this.getFxEl();
10180 el.queueFx(o, function(){
10182 anchor = anchor || "t";
10184 // fix display to visibility
10187 // restore values after effect
10188 var r = this.getFxRestore();
10189 var b = this.getBox();
10190 // fixed size for slide
10194 var wrap = this.fxWrap(r.pos, o, "hidden");
10196 var st = this.dom.style;
10197 st.visibility = "visible";
10198 st.position = "absolute";
10200 // clear out temp styles after slide and unwrap
10201 var after = function(){
10202 el.fxUnwrap(wrap, r.pos, o);
10203 st.width = r.width;
10204 st.height = r.height;
10207 // time to calc the positions
10208 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10210 switch(anchor.toLowerCase()){
10212 wrap.setSize(b.width, 0);
10213 st.left = st.bottom = "0";
10217 wrap.setSize(0, b.height);
10218 st.right = st.top = "0";
10222 wrap.setSize(0, b.height);
10223 wrap.setX(b.right);
10224 st.left = st.top = "0";
10225 a = {width: bw, points: pt};
10228 wrap.setSize(b.width, 0);
10229 wrap.setY(b.bottom);
10230 st.left = st.top = "0";
10231 a = {height: bh, points: pt};
10234 wrap.setSize(0, 0);
10235 st.right = st.bottom = "0";
10236 a = {width: bw, height: bh};
10239 wrap.setSize(0, 0);
10240 wrap.setY(b.y+b.height);
10241 st.right = st.top = "0";
10242 a = {width: bw, height: bh, points: pt};
10245 wrap.setSize(0, 0);
10246 wrap.setXY([b.right, b.bottom]);
10247 st.left = st.top = "0";
10248 a = {width: bw, height: bh, points: pt};
10251 wrap.setSize(0, 0);
10252 wrap.setX(b.x+b.width);
10253 st.left = st.bottom = "0";
10254 a = {width: bw, height: bh, points: pt};
10257 this.dom.style.visibility = "visible";
10260 arguments.callee.anim = wrap.fxanim(a,
10270 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10271 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10272 * 'hidden') but block elements will still take up space in the document. The element must be removed
10273 * from the DOM using the 'remove' config option if desired. This function automatically handles
10274 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10277 // default: slide the element out to the top
10280 // custom: slide the element out to the right with a 2-second duration
10281 el.slideOut('r', { duration: 2 });
10283 // common config options shown with default values
10291 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10292 * @param {Object} options (optional) Object literal with any of the Fx config options
10293 * @return {Roo.Element} The Element
10295 slideOut : function(anchor, o){
10296 var el = this.getFxEl();
10299 el.queueFx(o, function(){
10301 anchor = anchor || "t";
10303 // restore values after effect
10304 var r = this.getFxRestore();
10306 var b = this.getBox();
10307 // fixed size for slide
10311 var wrap = this.fxWrap(r.pos, o, "visible");
10313 var st = this.dom.style;
10314 st.visibility = "visible";
10315 st.position = "absolute";
10319 var after = function(){
10321 el.setDisplayed(false);
10326 el.fxUnwrap(wrap, r.pos, o);
10328 st.width = r.width;
10329 st.height = r.height;
10334 var a, zero = {to: 0};
10335 switch(anchor.toLowerCase()){
10337 st.left = st.bottom = "0";
10338 a = {height: zero};
10341 st.right = st.top = "0";
10345 st.left = st.top = "0";
10346 a = {width: zero, points: {to:[b.right, b.y]}};
10349 st.left = st.top = "0";
10350 a = {height: zero, points: {to:[b.x, b.bottom]}};
10353 st.right = st.bottom = "0";
10354 a = {width: zero, height: zero};
10357 st.right = st.top = "0";
10358 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10361 st.left = st.top = "0";
10362 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10365 st.left = st.bottom = "0";
10366 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10370 arguments.callee.anim = wrap.fxanim(a,
10380 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10381 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10382 * The element must be removed from the DOM using the 'remove' config option if desired.
10388 // common config options shown with default values
10396 * @param {Object} options (optional) Object literal with any of the Fx config options
10397 * @return {Roo.Element} The Element
10399 puff : function(o){
10400 var el = this.getFxEl();
10403 el.queueFx(o, function(){
10404 this.clearOpacity();
10407 // restore values after effect
10408 var r = this.getFxRestore();
10409 var st = this.dom.style;
10411 var after = function(){
10413 el.setDisplayed(false);
10420 el.setPositioning(r.pos);
10421 st.width = r.width;
10422 st.height = r.height;
10427 var width = this.getWidth();
10428 var height = this.getHeight();
10430 arguments.callee.anim = this.fxanim({
10431 width : {to: this.adjustWidth(width * 2)},
10432 height : {to: this.adjustHeight(height * 2)},
10433 points : {by: [-(width * .5), -(height * .5)]},
10435 fontSize: {to:200, unit: "%"}
10446 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10447 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10448 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10454 // all config options shown with default values
10462 * @param {Object} options (optional) Object literal with any of the Fx config options
10463 * @return {Roo.Element} The Element
10465 switchOff : function(o){
10466 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 this.clearOpacity();
10473 // restore values after effect
10474 var r = this.getFxRestore();
10475 var st = this.dom.style;
10477 var after = function(){
10479 el.setDisplayed(false);
10485 el.setPositioning(r.pos);
10486 st.width = r.width;
10487 st.height = r.height;
10492 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10493 this.clearOpacity();
10497 points:{by:[0, this.getHeight() * .5]}
10498 }, o, 'motion', 0.3, 'easeIn', after);
10499 }).defer(100, this);
10506 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10507 * changed using the "attr" config option) and then fading back to the original color. If no original
10508 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10511 // default: highlight background to yellow
10514 // custom: highlight foreground text to blue for 2 seconds
10515 el.highlight("0000ff", { attr: 'color', duration: 2 });
10517 // common config options shown with default values
10518 el.highlight("ffff9c", {
10519 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10520 endColor: (current color) or "ffffff",
10525 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10526 * @param {Object} options (optional) Object literal with any of the Fx config options
10527 * @return {Roo.Element} The Element
10529 highlight : function(color, o){
10530 var el = this.getFxEl();
10533 el.queueFx(o, function(){
10534 color = color || "ffff9c";
10535 attr = o.attr || "backgroundColor";
10537 this.clearOpacity();
10540 var origColor = this.getColor(attr);
10541 var restoreColor = this.dom.style[attr];
10542 endColor = (o.endColor || origColor) || "ffffff";
10544 var after = function(){
10545 el.dom.style[attr] = restoreColor;
10550 a[attr] = {from: color, to: endColor};
10551 arguments.callee.anim = this.fxanim(a,
10561 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10564 // default: a single light blue ripple
10567 // custom: 3 red ripples lasting 3 seconds total
10568 el.frame("ff0000", 3, { duration: 3 });
10570 // common config options shown with default values
10571 el.frame("C3DAF9", 1, {
10572 duration: 1 //duration of entire animation (not each individual ripple)
10573 // Note: Easing is not configurable and will be ignored if included
10576 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10577 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10578 * @param {Object} options (optional) Object literal with any of the Fx config options
10579 * @return {Roo.Element} The Element
10581 frame : function(color, count, o){
10582 var el = this.getFxEl();
10585 el.queueFx(o, function(){
10586 color = color || "#C3DAF9";
10587 if(color.length == 6){
10588 color = "#" + color;
10590 count = count || 1;
10591 duration = o.duration || 1;
10594 var b = this.getBox();
10595 var animFn = function(){
10596 var proxy = this.createProxy({
10599 visbility:"hidden",
10600 position:"absolute",
10601 "z-index":"35000", // yee haw
10602 border:"0px solid " + color
10605 var scale = Roo.isBorderBox ? 2 : 1;
10607 top:{from:b.y, to:b.y - 20},
10608 left:{from:b.x, to:b.x - 20},
10609 borderWidth:{from:0, to:10},
10610 opacity:{from:1, to:0},
10611 height:{from:b.height, to:(b.height + (20*scale))},
10612 width:{from:b.width, to:(b.width + (20*scale))}
10613 }, duration, function(){
10617 animFn.defer((duration/2)*1000, this);
10628 * Creates a pause before any subsequent queued effects begin. If there are
10629 * no effects queued after the pause it will have no effect.
10634 * @param {Number} seconds The length of time to pause (in seconds)
10635 * @return {Roo.Element} The Element
10637 pause : function(seconds){
10638 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 setTimeout(function(){
10644 }, seconds * 1000);
10650 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10651 * using the "endOpacity" config option.
10654 // default: fade in from opacity 0 to 100%
10657 // custom: fade in from opacity 0 to 75% over 2 seconds
10658 el.fadeIn({ endOpacity: .75, duration: 2});
10660 // common config options shown with default values
10662 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10667 * @param {Object} options (optional) Object literal with any of the Fx config options
10668 * @return {Roo.Element} The Element
10670 fadeIn : function(o){
10671 var el = this.getFxEl();
10673 el.queueFx(o, function(){
10674 this.setOpacity(0);
10676 this.dom.style.visibility = 'visible';
10677 var to = o.endOpacity || 1;
10678 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10679 o, null, .5, "easeOut", function(){
10681 this.clearOpacity();
10690 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10691 * using the "endOpacity" config option.
10694 // default: fade out from the element's current opacity to 0
10697 // custom: fade out from the element's current opacity to 25% over 2 seconds
10698 el.fadeOut({ endOpacity: .25, duration: 2});
10700 // common config options shown with default values
10702 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10709 * @param {Object} options (optional) Object literal with any of the Fx config options
10710 * @return {Roo.Element} The Element
10712 fadeOut : function(o){
10713 var el = this.getFxEl();
10715 el.queueFx(o, function(){
10716 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10717 o, null, .5, "easeOut", function(){
10718 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10719 this.dom.style.display = "none";
10721 this.dom.style.visibility = "hidden";
10723 this.clearOpacity();
10731 * Animates the transition of an element's dimensions from a starting height/width
10732 * to an ending height/width.
10735 // change height and width to 100x100 pixels
10736 el.scale(100, 100);
10738 // common config options shown with default values. The height and width will default to
10739 // the element's existing values if passed as null.
10742 [element's height], {
10747 * @param {Number} width The new width (pass undefined to keep the original width)
10748 * @param {Number} height The new height (pass undefined to keep the original height)
10749 * @param {Object} options (optional) Object literal with any of the Fx config options
10750 * @return {Roo.Element} The Element
10752 scale : function(w, h, o){
10753 this.shift(Roo.apply({}, o, {
10761 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10762 * Any of these properties not specified in the config object will not be changed. This effect
10763 * requires that at least one new dimension, position or opacity setting must be passed in on
10764 * the config object in order for the function to have any effect.
10767 // slide the element horizontally to x position 200 while changing the height and opacity
10768 el.shift({ x: 200, height: 50, opacity: .8 });
10770 // common config options shown with default values.
10772 width: [element's width],
10773 height: [element's height],
10774 x: [element's x position],
10775 y: [element's y position],
10776 opacity: [element's opacity],
10781 * @param {Object} options Object literal with any of the Fx config options
10782 * @return {Roo.Element} The Element
10784 shift : function(o){
10785 var el = this.getFxEl();
10787 el.queueFx(o, function(){
10788 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10789 if(w !== undefined){
10790 a.width = {to: this.adjustWidth(w)};
10792 if(h !== undefined){
10793 a.height = {to: this.adjustHeight(h)};
10795 if(x !== undefined || y !== undefined){
10797 x !== undefined ? x : this.getX(),
10798 y !== undefined ? y : this.getY()
10801 if(op !== undefined){
10802 a.opacity = {to: op};
10804 if(o.xy !== undefined){
10805 a.points = {to: o.xy};
10807 arguments.callee.anim = this.fxanim(a,
10808 o, 'motion', .35, "easeOut", function(){
10816 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10817 * ending point of the effect.
10820 // default: slide the element downward while fading out
10823 // custom: slide the element out to the right with a 2-second duration
10824 el.ghost('r', { duration: 2 });
10826 // common config options shown with default values
10834 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10835 * @param {Object} options (optional) Object literal with any of the Fx config options
10836 * @return {Roo.Element} The Element
10838 ghost : function(anchor, o){
10839 var el = this.getFxEl();
10842 el.queueFx(o, function(){
10843 anchor = anchor || "b";
10845 // restore values after effect
10846 var r = this.getFxRestore();
10847 var w = this.getWidth(),
10848 h = this.getHeight();
10850 var st = this.dom.style;
10852 var after = function(){
10854 el.setDisplayed(false);
10860 el.setPositioning(r.pos);
10861 st.width = r.width;
10862 st.height = r.height;
10867 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10868 switch(anchor.toLowerCase()){
10895 arguments.callee.anim = this.fxanim(a,
10905 * Ensures that all effects queued after syncFx is called on the element are
10906 * run concurrently. This is the opposite of {@link #sequenceFx}.
10907 * @return {Roo.Element} The Element
10909 syncFx : function(){
10910 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10919 * Ensures that all effects queued after sequenceFx is called on the element are
10920 * run in sequence. This is the opposite of {@link #syncFx}.
10921 * @return {Roo.Element} The Element
10923 sequenceFx : function(){
10924 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10926 concurrent : false,
10933 nextFx : function(){
10934 var ef = this.fxQueue[0];
10941 * Returns true if the element has any effects actively running or queued, else returns false.
10942 * @return {Boolean} True if element has active effects, else false
10944 hasActiveFx : function(){
10945 return this.fxQueue && this.fxQueue[0];
10949 * Stops any running effects and clears the element's internal effects queue if it contains
10950 * any additional effects that haven't started yet.
10951 * @return {Roo.Element} The Element
10953 stopFx : function(){
10954 if(this.hasActiveFx()){
10955 var cur = this.fxQueue[0];
10956 if(cur && cur.anim && cur.anim.isAnimated()){
10957 this.fxQueue = [cur]; // clear out others
10958 cur.anim.stop(true);
10965 beforeFx : function(o){
10966 if(this.hasActiveFx() && !o.concurrent){
10977 * Returns true if the element is currently blocking so that no other effect can be queued
10978 * until this effect is finished, else returns false if blocking is not set. This is commonly
10979 * used to ensure that an effect initiated by a user action runs to completion prior to the
10980 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10981 * @return {Boolean} True if blocking, else false
10983 hasFxBlock : function(){
10984 var q = this.fxQueue;
10985 return q && q[0] && q[0].block;
10989 queueFx : function(o, fn){
10993 if(!this.hasFxBlock()){
10994 Roo.applyIf(o, this.fxDefaults);
10996 var run = this.beforeFx(o);
10997 fn.block = o.block;
10998 this.fxQueue.push(fn);
11010 fxWrap : function(pos, o, vis){
11012 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11015 wrapXY = this.getXY();
11017 var div = document.createElement("div");
11018 div.style.visibility = vis;
11019 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11020 wrap.setPositioning(pos);
11021 if(wrap.getStyle("position") == "static"){
11022 wrap.position("relative");
11024 this.clearPositioning('auto');
11026 wrap.dom.appendChild(this.dom);
11028 wrap.setXY(wrapXY);
11035 fxUnwrap : function(wrap, pos, o){
11036 this.clearPositioning();
11037 this.setPositioning(pos);
11039 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11045 getFxRestore : function(){
11046 var st = this.dom.style;
11047 return {pos: this.getPositioning(), width: st.width, height : st.height};
11051 afterFx : function(o){
11053 this.applyStyles(o.afterStyle);
11056 this.addClass(o.afterCls);
11058 if(o.remove === true){
11061 Roo.callback(o.callback, o.scope, [this]);
11063 this.fxQueue.shift();
11069 getFxEl : function(){ // support for composite element fx
11070 return Roo.get(this.dom);
11074 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11075 animType = animType || 'run';
11077 var anim = Roo.lib.Anim[animType](
11079 (opt.duration || defaultDur) || .35,
11080 (opt.easing || defaultEase) || 'easeOut',
11082 Roo.callback(cb, this);
11091 // backwords compat
11092 Roo.Fx.resize = Roo.Fx.scale;
11094 //When included, Roo.Fx is automatically applied to Element so that all basic
11095 //effects are available directly via the Element API
11096 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11098 * Ext JS Library 1.1.1
11099 * Copyright(c) 2006-2007, Ext JS, LLC.
11101 * Originally Released Under LGPL - original licence link has changed is not relivant.
11104 * <script type="text/javascript">
11109 * @class Roo.CompositeElement
11110 * Standard composite class. Creates a Roo.Element for every element in the collection.
11112 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11113 * actions will be performed on all the elements in this collection.</b>
11115 * All methods return <i>this</i> and can be chained.
11117 var els = Roo.select("#some-el div.some-class", true);
11118 // or select directly from an existing element
11119 var el = Roo.get('some-el');
11120 el.select('div.some-class', true);
11122 els.setWidth(100); // all elements become 100 width
11123 els.hide(true); // all elements fade out and hide
11125 els.setWidth(100).hide(true);
11128 Roo.CompositeElement = function(els){
11129 this.elements = [];
11130 this.addElements(els);
11132 Roo.CompositeElement.prototype = {
11134 addElements : function(els){
11138 if(typeof els == "string"){
11139 els = Roo.Element.selectorFunction(els);
11141 var yels = this.elements;
11142 var index = yels.length-1;
11143 for(var i = 0, len = els.length; i < len; i++) {
11144 yels[++index] = Roo.get(els[i]);
11150 * Clears this composite and adds the elements returned by the passed selector.
11151 * @param {String/Array} els A string CSS selector, an array of elements or an element
11152 * @return {CompositeElement} this
11154 fill : function(els){
11155 this.elements = [];
11161 * Filters this composite to only elements that match the passed selector.
11162 * @param {String} selector A string CSS selector
11163 * @param {Boolean} inverse return inverse filter (not matches)
11164 * @return {CompositeElement} this
11166 filter : function(selector, inverse){
11168 inverse = inverse || false;
11169 this.each(function(el){
11170 var match = inverse ? !el.is(selector) : el.is(selector);
11172 els[els.length] = el.dom;
11179 invoke : function(fn, args){
11180 var els = this.elements;
11181 for(var i = 0, len = els.length; i < len; i++) {
11182 Roo.Element.prototype[fn].apply(els[i], args);
11187 * Adds elements to this composite.
11188 * @param {String/Array} els A string CSS selector, an array of elements or an element
11189 * @return {CompositeElement} this
11191 add : function(els){
11192 if(typeof els == "string"){
11193 this.addElements(Roo.Element.selectorFunction(els));
11194 }else if(els.length !== undefined){
11195 this.addElements(els);
11197 this.addElements([els]);
11202 * Calls the passed function passing (el, this, index) for each element in this composite.
11203 * @param {Function} fn The function to call
11204 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11205 * @return {CompositeElement} this
11207 each : function(fn, scope){
11208 var els = this.elements;
11209 for(var i = 0, len = els.length; i < len; i++){
11210 if(fn.call(scope || els[i], els[i], this, i) === false) {
11218 * Returns the Element object at the specified index
11219 * @param {Number} index
11220 * @return {Roo.Element}
11222 item : function(index){
11223 return this.elements[index] || null;
11227 * Returns the first Element
11228 * @return {Roo.Element}
11230 first : function(){
11231 return this.item(0);
11235 * Returns the last Element
11236 * @return {Roo.Element}
11239 return this.item(this.elements.length-1);
11243 * Returns the number of elements in this composite
11246 getCount : function(){
11247 return this.elements.length;
11251 * Returns true if this composite contains the passed element
11254 contains : function(el){
11255 return this.indexOf(el) !== -1;
11259 * Returns true if this composite contains the passed element
11262 indexOf : function(el){
11263 return this.elements.indexOf(Roo.get(el));
11268 * Removes the specified element(s).
11269 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11270 * or an array of any of those.
11271 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11272 * @return {CompositeElement} this
11274 removeElement : function(el, removeDom){
11275 if(el instanceof Array){
11276 for(var i = 0, len = el.length; i < len; i++){
11277 this.removeElement(el[i]);
11281 var index = typeof el == 'number' ? el : this.indexOf(el);
11284 var d = this.elements[index];
11288 d.parentNode.removeChild(d);
11291 this.elements.splice(index, 1);
11297 * Replaces the specified element with the passed element.
11298 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11300 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11301 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11302 * @return {CompositeElement} this
11304 replaceElement : function(el, replacement, domReplace){
11305 var index = typeof el == 'number' ? el : this.indexOf(el);
11308 this.elements[index].replaceWith(replacement);
11310 this.elements.splice(index, 1, Roo.get(replacement))
11317 * Removes all elements.
11319 clear : function(){
11320 this.elements = [];
11324 Roo.CompositeElement.createCall = function(proto, fnName){
11325 if(!proto[fnName]){
11326 proto[fnName] = function(){
11327 return this.invoke(fnName, arguments);
11331 for(var fnName in Roo.Element.prototype){
11332 if(typeof Roo.Element.prototype[fnName] == "function"){
11333 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11339 * Ext JS Library 1.1.1
11340 * Copyright(c) 2006-2007, Ext JS, LLC.
11342 * Originally Released Under LGPL - original licence link has changed is not relivant.
11345 * <script type="text/javascript">
11349 * @class Roo.CompositeElementLite
11350 * @extends Roo.CompositeElement
11351 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11353 var els = Roo.select("#some-el div.some-class");
11354 // or select directly from an existing element
11355 var el = Roo.get('some-el');
11356 el.select('div.some-class');
11358 els.setWidth(100); // all elements become 100 width
11359 els.hide(true); // all elements fade out and hide
11361 els.setWidth(100).hide(true);
11362 </code></pre><br><br>
11363 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11364 * actions will be performed on all the elements in this collection.</b>
11366 Roo.CompositeElementLite = function(els){
11367 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11368 this.el = new Roo.Element.Flyweight();
11370 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11371 addElements : function(els){
11373 if(els instanceof Array){
11374 this.elements = this.elements.concat(els);
11376 var yels = this.elements;
11377 var index = yels.length-1;
11378 for(var i = 0, len = els.length; i < len; i++) {
11379 yels[++index] = els[i];
11385 invoke : function(fn, args){
11386 var els = this.elements;
11388 for(var i = 0, len = els.length; i < len; i++) {
11390 Roo.Element.prototype[fn].apply(el, args);
11395 * Returns a flyweight Element of the dom element object at the specified index
11396 * @param {Number} index
11397 * @return {Roo.Element}
11399 item : function(index){
11400 if(!this.elements[index]){
11403 this.el.dom = this.elements[index];
11407 // fixes scope with flyweight
11408 addListener : function(eventName, handler, scope, opt){
11409 var els = this.elements;
11410 for(var i = 0, len = els.length; i < len; i++) {
11411 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11417 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11418 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11419 * a reference to the dom node, use el.dom.</b>
11420 * @param {Function} fn The function to call
11421 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11422 * @return {CompositeElement} this
11424 each : function(fn, scope){
11425 var els = this.elements;
11427 for(var i = 0, len = els.length; i < len; i++){
11429 if(fn.call(scope || el, el, this, i) === false){
11436 indexOf : function(el){
11437 return this.elements.indexOf(Roo.getDom(el));
11440 replaceElement : function(el, replacement, domReplace){
11441 var index = typeof el == 'number' ? el : this.indexOf(el);
11443 replacement = Roo.getDom(replacement);
11445 var d = this.elements[index];
11446 d.parentNode.insertBefore(replacement, d);
11447 d.parentNode.removeChild(d);
11449 this.elements.splice(index, 1, replacement);
11454 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11458 * Ext JS Library 1.1.1
11459 * Copyright(c) 2006-2007, Ext JS, LLC.
11461 * Originally Released Under LGPL - original licence link has changed is not relivant.
11464 * <script type="text/javascript">
11470 * @class Roo.data.Connection
11471 * @extends Roo.util.Observable
11472 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11473 * either to a configured URL, or to a URL specified at request time.<br><br>
11475 * Requests made by this class are asynchronous, and will return immediately. No data from
11476 * the server will be available to the statement immediately following the {@link #request} call.
11477 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11479 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11480 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11481 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11482 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11483 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11484 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11485 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11486 * standard DOM methods.
11488 * @param {Object} config a configuration object.
11490 Roo.data.Connection = function(config){
11491 Roo.apply(this, config);
11494 * @event beforerequest
11495 * Fires before a network request is made to retrieve a data object.
11496 * @param {Connection} conn This Connection object.
11497 * @param {Object} options The options config object passed to the {@link #request} method.
11499 "beforerequest" : true,
11501 * @event requestcomplete
11502 * Fires if the request was successfully completed.
11503 * @param {Connection} conn This Connection object.
11504 * @param {Object} response The XHR object containing the response data.
11505 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11506 * @param {Object} options The options config object passed to the {@link #request} method.
11508 "requestcomplete" : true,
11510 * @event requestexception
11511 * Fires if an error HTTP status was returned from the server.
11512 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11513 * @param {Connection} conn This Connection object.
11514 * @param {Object} response The XHR object containing the response data.
11515 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11516 * @param {Object} options The options config object passed to the {@link #request} method.
11518 "requestexception" : true
11520 Roo.data.Connection.superclass.constructor.call(this);
11523 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11525 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11528 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11529 * extra parameters to each request made by this object. (defaults to undefined)
11532 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11533 * to each request made by this object. (defaults to undefined)
11536 * @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)
11539 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11543 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11549 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11552 disableCaching: true,
11555 * Sends an HTTP request to a remote server.
11556 * @param {Object} options An object which may contain the following properties:<ul>
11557 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11558 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11559 * request, a url encoded string or a function to call to get either.</li>
11560 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11561 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11562 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11563 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11564 * <li>options {Object} The parameter to the request call.</li>
11565 * <li>success {Boolean} True if the request succeeded.</li>
11566 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11568 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11569 * The callback is passed the following parameters:<ul>
11570 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11571 * <li>options {Object} The parameter to the request call.</li>
11573 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11574 * The callback is passed the following parameters:<ul>
11575 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11576 * <li>options {Object} The parameter to the request call.</li>
11578 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11579 * for the callback function. Defaults to the browser window.</li>
11580 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11581 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11582 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11583 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11584 * params for the post data. Any params will be appended to the URL.</li>
11585 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11587 * @return {Number} transactionId
11589 request : function(o){
11590 if(this.fireEvent("beforerequest", this, o) !== false){
11593 if(typeof p == "function"){
11594 p = p.call(o.scope||window, o);
11596 if(typeof p == "object"){
11597 p = Roo.urlEncode(o.params);
11599 if(this.extraParams){
11600 var extras = Roo.urlEncode(this.extraParams);
11601 p = p ? (p + '&' + extras) : extras;
11604 var url = o.url || this.url;
11605 if(typeof url == 'function'){
11606 url = url.call(o.scope||window, o);
11610 var form = Roo.getDom(o.form);
11611 url = url || form.action;
11613 var enctype = form.getAttribute("enctype");
11614 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11615 return this.doFormUpload(o, p, url);
11617 var f = Roo.lib.Ajax.serializeForm(form);
11618 p = p ? (p + '&' + f) : f;
11621 var hs = o.headers;
11622 if(this.defaultHeaders){
11623 hs = Roo.apply(hs || {}, this.defaultHeaders);
11630 success: this.handleResponse,
11631 failure: this.handleFailure,
11633 argument: {options: o},
11634 timeout : o.timeout || this.timeout
11637 var method = o.method||this.method||(p ? "POST" : "GET");
11639 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11640 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11643 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11647 }else if(this.autoAbort !== false){
11651 if((method == 'GET' && p) || o.xmlData){
11652 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11655 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11656 return this.transId;
11658 Roo.callback(o.callback, o.scope, [o, null, null]);
11664 * Determine whether this object has a request outstanding.
11665 * @param {Number} transactionId (Optional) defaults to the last transaction
11666 * @return {Boolean} True if there is an outstanding request.
11668 isLoading : function(transId){
11670 return Roo.lib.Ajax.isCallInProgress(transId);
11672 return this.transId ? true : false;
11677 * Aborts any outstanding request.
11678 * @param {Number} transactionId (Optional) defaults to the last transaction
11680 abort : function(transId){
11681 if(transId || this.isLoading()){
11682 Roo.lib.Ajax.abort(transId || this.transId);
11687 handleResponse : function(response){
11688 this.transId = false;
11689 var options = response.argument.options;
11690 response.argument = options ? options.argument : null;
11691 this.fireEvent("requestcomplete", this, response, options);
11692 Roo.callback(options.success, options.scope, [response, options]);
11693 Roo.callback(options.callback, options.scope, [options, true, response]);
11697 handleFailure : function(response, e){
11698 this.transId = false;
11699 var options = response.argument.options;
11700 response.argument = options ? options.argument : null;
11701 this.fireEvent("requestexception", this, response, options, e);
11702 Roo.callback(options.failure, options.scope, [response, options]);
11703 Roo.callback(options.callback, options.scope, [options, false, response]);
11707 doFormUpload : function(o, ps, url){
11709 var frame = document.createElement('iframe');
11712 frame.className = 'x-hidden';
11714 frame.src = Roo.SSL_SECURE_URL;
11716 document.body.appendChild(frame);
11719 document.frames[id].name = id;
11722 var form = Roo.getDom(o.form);
11724 form.method = 'POST';
11725 form.enctype = form.encoding = 'multipart/form-data';
11731 if(ps){ // add dynamic params
11733 ps = Roo.urlDecode(ps, false);
11735 if(ps.hasOwnProperty(k)){
11736 hd = document.createElement('input');
11737 hd.type = 'hidden';
11740 form.appendChild(hd);
11747 var r = { // bogus response object
11752 r.argument = o ? o.argument : null;
11757 doc = frame.contentWindow.document;
11759 doc = (frame.contentDocument || window.frames[id].document);
11761 if(doc && doc.body){
11762 r.responseText = doc.body.innerHTML;
11764 if(doc && doc.XMLDocument){
11765 r.responseXML = doc.XMLDocument;
11767 r.responseXML = doc;
11774 Roo.EventManager.removeListener(frame, 'load', cb, this);
11776 this.fireEvent("requestcomplete", this, r, o);
11777 Roo.callback(o.success, o.scope, [r, o]);
11778 Roo.callback(o.callback, o.scope, [o, true, r]);
11780 setTimeout(function(){document.body.removeChild(frame);}, 100);
11783 Roo.EventManager.on(frame, 'load', cb, this);
11786 if(hiddens){ // remove dynamic params
11787 for(var i = 0, len = hiddens.length; i < len; i++){
11788 form.removeChild(hiddens[i]);
11795 * Ext JS Library 1.1.1
11796 * Copyright(c) 2006-2007, Ext JS, LLC.
11798 * Originally Released Under LGPL - original licence link has changed is not relivant.
11801 * <script type="text/javascript">
11805 * Global Ajax request class.
11808 * @extends Roo.data.Connection
11811 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11812 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11813 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11814 * @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)
11815 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11816 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11817 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11819 Roo.Ajax = new Roo.data.Connection({
11828 * Serialize the passed form into a url encoded string
11830 * @param {String/HTMLElement} form
11833 serializeForm : function(form){
11834 return Roo.lib.Ajax.serializeForm(form);
11838 * Ext JS Library 1.1.1
11839 * Copyright(c) 2006-2007, Ext JS, LLC.
11841 * Originally Released Under LGPL - original licence link has changed is not relivant.
11844 * <script type="text/javascript">
11849 * @class Roo.UpdateManager
11850 * @extends Roo.util.Observable
11851 * Provides AJAX-style update for Element object.<br><br>
11854 * // Get it from a Roo.Element object
11855 * var el = Roo.get("foo");
11856 * var mgr = el.getUpdateManager();
11857 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11859 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11861 * // or directly (returns the same UpdateManager instance)
11862 * var mgr = new Roo.UpdateManager("myElementId");
11863 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11864 * mgr.on("update", myFcnNeedsToKnow);
11866 // short handed call directly from the element object
11867 Roo.get("foo").load({
11871 text: "Loading Foo..."
11875 * Create new UpdateManager directly.
11876 * @param {String/HTMLElement/Roo.Element} el The element to update
11877 * @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).
11879 Roo.UpdateManager = function(el, forceNew){
11881 if(!forceNew && el.updateManager){
11882 return el.updateManager;
11885 * The Element object
11886 * @type Roo.Element
11890 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11893 this.defaultUrl = null;
11897 * @event beforeupdate
11898 * Fired before an update is made, return false from your handler and the update is cancelled.
11899 * @param {Roo.Element} el
11900 * @param {String/Object/Function} url
11901 * @param {String/Object} params
11903 "beforeupdate": true,
11906 * Fired after successful update is made.
11907 * @param {Roo.Element} el
11908 * @param {Object} oResponseObject The response Object
11913 * Fired on update failure.
11914 * @param {Roo.Element} el
11915 * @param {Object} oResponseObject The response Object
11919 var d = Roo.UpdateManager.defaults;
11921 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11924 this.sslBlankUrl = d.sslBlankUrl;
11926 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11929 this.disableCaching = d.disableCaching;
11931 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11934 this.indicatorText = d.indicatorText;
11936 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11939 this.showLoadIndicator = d.showLoadIndicator;
11941 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11944 this.timeout = d.timeout;
11947 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11950 this.loadScripts = d.loadScripts;
11953 * Transaction object of current executing transaction
11955 this.transaction = null;
11960 this.autoRefreshProcId = null;
11962 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11965 this.refreshDelegate = this.refresh.createDelegate(this);
11967 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11970 this.updateDelegate = this.update.createDelegate(this);
11972 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11975 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11979 this.successDelegate = this.processSuccess.createDelegate(this);
11983 this.failureDelegate = this.processFailure.createDelegate(this);
11985 if(!this.renderer){
11987 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11989 this.renderer = new Roo.UpdateManager.BasicRenderer();
11992 Roo.UpdateManager.superclass.constructor.call(this);
11995 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11997 * Get the Element this UpdateManager is bound to
11998 * @return {Roo.Element} The element
12000 getEl : function(){
12004 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12005 * @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:
12008 url: "your-url.php",<br/>
12009 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12010 callback: yourFunction,<br/>
12011 scope: yourObject, //(optional scope) <br/>
12012 discardUrl: false, <br/>
12013 nocache: false,<br/>
12014 text: "Loading...",<br/>
12016 scripts: false<br/>
12019 * The only required property is url. The optional properties nocache, text and scripts
12020 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12021 * @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}
12022 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12023 * @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.
12025 update : function(url, params, callback, discardUrl){
12026 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12027 var method = this.method,
12029 if(typeof url == "object"){ // must be config object
12032 params = params || cfg.params;
12033 callback = callback || cfg.callback;
12034 discardUrl = discardUrl || cfg.discardUrl;
12035 if(callback && cfg.scope){
12036 callback = callback.createDelegate(cfg.scope);
12038 if(typeof cfg.method != "undefined"){method = cfg.method;};
12039 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12040 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12041 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12042 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12044 this.showLoading();
12046 this.defaultUrl = url;
12048 if(typeof url == "function"){
12049 url = url.call(this);
12052 method = method || (params ? "POST" : "GET");
12053 if(method == "GET"){
12054 url = this.prepareUrl(url);
12057 var o = Roo.apply(cfg ||{}, {
12060 success: this.successDelegate,
12061 failure: this.failureDelegate,
12062 callback: undefined,
12063 timeout: (this.timeout*1000),
12064 argument: {"url": url, "form": null, "callback": callback, "params": params}
12066 Roo.log("updated manager called with timeout of " + o.timeout);
12067 this.transaction = Roo.Ajax.request(o);
12072 * 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.
12073 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12074 * @param {String/HTMLElement} form The form Id or form element
12075 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12076 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12077 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12079 formUpdate : function(form, url, reset, callback){
12080 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12081 if(typeof url == "function"){
12082 url = url.call(this);
12084 form = Roo.getDom(form);
12085 this.transaction = Roo.Ajax.request({
12088 success: this.successDelegate,
12089 failure: this.failureDelegate,
12090 timeout: (this.timeout*1000),
12091 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12093 this.showLoading.defer(1, this);
12098 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12099 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12101 refresh : function(callback){
12102 if(this.defaultUrl == null){
12105 this.update(this.defaultUrl, null, callback, true);
12109 * Set this element to auto refresh.
12110 * @param {Number} interval How often to update (in seconds).
12111 * @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)
12112 * @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}
12113 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12114 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12116 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12118 this.update(url || this.defaultUrl, params, callback, true);
12120 if(this.autoRefreshProcId){
12121 clearInterval(this.autoRefreshProcId);
12123 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12127 * Stop auto refresh on this element.
12129 stopAutoRefresh : function(){
12130 if(this.autoRefreshProcId){
12131 clearInterval(this.autoRefreshProcId);
12132 delete this.autoRefreshProcId;
12136 isAutoRefreshing : function(){
12137 return this.autoRefreshProcId ? true : false;
12140 * Called to update the element to "Loading" state. Override to perform custom action.
12142 showLoading : function(){
12143 if(this.showLoadIndicator){
12144 this.el.update(this.indicatorText);
12149 * Adds unique parameter to query string if disableCaching = true
12152 prepareUrl : function(url){
12153 if(this.disableCaching){
12154 var append = "_dc=" + (new Date().getTime());
12155 if(url.indexOf("?") !== -1){
12156 url += "&" + append;
12158 url += "?" + append;
12167 processSuccess : function(response){
12168 this.transaction = null;
12169 if(response.argument.form && response.argument.reset){
12170 try{ // put in try/catch since some older FF releases had problems with this
12171 response.argument.form.reset();
12174 if(this.loadScripts){
12175 this.renderer.render(this.el, response, this,
12176 this.updateComplete.createDelegate(this, [response]));
12178 this.renderer.render(this.el, response, this);
12179 this.updateComplete(response);
12183 updateComplete : function(response){
12184 this.fireEvent("update", this.el, response);
12185 if(typeof response.argument.callback == "function"){
12186 response.argument.callback(this.el, true, response);
12193 processFailure : function(response){
12194 this.transaction = null;
12195 this.fireEvent("failure", this.el, response);
12196 if(typeof response.argument.callback == "function"){
12197 response.argument.callback(this.el, false, response);
12202 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12203 * @param {Object} renderer The object implementing the render() method
12205 setRenderer : function(renderer){
12206 this.renderer = renderer;
12209 getRenderer : function(){
12210 return this.renderer;
12214 * Set the defaultUrl used for updates
12215 * @param {String/Function} defaultUrl The url or a function to call to get the url
12217 setDefaultUrl : function(defaultUrl){
12218 this.defaultUrl = defaultUrl;
12222 * Aborts the executing transaction
12224 abort : function(){
12225 if(this.transaction){
12226 Roo.Ajax.abort(this.transaction);
12231 * Returns true if an update is in progress
12232 * @return {Boolean}
12234 isUpdating : function(){
12235 if(this.transaction){
12236 return Roo.Ajax.isLoading(this.transaction);
12243 * @class Roo.UpdateManager.defaults
12244 * @static (not really - but it helps the doc tool)
12245 * The defaults collection enables customizing the default properties of UpdateManager
12247 Roo.UpdateManager.defaults = {
12249 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12255 * True to process scripts by default (Defaults to false).
12258 loadScripts : false,
12261 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12264 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12266 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12269 disableCaching : false,
12271 * Whether to show indicatorText when loading (Defaults to true).
12274 showLoadIndicator : true,
12276 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12279 indicatorText : '<div class="loading-indicator">Loading...</div>'
12283 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12285 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12286 * @param {String/HTMLElement/Roo.Element} el The element to update
12287 * @param {String} url The url
12288 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12289 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12292 * @member Roo.UpdateManager
12294 Roo.UpdateManager.updateElement = function(el, url, params, options){
12295 var um = Roo.get(el, true).getUpdateManager();
12296 Roo.apply(um, options);
12297 um.update(url, params, options ? options.callback : null);
12299 // alias for backwards compat
12300 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12302 * @class Roo.UpdateManager.BasicRenderer
12303 * Default Content renderer. Updates the elements innerHTML with the responseText.
12305 Roo.UpdateManager.BasicRenderer = function(){};
12307 Roo.UpdateManager.BasicRenderer.prototype = {
12309 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12310 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12311 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12312 * @param {Roo.Element} el The element being rendered
12313 * @param {Object} response The YUI Connect response object
12314 * @param {UpdateManager} updateManager The calling update manager
12315 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12317 render : function(el, response, updateManager, callback){
12318 el.update(response.responseText, updateManager.loadScripts, callback);
12324 * (c)) Alan Knowles
12330 * @class Roo.DomTemplate
12331 * @extends Roo.Template
12332 * An effort at a dom based template engine..
12334 * Similar to XTemplate, except it uses dom parsing to create the template..
12336 * Supported features:
12341 {a_variable} - output encoded.
12342 {a_variable.format:("Y-m-d")} - call a method on the variable
12343 {a_variable:raw} - unencoded output
12344 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12345 {a_variable:this.method_on_template(...)} - call a method on the template object.
12350 <div roo-for="a_variable or condition.."></div>
12351 <div roo-if="a_variable or condition"></div>
12352 <div roo-exec="some javascript"></div>
12353 <div roo-name="named_template"></div>
12358 Roo.DomTemplate = function()
12360 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12367 Roo.extend(Roo.DomTemplate, Roo.Template, {
12369 * id counter for sub templates.
12373 * flag to indicate if dom parser is inside a pre,
12374 * it will strip whitespace if not.
12379 * The various sub templates
12387 * basic tag replacing syntax
12390 * // you can fake an object call by doing this
12394 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12395 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12397 iterChild : function (node, method) {
12399 var oldPre = this.inPre;
12400 if (node.tagName == 'PRE') {
12403 for( var i = 0; i < node.childNodes.length; i++) {
12404 method.call(this, node.childNodes[i]);
12406 this.inPre = oldPre;
12412 * compile the template
12414 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12417 compile: function()
12421 // covert the html into DOM...
12425 doc = document.implementation.createHTMLDocument("");
12426 doc.documentElement.innerHTML = this.html ;
12427 div = doc.documentElement;
12429 // old IE... - nasty -- it causes all sorts of issues.. with
12430 // images getting pulled from server..
12431 div = document.createElement('div');
12432 div.innerHTML = this.html;
12434 //doc.documentElement.innerHTML = htmlBody
12440 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12442 var tpls = this.tpls;
12444 // create a top level template from the snippet..
12446 //Roo.log(div.innerHTML);
12453 body : div.innerHTML,
12466 Roo.each(tpls, function(tp){
12467 this.compileTpl(tp);
12468 this.tpls[tp.id] = tp;
12471 this.master = tpls[0];
12477 compileNode : function(node, istop) {
12482 // skip anything not a tag..
12483 if (node.nodeType != 1) {
12484 if (node.nodeType == 3 && !this.inPre) {
12485 // reduce white space..
12486 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12509 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12510 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12511 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12512 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12518 // just itterate children..
12519 this.iterChild(node,this.compileNode);
12522 tpl.uid = this.id++;
12523 tpl.value = node.getAttribute('roo-' + tpl.attr);
12524 node.removeAttribute('roo-'+ tpl.attr);
12525 if (tpl.attr != 'name') {
12526 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12527 node.parentNode.replaceChild(placeholder, node);
12530 var placeholder = document.createElement('span');
12531 placeholder.className = 'roo-tpl-' + tpl.value;
12532 node.parentNode.replaceChild(placeholder, node);
12535 // parent now sees '{domtplXXXX}
12536 this.iterChild(node,this.compileNode);
12538 // we should now have node body...
12539 var div = document.createElement('div');
12540 div.appendChild(node);
12542 // this has the unfortunate side effect of converting tagged attributes
12543 // eg. href="{...}" into %7C...%7D
12544 // this has been fixed by searching for those combo's although it's a bit hacky..
12547 tpl.body = div.innerHTML;
12554 switch (tpl.value) {
12555 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12556 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12557 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12562 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12566 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12570 tpl.id = tpl.value; // replace non characters???
12576 this.tpls.push(tpl);
12586 * Compile a segment of the template into a 'sub-template'
12592 compileTpl : function(tpl)
12594 var fm = Roo.util.Format;
12595 var useF = this.disableFormats !== true;
12597 var sep = Roo.isGecko ? "+\n" : ",\n";
12599 var undef = function(str) {
12600 Roo.debug && Roo.log("Property not found :" + str);
12604 //Roo.log(tpl.body);
12608 var fn = function(m, lbrace, name, format, args)
12611 //Roo.log(arguments);
12612 args = args ? args.replace(/\\'/g,"'") : args;
12613 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12614 if (typeof(format) == 'undefined') {
12615 format = 'htmlEncode';
12617 if (format == 'raw' ) {
12621 if(name.substr(0, 6) == 'domtpl'){
12622 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12625 // build an array of options to determine if value is undefined..
12627 // basically get 'xxxx.yyyy' then do
12628 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12629 // (function () { Roo.log("Property not found"); return ''; })() :
12634 Roo.each(name.split('.'), function(st) {
12635 lookfor += (lookfor.length ? '.': '') + st;
12636 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12639 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12642 if(format && useF){
12644 args = args ? ',' + args : "";
12646 if(format.substr(0, 5) != "this."){
12647 format = "fm." + format + '(';
12649 format = 'this.call("'+ format.substr(5) + '", ';
12653 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12656 if (args && args.length) {
12657 // called with xxyx.yuu:(test,test)
12659 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12661 // raw.. - :raw modifier..
12662 return "'"+ sep + udef_st + name + ")"+sep+"'";
12666 // branched to use + in gecko and [].join() in others
12668 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12669 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12672 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12673 body.push(tpl.body.replace(/(\r\n|\n)/g,
12674 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12675 body.push("'].join('');};};");
12676 body = body.join('');
12679 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12681 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12688 * same as applyTemplate, except it's done to one of the subTemplates
12689 * when using named templates, you can do:
12691 * var str = pl.applySubTemplate('your-name', values);
12694 * @param {Number} id of the template
12695 * @param {Object} values to apply to template
12696 * @param {Object} parent (normaly the instance of this object)
12698 applySubTemplate : function(id, values, parent)
12702 var t = this.tpls[id];
12706 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12707 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12711 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12718 if(t.execCall && t.execCall.call(this, values, parent)){
12722 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12728 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12729 parent = t.target ? values : parent;
12730 if(t.forCall && vs instanceof Array){
12732 for(var i = 0, len = vs.length; i < len; i++){
12734 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12736 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12738 //Roo.log(t.compiled);
12742 return buf.join('');
12745 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12750 return t.compiled.call(this, vs, parent);
12752 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12754 //Roo.log(t.compiled);
12762 applyTemplate : function(values){
12763 return this.master.compiled.call(this, values, {});
12764 //var s = this.subs;
12767 apply : function(){
12768 return this.applyTemplate.apply(this, arguments);
12773 Roo.DomTemplate.from = function(el){
12774 el = Roo.getDom(el);
12775 return new Roo.Domtemplate(el.value || el.innerHTML);
12778 * Ext JS Library 1.1.1
12779 * Copyright(c) 2006-2007, Ext JS, LLC.
12781 * Originally Released Under LGPL - original licence link has changed is not relivant.
12784 * <script type="text/javascript">
12788 * @class Roo.util.DelayedTask
12789 * Provides a convenient method of performing setTimeout where a new
12790 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12791 * You can use this class to buffer
12792 * the keypress events for a certain number of milliseconds, and perform only if they stop
12793 * for that amount of time.
12794 * @constructor The parameters to this constructor serve as defaults and are not required.
12795 * @param {Function} fn (optional) The default function to timeout
12796 * @param {Object} scope (optional) The default scope of that timeout
12797 * @param {Array} args (optional) The default Array of arguments
12799 Roo.util.DelayedTask = function(fn, scope, args){
12800 var id = null, d, t;
12802 var call = function(){
12803 var now = new Date().getTime();
12807 fn.apply(scope, args || []);
12811 * Cancels any pending timeout and queues a new one
12812 * @param {Number} delay The milliseconds to delay
12813 * @param {Function} newFn (optional) Overrides function passed to constructor
12814 * @param {Object} newScope (optional) Overrides scope passed to constructor
12815 * @param {Array} newArgs (optional) Overrides args passed to constructor
12817 this.delay = function(delay, newFn, newScope, newArgs){
12818 if(id && delay != d){
12822 t = new Date().getTime();
12824 scope = newScope || scope;
12825 args = newArgs || args;
12827 id = setInterval(call, d);
12832 * Cancel the last queued timeout
12834 this.cancel = function(){
12842 * Ext JS Library 1.1.1
12843 * Copyright(c) 2006-2007, Ext JS, LLC.
12845 * Originally Released Under LGPL - original licence link has changed is not relivant.
12848 * <script type="text/javascript">
12852 Roo.util.TaskRunner = function(interval){
12853 interval = interval || 10;
12854 var tasks = [], removeQueue = [];
12856 var running = false;
12858 var stopThread = function(){
12864 var startThread = function(){
12867 id = setInterval(runTasks, interval);
12871 var removeTask = function(task){
12872 removeQueue.push(task);
12878 var runTasks = function(){
12879 if(removeQueue.length > 0){
12880 for(var i = 0, len = removeQueue.length; i < len; i++){
12881 tasks.remove(removeQueue[i]);
12884 if(tasks.length < 1){
12889 var now = new Date().getTime();
12890 for(var i = 0, len = tasks.length; i < len; ++i){
12892 var itime = now - t.taskRunTime;
12893 if(t.interval <= itime){
12894 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12895 t.taskRunTime = now;
12896 if(rt === false || t.taskRunCount === t.repeat){
12901 if(t.duration && t.duration <= (now - t.taskStartTime)){
12908 * Queues a new task.
12909 * @param {Object} task
12911 this.start = function(task){
12913 task.taskStartTime = new Date().getTime();
12914 task.taskRunTime = 0;
12915 task.taskRunCount = 0;
12920 this.stop = function(task){
12925 this.stopAll = function(){
12927 for(var i = 0, len = tasks.length; i < len; i++){
12928 if(tasks[i].onStop){
12937 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12939 * Ext JS Library 1.1.1
12940 * Copyright(c) 2006-2007, Ext JS, LLC.
12942 * Originally Released Under LGPL - original licence link has changed is not relivant.
12945 * <script type="text/javascript">
12950 * @class Roo.util.MixedCollection
12951 * @extends Roo.util.Observable
12952 * A Collection class that maintains both numeric indexes and keys and exposes events.
12954 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12955 * collection (defaults to false)
12956 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12957 * and return the key value for that item. This is used when available to look up the key on items that
12958 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12959 * equivalent to providing an implementation for the {@link #getKey} method.
12961 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12969 * Fires when the collection is cleared.
12974 * Fires when an item is added to the collection.
12975 * @param {Number} index The index at which the item was added.
12976 * @param {Object} o The item added.
12977 * @param {String} key The key associated with the added item.
12982 * Fires when an item is replaced in the collection.
12983 * @param {String} key he key associated with the new added.
12984 * @param {Object} old The item being replaced.
12985 * @param {Object} new The new item.
12990 * Fires when an item is removed from the collection.
12991 * @param {Object} o The item being removed.
12992 * @param {String} key (optional) The key associated with the removed item.
12997 this.allowFunctions = allowFunctions === true;
12999 this.getKey = keyFn;
13001 Roo.util.MixedCollection.superclass.constructor.call(this);
13004 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13005 allowFunctions : false,
13008 * Adds an item to the collection.
13009 * @param {String} key The key to associate with the item
13010 * @param {Object} o The item to add.
13011 * @return {Object} The item added.
13013 add : function(key, o){
13014 if(arguments.length == 1){
13016 key = this.getKey(o);
13018 if(typeof key == "undefined" || key === null){
13020 this.items.push(o);
13021 this.keys.push(null);
13023 var old = this.map[key];
13025 return this.replace(key, o);
13028 this.items.push(o);
13030 this.keys.push(key);
13032 this.fireEvent("add", this.length-1, o, key);
13037 * MixedCollection has a generic way to fetch keys if you implement getKey.
13040 var mc = new Roo.util.MixedCollection();
13041 mc.add(someEl.dom.id, someEl);
13042 mc.add(otherEl.dom.id, otherEl);
13046 var mc = new Roo.util.MixedCollection();
13047 mc.getKey = function(el){
13053 // or via the constructor
13054 var mc = new Roo.util.MixedCollection(false, function(el){
13060 * @param o {Object} The item for which to find the key.
13061 * @return {Object} The key for the passed item.
13063 getKey : function(o){
13068 * Replaces an item in the collection.
13069 * @param {String} key The key associated with the item to replace, or the item to replace.
13070 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13071 * @return {Object} The new item.
13073 replace : function(key, o){
13074 if(arguments.length == 1){
13076 key = this.getKey(o);
13078 var old = this.item(key);
13079 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13080 return this.add(key, o);
13082 var index = this.indexOfKey(key);
13083 this.items[index] = o;
13085 this.fireEvent("replace", key, old, o);
13090 * Adds all elements of an Array or an Object to the collection.
13091 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13092 * an Array of values, each of which are added to the collection.
13094 addAll : function(objs){
13095 if(arguments.length > 1 || objs instanceof Array){
13096 var args = arguments.length > 1 ? arguments : objs;
13097 for(var i = 0, len = args.length; i < len; i++){
13101 for(var key in objs){
13102 if(this.allowFunctions || typeof objs[key] != "function"){
13103 this.add(key, objs[key]);
13110 * Executes the specified function once for every item in the collection, passing each
13111 * item as the first and only parameter. returning false from the function will stop the iteration.
13112 * @param {Function} fn The function to execute for each item.
13113 * @param {Object} scope (optional) The scope in which to execute the function.
13115 each : function(fn, scope){
13116 var items = [].concat(this.items); // each safe for removal
13117 for(var i = 0, len = items.length; i < len; i++){
13118 if(fn.call(scope || items[i], items[i], i, len) === false){
13125 * Executes the specified function once for every key in the collection, passing each
13126 * key, and its associated item as the first two parameters.
13127 * @param {Function} fn The function to execute for each item.
13128 * @param {Object} scope (optional) The scope in which to execute the function.
13130 eachKey : function(fn, scope){
13131 for(var i = 0, len = this.keys.length; i < len; i++){
13132 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13137 * Returns the first item in the collection which elicits a true return value from the
13138 * passed selection function.
13139 * @param {Function} fn The selection function to execute for each item.
13140 * @param {Object} scope (optional) The scope in which to execute the function.
13141 * @return {Object} The first item in the collection which returned true from the selection function.
13143 find : function(fn, scope){
13144 for(var i = 0, len = this.items.length; i < len; i++){
13145 if(fn.call(scope || window, this.items[i], this.keys[i])){
13146 return this.items[i];
13153 * Inserts an item at the specified index in the collection.
13154 * @param {Number} index The index to insert the item at.
13155 * @param {String} key The key to associate with the new item, or the item itself.
13156 * @param {Object} o (optional) If the second parameter was a key, the new item.
13157 * @return {Object} The item inserted.
13159 insert : function(index, key, o){
13160 if(arguments.length == 2){
13162 key = this.getKey(o);
13164 if(index >= this.length){
13165 return this.add(key, o);
13168 this.items.splice(index, 0, o);
13169 if(typeof key != "undefined" && key != null){
13172 this.keys.splice(index, 0, key);
13173 this.fireEvent("add", index, o, key);
13178 * Removed an item from the collection.
13179 * @param {Object} o The item to remove.
13180 * @return {Object} The item removed.
13182 remove : function(o){
13183 return this.removeAt(this.indexOf(o));
13187 * Remove an item from a specified index in the collection.
13188 * @param {Number} index The index within the collection of the item to remove.
13190 removeAt : function(index){
13191 if(index < this.length && index >= 0){
13193 var o = this.items[index];
13194 this.items.splice(index, 1);
13195 var key = this.keys[index];
13196 if(typeof key != "undefined"){
13197 delete this.map[key];
13199 this.keys.splice(index, 1);
13200 this.fireEvent("remove", o, key);
13205 * Removed an item associated with the passed key fom the collection.
13206 * @param {String} key The key of the item to remove.
13208 removeKey : function(key){
13209 return this.removeAt(this.indexOfKey(key));
13213 * Returns the number of items in the collection.
13214 * @return {Number} the number of items in the collection.
13216 getCount : function(){
13217 return this.length;
13221 * Returns index within the collection of the passed Object.
13222 * @param {Object} o The item to find the index of.
13223 * @return {Number} index of the item.
13225 indexOf : function(o){
13226 if(!this.items.indexOf){
13227 for(var i = 0, len = this.items.length; i < len; i++){
13228 if(this.items[i] == o) {
13234 return this.items.indexOf(o);
13239 * Returns index within the collection of the passed key.
13240 * @param {String} key The key to find the index of.
13241 * @return {Number} index of the key.
13243 indexOfKey : function(key){
13244 if(!this.keys.indexOf){
13245 for(var i = 0, len = this.keys.length; i < len; i++){
13246 if(this.keys[i] == key) {
13252 return this.keys.indexOf(key);
13257 * Returns the item associated with the passed key OR index. Key has priority over index.
13258 * @param {String/Number} key The key or index of the item.
13259 * @return {Object} The item associated with the passed key.
13261 item : function(key){
13262 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13263 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13267 * Returns the item at the specified index.
13268 * @param {Number} index The index of the item.
13271 itemAt : function(index){
13272 return this.items[index];
13276 * Returns the item associated with the passed key.
13277 * @param {String/Number} key The key of the item.
13278 * @return {Object} The item associated with the passed key.
13280 key : function(key){
13281 return this.map[key];
13285 * Returns true if the collection contains the passed Object as an item.
13286 * @param {Object} o The Object to look for in the collection.
13287 * @return {Boolean} True if the collection contains the Object as an item.
13289 contains : function(o){
13290 return this.indexOf(o) != -1;
13294 * Returns true if the collection contains the passed Object as a key.
13295 * @param {String} key The key to look for in the collection.
13296 * @return {Boolean} True if the collection contains the Object as a key.
13298 containsKey : function(key){
13299 return typeof this.map[key] != "undefined";
13303 * Removes all items from the collection.
13305 clear : function(){
13310 this.fireEvent("clear");
13314 * Returns the first item in the collection.
13315 * @return {Object} the first item in the collection..
13317 first : function(){
13318 return this.items[0];
13322 * Returns the last item in the collection.
13323 * @return {Object} the last item in the collection..
13326 return this.items[this.length-1];
13329 _sort : function(property, dir, fn){
13330 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13331 fn = fn || function(a, b){
13334 var c = [], k = this.keys, items = this.items;
13335 for(var i = 0, len = items.length; i < len; i++){
13336 c[c.length] = {key: k[i], value: items[i], index: i};
13338 c.sort(function(a, b){
13339 var v = fn(a[property], b[property]) * dsc;
13341 v = (a.index < b.index ? -1 : 1);
13345 for(var i = 0, len = c.length; i < len; i++){
13346 items[i] = c[i].value;
13349 this.fireEvent("sort", this);
13353 * Sorts this collection with the passed comparison function
13354 * @param {String} direction (optional) "ASC" or "DESC"
13355 * @param {Function} fn (optional) comparison function
13357 sort : function(dir, fn){
13358 this._sort("value", dir, fn);
13362 * Sorts this collection by keys
13363 * @param {String} direction (optional) "ASC" or "DESC"
13364 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13366 keySort : function(dir, fn){
13367 this._sort("key", dir, fn || function(a, b){
13368 return String(a).toUpperCase()-String(b).toUpperCase();
13373 * Returns a range of items in this collection
13374 * @param {Number} startIndex (optional) defaults to 0
13375 * @param {Number} endIndex (optional) default to the last item
13376 * @return {Array} An array of items
13378 getRange : function(start, end){
13379 var items = this.items;
13380 if(items.length < 1){
13383 start = start || 0;
13384 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13387 for(var i = start; i <= end; i++) {
13388 r[r.length] = items[i];
13391 for(var i = start; i >= end; i--) {
13392 r[r.length] = items[i];
13399 * Filter the <i>objects</i> in this collection by a specific property.
13400 * Returns a new collection that has been filtered.
13401 * @param {String} property A property on your objects
13402 * @param {String/RegExp} value Either string that the property values
13403 * should start with or a RegExp to test against the property
13404 * @return {MixedCollection} The new filtered collection
13406 filter : function(property, value){
13407 if(!value.exec){ // not a regex
13408 value = String(value);
13409 if(value.length == 0){
13410 return this.clone();
13412 value = new RegExp("^" + Roo.escapeRe(value), "i");
13414 return this.filterBy(function(o){
13415 return o && value.test(o[property]);
13420 * Filter by a function. * Returns a new collection that has been filtered.
13421 * The passed function will be called with each
13422 * object in the collection. If the function returns true, the value is included
13423 * otherwise it is filtered.
13424 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13425 * @param {Object} scope (optional) The scope of the function (defaults to this)
13426 * @return {MixedCollection} The new filtered collection
13428 filterBy : function(fn, scope){
13429 var r = new Roo.util.MixedCollection();
13430 r.getKey = this.getKey;
13431 var k = this.keys, it = this.items;
13432 for(var i = 0, len = it.length; i < len; i++){
13433 if(fn.call(scope||this, it[i], k[i])){
13434 r.add(k[i], it[i]);
13441 * Creates a duplicate of this collection
13442 * @return {MixedCollection}
13444 clone : function(){
13445 var r = new Roo.util.MixedCollection();
13446 var k = this.keys, it = this.items;
13447 for(var i = 0, len = it.length; i < len; i++){
13448 r.add(k[i], it[i]);
13450 r.getKey = this.getKey;
13455 * Returns the item associated with the passed key or index.
13457 * @param {String/Number} key The key or index of the item.
13458 * @return {Object} The item associated with the passed key.
13460 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13462 * Ext JS Library 1.1.1
13463 * Copyright(c) 2006-2007, Ext JS, LLC.
13465 * Originally Released Under LGPL - original licence link has changed is not relivant.
13468 * <script type="text/javascript">
13471 * @class Roo.util.JSON
13472 * Modified version of Douglas Crockford"s json.js that doesn"t
13473 * mess with the Object prototype
13474 * http://www.json.org/js.html
13477 Roo.util.JSON = new (function(){
13478 var useHasOwn = {}.hasOwnProperty ? true : false;
13480 // crashes Safari in some instances
13481 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13483 var pad = function(n) {
13484 return n < 10 ? "0" + n : n;
13497 var encodeString = function(s){
13498 if (/["\\\x00-\x1f]/.test(s)) {
13499 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13504 c = b.charCodeAt();
13506 Math.floor(c / 16).toString(16) +
13507 (c % 16).toString(16);
13510 return '"' + s + '"';
13513 var encodeArray = function(o){
13514 var a = ["["], b, i, l = o.length, v;
13515 for (i = 0; i < l; i += 1) {
13517 switch (typeof v) {
13526 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13534 var encodeDate = function(o){
13535 return '"' + o.getFullYear() + "-" +
13536 pad(o.getMonth() + 1) + "-" +
13537 pad(o.getDate()) + "T" +
13538 pad(o.getHours()) + ":" +
13539 pad(o.getMinutes()) + ":" +
13540 pad(o.getSeconds()) + '"';
13544 * Encodes an Object, Array or other value
13545 * @param {Mixed} o The variable to encode
13546 * @return {String} The JSON string
13548 this.encode = function(o)
13550 // should this be extended to fully wrap stringify..
13552 if(typeof o == "undefined" || o === null){
13554 }else if(o instanceof Array){
13555 return encodeArray(o);
13556 }else if(o instanceof Date){
13557 return encodeDate(o);
13558 }else if(typeof o == "string"){
13559 return encodeString(o);
13560 }else if(typeof o == "number"){
13561 return isFinite(o) ? String(o) : "null";
13562 }else if(typeof o == "boolean"){
13565 var a = ["{"], b, i, v;
13567 if(!useHasOwn || o.hasOwnProperty(i)) {
13569 switch (typeof v) {
13578 a.push(this.encode(i), ":",
13579 v === null ? "null" : this.encode(v));
13590 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13591 * @param {String} json The JSON string
13592 * @return {Object} The resulting object
13594 this.decode = function(json){
13596 return /** eval:var:json */ eval("(" + json + ')');
13600 * Shorthand for {@link Roo.util.JSON#encode}
13601 * @member Roo encode
13603 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13605 * Shorthand for {@link Roo.util.JSON#decode}
13606 * @member Roo decode
13608 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13611 * Ext JS Library 1.1.1
13612 * Copyright(c) 2006-2007, Ext JS, LLC.
13614 * Originally Released Under LGPL - original licence link has changed is not relivant.
13617 * <script type="text/javascript">
13621 * @class Roo.util.Format
13622 * Reusable data formatting functions
13625 Roo.util.Format = function(){
13626 var trimRe = /^\s+|\s+$/g;
13629 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13630 * @param {String} value The string to truncate
13631 * @param {Number} length The maximum length to allow before truncating
13632 * @return {String} The converted text
13634 ellipsis : function(value, len){
13635 if(value && value.length > len){
13636 return value.substr(0, len-3)+"...";
13642 * Checks a reference and converts it to empty string if it is undefined
13643 * @param {Mixed} value Reference to check
13644 * @return {Mixed} Empty string if converted, otherwise the original value
13646 undef : function(value){
13647 return typeof value != "undefined" ? value : "";
13651 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13652 * @param {String} value The string to encode
13653 * @return {String} The encoded text
13655 htmlEncode : function(value){
13656 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13660 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13661 * @param {String} value The string to decode
13662 * @return {String} The decoded text
13664 htmlDecode : function(value){
13665 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13669 * Trims any whitespace from either side of a string
13670 * @param {String} value The text to trim
13671 * @return {String} The trimmed text
13673 trim : function(value){
13674 return String(value).replace(trimRe, "");
13678 * Returns a substring from within an original string
13679 * @param {String} value The original text
13680 * @param {Number} start The start index of the substring
13681 * @param {Number} length The length of the substring
13682 * @return {String} The substring
13684 substr : function(value, start, length){
13685 return String(value).substr(start, length);
13689 * Converts a string to all lower case letters
13690 * @param {String} value The text to convert
13691 * @return {String} The converted text
13693 lowercase : function(value){
13694 return String(value).toLowerCase();
13698 * Converts a string to all upper case letters
13699 * @param {String} value The text to convert
13700 * @return {String} The converted text
13702 uppercase : function(value){
13703 return String(value).toUpperCase();
13707 * Converts the first character only of a string to upper case
13708 * @param {String} value The text to convert
13709 * @return {String} The converted text
13711 capitalize : function(value){
13712 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13716 call : function(value, fn){
13717 if(arguments.length > 2){
13718 var args = Array.prototype.slice.call(arguments, 2);
13719 args.unshift(value);
13721 return /** eval:var:value */ eval(fn).apply(window, args);
13723 /** eval:var:value */
13724 return /** eval:var:value */ eval(fn).call(window, value);
13730 * safer version of Math.toFixed..??/
13731 * @param {Number/String} value The numeric value to format
13732 * @param {Number/String} value Decimal places
13733 * @return {String} The formatted currency string
13735 toFixed : function(v, n)
13737 // why not use to fixed - precision is buggered???
13739 return Math.round(v-0);
13741 var fact = Math.pow(10,n+1);
13742 v = (Math.round((v-0)*fact))/fact;
13743 var z = (''+fact).substring(2);
13744 if (v == Math.floor(v)) {
13745 return Math.floor(v) + '.' + z;
13748 // now just padd decimals..
13749 var ps = String(v).split('.');
13750 var fd = (ps[1] + z);
13751 var r = fd.substring(0,n);
13752 var rm = fd.substring(n);
13754 return ps[0] + '.' + r;
13756 r*=1; // turn it into a number;
13758 if (String(r).length != n) {
13761 r = String(r).substring(1); // chop the end off.
13764 return ps[0] + '.' + r;
13769 * Format a number as US currency
13770 * @param {Number/String} value The numeric value to format
13771 * @return {String} The formatted currency string
13773 usMoney : function(v){
13774 return '$' + Roo.util.Format.number(v);
13779 * eventually this should probably emulate php's number_format
13780 * @param {Number/String} value The numeric value to format
13781 * @param {Number} decimals number of decimal places
13782 * @param {String} delimiter for thousands (default comma)
13783 * @return {String} The formatted currency string
13785 number : function(v, decimals, thousandsDelimiter)
13787 // multiply and round.
13788 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13789 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13791 var mul = Math.pow(10, decimals);
13792 var zero = String(mul).substring(1);
13793 v = (Math.round((v-0)*mul))/mul;
13795 // if it's '0' number.. then
13797 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13799 var ps = v.split('.');
13802 var r = /(\d+)(\d{3})/;
13805 if(thousandsDelimiter.length != 0) {
13806 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13811 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13812 // does not have decimals
13813 (decimals ? ('.' + zero) : '');
13816 return whole + sub ;
13820 * Parse a value into a formatted date using the specified format pattern.
13821 * @param {Mixed} value The value to format
13822 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13823 * @return {String} The formatted date string
13825 date : function(v, format){
13829 if(!(v instanceof Date)){
13830 v = new Date(Date.parse(v));
13832 return v.dateFormat(format || Roo.util.Format.defaults.date);
13836 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13837 * @param {String} format Any valid date format string
13838 * @return {Function} The date formatting function
13840 dateRenderer : function(format){
13841 return function(v){
13842 return Roo.util.Format.date(v, format);
13847 stripTagsRE : /<\/?[^>]+>/gi,
13850 * Strips all HTML tags
13851 * @param {Mixed} value The text from which to strip tags
13852 * @return {String} The stripped text
13854 stripTags : function(v){
13855 return !v ? v : String(v).replace(this.stripTagsRE, "");
13859 Roo.util.Format.defaults = {
13863 * Ext JS Library 1.1.1
13864 * Copyright(c) 2006-2007, Ext JS, LLC.
13866 * Originally Released Under LGPL - original licence link has changed is not relivant.
13869 * <script type="text/javascript">
13876 * @class Roo.MasterTemplate
13877 * @extends Roo.Template
13878 * Provides a template that can have child templates. The syntax is:
13880 var t = new Roo.MasterTemplate(
13881 '<select name="{name}">',
13882 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13885 t.add('options', {value: 'foo', text: 'bar'});
13886 // or you can add multiple child elements in one shot
13887 t.addAll('options', [
13888 {value: 'foo', text: 'bar'},
13889 {value: 'foo2', text: 'bar2'},
13890 {value: 'foo3', text: 'bar3'}
13892 // then append, applying the master template values
13893 t.append('my-form', {name: 'my-select'});
13895 * A name attribute for the child template is not required if you have only one child
13896 * template or you want to refer to them by index.
13898 Roo.MasterTemplate = function(){
13899 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13900 this.originalHtml = this.html;
13902 var m, re = this.subTemplateRe;
13905 while(m = re.exec(this.html)){
13906 var name = m[1], content = m[2];
13911 tpl : new Roo.Template(content)
13914 st[name] = st[subIndex];
13916 st[subIndex].tpl.compile();
13917 st[subIndex].tpl.call = this.call.createDelegate(this);
13920 this.subCount = subIndex;
13923 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13925 * The regular expression used to match sub templates
13929 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13932 * Applies the passed values to a child template.
13933 * @param {String/Number} name (optional) The name or index of the child template
13934 * @param {Array/Object} values The values to be applied to the template
13935 * @return {MasterTemplate} this
13937 add : function(name, values){
13938 if(arguments.length == 1){
13939 values = arguments[0];
13942 var s = this.subs[name];
13943 s.buffer[s.buffer.length] = s.tpl.apply(values);
13948 * Applies all the passed values to a child template.
13949 * @param {String/Number} name (optional) The name or index of the child template
13950 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13951 * @param {Boolean} reset (optional) True to reset the template first
13952 * @return {MasterTemplate} this
13954 fill : function(name, values, reset){
13956 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13964 for(var i = 0, len = values.length; i < len; i++){
13965 this.add(name, values[i]);
13971 * Resets the template for reuse
13972 * @return {MasterTemplate} this
13974 reset : function(){
13976 for(var i = 0; i < this.subCount; i++){
13982 applyTemplate : function(values){
13984 var replaceIndex = -1;
13985 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13986 return s[++replaceIndex].buffer.join("");
13988 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13991 apply : function(){
13992 return this.applyTemplate.apply(this, arguments);
13995 compile : function(){return this;}
13999 * Alias for fill().
14002 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14004 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14005 * var tpl = Roo.MasterTemplate.from('element-id');
14006 * @param {String/HTMLElement} el
14007 * @param {Object} config
14010 Roo.MasterTemplate.from = function(el, config){
14011 el = Roo.getDom(el);
14012 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14015 * Ext JS Library 1.1.1
14016 * Copyright(c) 2006-2007, Ext JS, LLC.
14018 * Originally Released Under LGPL - original licence link has changed is not relivant.
14021 * <script type="text/javascript">
14026 * @class Roo.util.CSS
14027 * Utility class for manipulating CSS rules
14030 Roo.util.CSS = function(){
14032 var doc = document;
14034 var camelRe = /(-[a-z])/gi;
14035 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14039 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14040 * tag and appended to the HEAD of the document.
14041 * @param {String|Object} cssText The text containing the css rules
14042 * @param {String} id An id to add to the stylesheet for later removal
14043 * @return {StyleSheet}
14045 createStyleSheet : function(cssText, id){
14047 var head = doc.getElementsByTagName("head")[0];
14048 var nrules = doc.createElement("style");
14049 nrules.setAttribute("type", "text/css");
14051 nrules.setAttribute("id", id);
14053 if (typeof(cssText) != 'string') {
14054 // support object maps..
14055 // not sure if this a good idea..
14056 // perhaps it should be merged with the general css handling
14057 // and handle js style props.
14058 var cssTextNew = [];
14059 for(var n in cssText) {
14061 for(var k in cssText[n]) {
14062 citems.push( k + ' : ' +cssText[n][k] + ';' );
14064 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14067 cssText = cssTextNew.join("\n");
14073 head.appendChild(nrules);
14074 ss = nrules.styleSheet;
14075 ss.cssText = cssText;
14078 nrules.appendChild(doc.createTextNode(cssText));
14080 nrules.cssText = cssText;
14082 head.appendChild(nrules);
14083 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14085 this.cacheStyleSheet(ss);
14090 * Removes a style or link tag by id
14091 * @param {String} id The id of the tag
14093 removeStyleSheet : function(id){
14094 var existing = doc.getElementById(id);
14096 existing.parentNode.removeChild(existing);
14101 * Dynamically swaps an existing stylesheet reference for a new one
14102 * @param {String} id The id of an existing link tag to remove
14103 * @param {String} url The href of the new stylesheet to include
14105 swapStyleSheet : function(id, url){
14106 this.removeStyleSheet(id);
14107 var ss = doc.createElement("link");
14108 ss.setAttribute("rel", "stylesheet");
14109 ss.setAttribute("type", "text/css");
14110 ss.setAttribute("id", id);
14111 ss.setAttribute("href", url);
14112 doc.getElementsByTagName("head")[0].appendChild(ss);
14116 * Refresh the rule cache if you have dynamically added stylesheets
14117 * @return {Object} An object (hash) of rules indexed by selector
14119 refreshCache : function(){
14120 return this.getRules(true);
14124 cacheStyleSheet : function(stylesheet){
14128 try{// try catch for cross domain access issue
14129 var ssRules = stylesheet.cssRules || stylesheet.rules;
14130 for(var j = ssRules.length-1; j >= 0; --j){
14131 rules[ssRules[j].selectorText] = ssRules[j];
14137 * Gets all css rules for the document
14138 * @param {Boolean} refreshCache true to refresh the internal cache
14139 * @return {Object} An object (hash) of rules indexed by selector
14141 getRules : function(refreshCache){
14142 if(rules == null || refreshCache){
14144 var ds = doc.styleSheets;
14145 for(var i =0, len = ds.length; i < len; i++){
14147 this.cacheStyleSheet(ds[i]);
14155 * Gets an an individual CSS rule by selector(s)
14156 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14157 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14158 * @return {CSSRule} The CSS rule or null if one is not found
14160 getRule : function(selector, refreshCache){
14161 var rs = this.getRules(refreshCache);
14162 if(!(selector instanceof Array)){
14163 return rs[selector];
14165 for(var i = 0; i < selector.length; i++){
14166 if(rs[selector[i]]){
14167 return rs[selector[i]];
14175 * Updates a rule property
14176 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14177 * @param {String} property The css property
14178 * @param {String} value The new value for the property
14179 * @return {Boolean} true If a rule was found and updated
14181 updateRule : function(selector, property, value){
14182 if(!(selector instanceof Array)){
14183 var rule = this.getRule(selector);
14185 rule.style[property.replace(camelRe, camelFn)] = value;
14189 for(var i = 0; i < selector.length; i++){
14190 if(this.updateRule(selector[i], property, value)){
14200 * Ext JS Library 1.1.1
14201 * Copyright(c) 2006-2007, Ext JS, LLC.
14203 * Originally Released Under LGPL - original licence link has changed is not relivant.
14206 * <script type="text/javascript">
14212 * @class Roo.util.ClickRepeater
14213 * @extends Roo.util.Observable
14215 * A wrapper class which can be applied to any element. Fires a "click" event while the
14216 * mouse is pressed. The interval between firings may be specified in the config but
14217 * defaults to 10 milliseconds.
14219 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14221 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14222 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14223 * Similar to an autorepeat key delay.
14224 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14225 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14226 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14227 * "interval" and "delay" are ignored. "immediate" is honored.
14228 * @cfg {Boolean} preventDefault True to prevent the default click event
14229 * @cfg {Boolean} stopDefault True to stop the default click event
14232 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14233 * 2007-02-02 jvs Renamed to ClickRepeater
14234 * 2007-02-03 jvs Modifications for FF Mac and Safari
14237 * @param {String/HTMLElement/Element} el The element to listen on
14238 * @param {Object} config
14240 Roo.util.ClickRepeater = function(el, config)
14242 this.el = Roo.get(el);
14243 this.el.unselectable();
14245 Roo.apply(this, config);
14250 * Fires when the mouse button is depressed.
14251 * @param {Roo.util.ClickRepeater} this
14253 "mousedown" : true,
14256 * Fires on a specified interval during the time the element is pressed.
14257 * @param {Roo.util.ClickRepeater} this
14262 * Fires when the mouse key is released.
14263 * @param {Roo.util.ClickRepeater} this
14268 this.el.on("mousedown", this.handleMouseDown, this);
14269 if(this.preventDefault || this.stopDefault){
14270 this.el.on("click", function(e){
14271 if(this.preventDefault){
14272 e.preventDefault();
14274 if(this.stopDefault){
14280 // allow inline handler
14282 this.on("click", this.handler, this.scope || this);
14285 Roo.util.ClickRepeater.superclass.constructor.call(this);
14288 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14291 preventDefault : true,
14292 stopDefault : false,
14296 handleMouseDown : function(){
14297 clearTimeout(this.timer);
14299 if(this.pressClass){
14300 this.el.addClass(this.pressClass);
14302 this.mousedownTime = new Date();
14304 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14305 this.el.on("mouseout", this.handleMouseOut, this);
14307 this.fireEvent("mousedown", this);
14308 this.fireEvent("click", this);
14310 this.timer = this.click.defer(this.delay || this.interval, this);
14314 click : function(){
14315 this.fireEvent("click", this);
14316 this.timer = this.click.defer(this.getInterval(), this);
14320 getInterval: function(){
14321 if(!this.accelerate){
14322 return this.interval;
14324 var pressTime = this.mousedownTime.getElapsed();
14325 if(pressTime < 500){
14327 }else if(pressTime < 1700){
14329 }else if(pressTime < 2600){
14331 }else if(pressTime < 3500){
14333 }else if(pressTime < 4400){
14335 }else if(pressTime < 5300){
14337 }else if(pressTime < 6200){
14345 handleMouseOut : function(){
14346 clearTimeout(this.timer);
14347 if(this.pressClass){
14348 this.el.removeClass(this.pressClass);
14350 this.el.on("mouseover", this.handleMouseReturn, this);
14354 handleMouseReturn : function(){
14355 this.el.un("mouseover", this.handleMouseReturn);
14356 if(this.pressClass){
14357 this.el.addClass(this.pressClass);
14363 handleMouseUp : function(){
14364 clearTimeout(this.timer);
14365 this.el.un("mouseover", this.handleMouseReturn);
14366 this.el.un("mouseout", this.handleMouseOut);
14367 Roo.get(document).un("mouseup", this.handleMouseUp);
14368 this.el.removeClass(this.pressClass);
14369 this.fireEvent("mouseup", this);
14373 * Ext JS Library 1.1.1
14374 * Copyright(c) 2006-2007, Ext JS, LLC.
14376 * Originally Released Under LGPL - original licence link has changed is not relivant.
14379 * <script type="text/javascript">
14384 * @class Roo.KeyNav
14385 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14386 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14387 * way to implement custom navigation schemes for any UI component.</p>
14388 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14389 * pageUp, pageDown, del, home, end. Usage:</p>
14391 var nav = new Roo.KeyNav("my-element", {
14392 "left" : function(e){
14393 this.moveLeft(e.ctrlKey);
14395 "right" : function(e){
14396 this.moveRight(e.ctrlKey);
14398 "enter" : function(e){
14405 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14406 * @param {Object} config The config
14408 Roo.KeyNav = function(el, config){
14409 this.el = Roo.get(el);
14410 Roo.apply(this, config);
14411 if(!this.disabled){
14412 this.disabled = true;
14417 Roo.KeyNav.prototype = {
14419 * @cfg {Boolean} disabled
14420 * True to disable this KeyNav instance (defaults to false)
14424 * @cfg {String} defaultEventAction
14425 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14426 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14427 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14429 defaultEventAction: "stopEvent",
14431 * @cfg {Boolean} forceKeyDown
14432 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14433 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14434 * handle keydown instead of keypress.
14436 forceKeyDown : false,
14439 prepareEvent : function(e){
14440 var k = e.getKey();
14441 var h = this.keyToHandler[k];
14442 //if(h && this[h]){
14443 // e.stopPropagation();
14445 if(Roo.isSafari && h && k >= 37 && k <= 40){
14451 relay : function(e){
14452 var k = e.getKey();
14453 var h = this.keyToHandler[k];
14455 if(this.doRelay(e, this[h], h) !== true){
14456 e[this.defaultEventAction]();
14462 doRelay : function(e, h, hname){
14463 return h.call(this.scope || this, e);
14466 // possible handlers
14480 // quick lookup hash
14497 * Enable this KeyNav
14499 enable: function(){
14501 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14502 // the EventObject will normalize Safari automatically
14503 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14504 this.el.on("keydown", this.relay, this);
14506 this.el.on("keydown", this.prepareEvent, this);
14507 this.el.on("keypress", this.relay, this);
14509 this.disabled = false;
14514 * Disable this KeyNav
14516 disable: function(){
14517 if(!this.disabled){
14518 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14519 this.el.un("keydown", this.relay);
14521 this.el.un("keydown", this.prepareEvent);
14522 this.el.un("keypress", this.relay);
14524 this.disabled = true;
14529 * Ext JS Library 1.1.1
14530 * Copyright(c) 2006-2007, Ext JS, LLC.
14532 * Originally Released Under LGPL - original licence link has changed is not relivant.
14535 * <script type="text/javascript">
14540 * @class Roo.KeyMap
14541 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14542 * The constructor accepts the same config object as defined by {@link #addBinding}.
14543 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14544 * combination it will call the function with this signature (if the match is a multi-key
14545 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14546 * A KeyMap can also handle a string representation of keys.<br />
14549 // map one key by key code
14550 var map = new Roo.KeyMap("my-element", {
14551 key: 13, // or Roo.EventObject.ENTER
14556 // map multiple keys to one action by string
14557 var map = new Roo.KeyMap("my-element", {
14563 // map multiple keys to multiple actions by strings and array of codes
14564 var map = new Roo.KeyMap("my-element", [
14567 fn: function(){ alert("Return was pressed"); }
14570 fn: function(){ alert('a, b or c was pressed'); }
14575 fn: function(){ alert('Control + shift + tab was pressed.'); }
14579 * <b>Note: A KeyMap starts enabled</b>
14581 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14582 * @param {Object} config The config (see {@link #addBinding})
14583 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14585 Roo.KeyMap = function(el, config, eventName){
14586 this.el = Roo.get(el);
14587 this.eventName = eventName || "keydown";
14588 this.bindings = [];
14590 this.addBinding(config);
14595 Roo.KeyMap.prototype = {
14597 * True to stop the event from bubbling and prevent the default browser action if the
14598 * key was handled by the KeyMap (defaults to false)
14604 * Add a new binding to this KeyMap. The following config object properties are supported:
14606 Property Type Description
14607 ---------- --------------- ----------------------------------------------------------------------
14608 key String/Array A single keycode or an array of keycodes to handle
14609 shift Boolean True to handle key only when shift is pressed (defaults to false)
14610 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14611 alt Boolean True to handle key only when alt is pressed (defaults to false)
14612 fn Function The function to call when KeyMap finds the expected key combination
14613 scope Object The scope of the callback function
14619 var map = new Roo.KeyMap(document, {
14620 key: Roo.EventObject.ENTER,
14625 //Add a new binding to the existing KeyMap later
14633 * @param {Object/Array} config A single KeyMap config or an array of configs
14635 addBinding : function(config){
14636 if(config instanceof Array){
14637 for(var i = 0, len = config.length; i < len; i++){
14638 this.addBinding(config[i]);
14642 var keyCode = config.key,
14643 shift = config.shift,
14644 ctrl = config.ctrl,
14647 scope = config.scope;
14648 if(typeof keyCode == "string"){
14650 var keyString = keyCode.toUpperCase();
14651 for(var j = 0, len = keyString.length; j < len; j++){
14652 ks.push(keyString.charCodeAt(j));
14656 var keyArray = keyCode instanceof Array;
14657 var handler = function(e){
14658 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14659 var k = e.getKey();
14661 for(var i = 0, len = keyCode.length; i < len; i++){
14662 if(keyCode[i] == k){
14663 if(this.stopEvent){
14666 fn.call(scope || window, k, e);
14672 if(this.stopEvent){
14675 fn.call(scope || window, k, e);
14680 this.bindings.push(handler);
14684 * Shorthand for adding a single key listener
14685 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14686 * following options:
14687 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14688 * @param {Function} fn The function to call
14689 * @param {Object} scope (optional) The scope of the function
14691 on : function(key, fn, scope){
14692 var keyCode, shift, ctrl, alt;
14693 if(typeof key == "object" && !(key instanceof Array)){
14712 handleKeyDown : function(e){
14713 if(this.enabled){ //just in case
14714 var b = this.bindings;
14715 for(var i = 0, len = b.length; i < len; i++){
14716 b[i].call(this, e);
14722 * Returns true if this KeyMap is enabled
14723 * @return {Boolean}
14725 isEnabled : function(){
14726 return this.enabled;
14730 * Enables this KeyMap
14732 enable: function(){
14734 this.el.on(this.eventName, this.handleKeyDown, this);
14735 this.enabled = true;
14740 * Disable this KeyMap
14742 disable: function(){
14744 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14745 this.enabled = false;
14750 * Ext JS Library 1.1.1
14751 * Copyright(c) 2006-2007, Ext JS, LLC.
14753 * Originally Released Under LGPL - original licence link has changed is not relivant.
14756 * <script type="text/javascript">
14761 * @class Roo.util.TextMetrics
14762 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14763 * wide, in pixels, a given block of text will be.
14766 Roo.util.TextMetrics = function(){
14770 * Measures the size of the specified text
14771 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14772 * that can affect the size of the rendered text
14773 * @param {String} text The text to measure
14774 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14775 * in order to accurately measure the text height
14776 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14778 measure : function(el, text, fixedWidth){
14780 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14783 shared.setFixedWidth(fixedWidth || 'auto');
14784 return shared.getSize(text);
14788 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14789 * the overhead of multiple calls to initialize the style properties on each measurement.
14790 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14791 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14792 * in order to accurately measure the text height
14793 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14795 createInstance : function(el, fixedWidth){
14796 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14803 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14804 var ml = new Roo.Element(document.createElement('div'));
14805 document.body.appendChild(ml.dom);
14806 ml.position('absolute');
14807 ml.setLeftTop(-1000, -1000);
14811 ml.setWidth(fixedWidth);
14816 * Returns the size of the specified text based on the internal element's style and width properties
14817 * @memberOf Roo.util.TextMetrics.Instance#
14818 * @param {String} text The text to measure
14819 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14821 getSize : function(text){
14823 var s = ml.getSize();
14829 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14830 * that can affect the size of the rendered text
14831 * @memberOf Roo.util.TextMetrics.Instance#
14832 * @param {String/HTMLElement} el The element, dom node or id
14834 bind : function(el){
14836 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14841 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14842 * to set a fixed width in order to accurately measure the text height.
14843 * @memberOf Roo.util.TextMetrics.Instance#
14844 * @param {Number} width The width to set on the element
14846 setFixedWidth : function(width){
14847 ml.setWidth(width);
14851 * Returns the measured width of the specified text
14852 * @memberOf Roo.util.TextMetrics.Instance#
14853 * @param {String} text The text to measure
14854 * @return {Number} width The width in pixels
14856 getWidth : function(text){
14857 ml.dom.style.width = 'auto';
14858 return this.getSize(text).width;
14862 * Returns the measured height of the specified text. For multiline text, be sure to call
14863 * {@link #setFixedWidth} if necessary.
14864 * @memberOf Roo.util.TextMetrics.Instance#
14865 * @param {String} text The text to measure
14866 * @return {Number} height The height in pixels
14868 getHeight : function(text){
14869 return this.getSize(text).height;
14873 instance.bind(bindTo);
14878 // backwards compat
14879 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14881 * Ext JS Library 1.1.1
14882 * Copyright(c) 2006-2007, Ext JS, LLC.
14884 * Originally Released Under LGPL - original licence link has changed is not relivant.
14887 * <script type="text/javascript">
14891 * @class Roo.state.Provider
14892 * Abstract base class for state provider implementations. This class provides methods
14893 * for encoding and decoding <b>typed</b> variables including dates and defines the
14894 * Provider interface.
14896 Roo.state.Provider = function(){
14898 * @event statechange
14899 * Fires when a state change occurs.
14900 * @param {Provider} this This state provider
14901 * @param {String} key The state key which was changed
14902 * @param {String} value The encoded value for the state
14905 "statechange": true
14908 Roo.state.Provider.superclass.constructor.call(this);
14910 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14912 * Returns the current value for a key
14913 * @param {String} name The key name
14914 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14915 * @return {Mixed} The state data
14917 get : function(name, defaultValue){
14918 return typeof this.state[name] == "undefined" ?
14919 defaultValue : this.state[name];
14923 * Clears a value from the state
14924 * @param {String} name The key name
14926 clear : function(name){
14927 delete this.state[name];
14928 this.fireEvent("statechange", this, name, null);
14932 * Sets the value for a key
14933 * @param {String} name The key name
14934 * @param {Mixed} value The value to set
14936 set : function(name, value){
14937 this.state[name] = value;
14938 this.fireEvent("statechange", this, name, value);
14942 * Decodes a string previously encoded with {@link #encodeValue}.
14943 * @param {String} value The value to decode
14944 * @return {Mixed} The decoded value
14946 decodeValue : function(cookie){
14947 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14948 var matches = re.exec(unescape(cookie));
14949 if(!matches || !matches[1]) {
14950 return; // non state cookie
14952 var type = matches[1];
14953 var v = matches[2];
14956 return parseFloat(v);
14958 return new Date(Date.parse(v));
14963 var values = v.split("^");
14964 for(var i = 0, len = values.length; i < len; i++){
14965 all.push(this.decodeValue(values[i]));
14970 var values = v.split("^");
14971 for(var i = 0, len = values.length; i < len; i++){
14972 var kv = values[i].split("=");
14973 all[kv[0]] = this.decodeValue(kv[1]);
14982 * Encodes a value including type information. Decode with {@link #decodeValue}.
14983 * @param {Mixed} value The value to encode
14984 * @return {String} The encoded value
14986 encodeValue : function(v){
14988 if(typeof v == "number"){
14990 }else if(typeof v == "boolean"){
14991 enc = "b:" + (v ? "1" : "0");
14992 }else if(v instanceof Date){
14993 enc = "d:" + v.toGMTString();
14994 }else if(v instanceof Array){
14996 for(var i = 0, len = v.length; i < len; i++){
14997 flat += this.encodeValue(v[i]);
15003 }else if(typeof v == "object"){
15006 if(typeof v[key] != "function"){
15007 flat += key + "=" + this.encodeValue(v[key]) + "^";
15010 enc = "o:" + flat.substring(0, flat.length-1);
15014 return escape(enc);
15020 * Ext JS Library 1.1.1
15021 * Copyright(c) 2006-2007, Ext JS, LLC.
15023 * Originally Released Under LGPL - original licence link has changed is not relivant.
15026 * <script type="text/javascript">
15029 * @class Roo.state.Manager
15030 * This is the global state manager. By default all components that are "state aware" check this class
15031 * for state information if you don't pass them a custom state provider. In order for this class
15032 * to be useful, it must be initialized with a provider when your application initializes.
15034 // in your initialization function
15036 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15038 // supposed you have a {@link Roo.BorderLayout}
15039 var layout = new Roo.BorderLayout(...);
15040 layout.restoreState();
15041 // or a {Roo.BasicDialog}
15042 var dialog = new Roo.BasicDialog(...);
15043 dialog.restoreState();
15047 Roo.state.Manager = function(){
15048 var provider = new Roo.state.Provider();
15052 * Configures the default state provider for your application
15053 * @param {Provider} stateProvider The state provider to set
15055 setProvider : function(stateProvider){
15056 provider = stateProvider;
15060 * Returns the current value for a key
15061 * @param {String} name The key name
15062 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15063 * @return {Mixed} The state data
15065 get : function(key, defaultValue){
15066 return provider.get(key, defaultValue);
15070 * Sets the value for a key
15071 * @param {String} name The key name
15072 * @param {Mixed} value The state data
15074 set : function(key, value){
15075 provider.set(key, value);
15079 * Clears a value from the state
15080 * @param {String} name The key name
15082 clear : function(key){
15083 provider.clear(key);
15087 * Gets the currently configured state provider
15088 * @return {Provider} The state provider
15090 getProvider : function(){
15097 * Ext JS Library 1.1.1
15098 * Copyright(c) 2006-2007, Ext JS, LLC.
15100 * Originally Released Under LGPL - original licence link has changed is not relivant.
15103 * <script type="text/javascript">
15106 * @class Roo.state.CookieProvider
15107 * @extends Roo.state.Provider
15108 * The default Provider implementation which saves state via cookies.
15111 var cp = new Roo.state.CookieProvider({
15113 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15114 domain: "roojs.com"
15116 Roo.state.Manager.setProvider(cp);
15118 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15119 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15120 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15121 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15122 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15123 * domain the page is running on including the 'www' like 'www.roojs.com')
15124 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15126 * Create a new CookieProvider
15127 * @param {Object} config The configuration object
15129 Roo.state.CookieProvider = function(config){
15130 Roo.state.CookieProvider.superclass.constructor.call(this);
15132 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15133 this.domain = null;
15134 this.secure = false;
15135 Roo.apply(this, config);
15136 this.state = this.readCookies();
15139 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15141 set : function(name, value){
15142 if(typeof value == "undefined" || value === null){
15146 this.setCookie(name, value);
15147 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15151 clear : function(name){
15152 this.clearCookie(name);
15153 Roo.state.CookieProvider.superclass.clear.call(this, name);
15157 readCookies : function(){
15159 var c = document.cookie + ";";
15160 var re = /\s?(.*?)=(.*?);/g;
15162 while((matches = re.exec(c)) != null){
15163 var name = matches[1];
15164 var value = matches[2];
15165 if(name && name.substring(0,3) == "ys-"){
15166 cookies[name.substr(3)] = this.decodeValue(value);
15173 setCookie : function(name, value){
15174 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15175 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15176 ((this.path == null) ? "" : ("; path=" + this.path)) +
15177 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15178 ((this.secure == true) ? "; secure" : "");
15182 clearCookie : function(name){
15183 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15184 ((this.path == null) ? "" : ("; path=" + this.path)) +
15185 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15186 ((this.secure == true) ? "; secure" : "");
15190 * Ext JS Library 1.1.1
15191 * Copyright(c) 2006-2007, Ext JS, LLC.
15193 * Originally Released Under LGPL - original licence link has changed is not relivant.
15196 * <script type="text/javascript">
15201 * @class Roo.ComponentMgr
15202 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15205 Roo.ComponentMgr = function(){
15206 var all = new Roo.util.MixedCollection();
15210 * Registers a component.
15211 * @param {Roo.Component} c The component
15213 register : function(c){
15218 * Unregisters a component.
15219 * @param {Roo.Component} c The component
15221 unregister : function(c){
15226 * Returns a component by id
15227 * @param {String} id The component id
15229 get : function(id){
15230 return all.get(id);
15234 * Registers a function that will be called when a specified component is added to ComponentMgr
15235 * @param {String} id The component id
15236 * @param {Funtction} fn The callback function
15237 * @param {Object} scope The scope of the callback
15239 onAvailable : function(id, fn, scope){
15240 all.on("add", function(index, o){
15242 fn.call(scope || o, o);
15243 all.un("add", fn, scope);
15250 * Ext JS Library 1.1.1
15251 * Copyright(c) 2006-2007, Ext JS, LLC.
15253 * Originally Released Under LGPL - original licence link has changed is not relivant.
15256 * <script type="text/javascript">
15260 * @class Roo.Component
15261 * @extends Roo.util.Observable
15262 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15263 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15264 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15265 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15266 * All visual components (widgets) that require rendering into a layout should subclass Component.
15268 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15269 * 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
15270 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15272 Roo.Component = function(config){
15273 config = config || {};
15274 if(config.tagName || config.dom || typeof config == "string"){ // element object
15275 config = {el: config, id: config.id || config};
15277 this.initialConfig = config;
15279 Roo.apply(this, config);
15283 * Fires after the component is disabled.
15284 * @param {Roo.Component} this
15289 * Fires after the component is enabled.
15290 * @param {Roo.Component} this
15294 * @event beforeshow
15295 * Fires before the component is shown. Return false to stop the show.
15296 * @param {Roo.Component} this
15301 * Fires after the component is shown.
15302 * @param {Roo.Component} this
15306 * @event beforehide
15307 * Fires before the component is hidden. Return false to stop the hide.
15308 * @param {Roo.Component} this
15313 * Fires after the component is hidden.
15314 * @param {Roo.Component} this
15318 * @event beforerender
15319 * Fires before the component is rendered. Return false to stop the render.
15320 * @param {Roo.Component} this
15322 beforerender : true,
15325 * Fires after the component is rendered.
15326 * @param {Roo.Component} this
15330 * @event beforedestroy
15331 * Fires before the component is destroyed. Return false to stop the destroy.
15332 * @param {Roo.Component} this
15334 beforedestroy : true,
15337 * Fires after the component is destroyed.
15338 * @param {Roo.Component} this
15343 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15345 Roo.ComponentMgr.register(this);
15346 Roo.Component.superclass.constructor.call(this);
15347 this.initComponent();
15348 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15349 this.render(this.renderTo);
15350 delete this.renderTo;
15355 Roo.Component.AUTO_ID = 1000;
15357 Roo.extend(Roo.Component, Roo.util.Observable, {
15359 * @scope Roo.Component.prototype
15361 * true if this component is hidden. Read-only.
15366 * true if this component is disabled. Read-only.
15371 * true if this component has been rendered. Read-only.
15375 /** @cfg {String} disableClass
15376 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15378 disabledClass : "x-item-disabled",
15379 /** @cfg {Boolean} allowDomMove
15380 * Whether the component can move the Dom node when rendering (defaults to true).
15382 allowDomMove : true,
15383 /** @cfg {String} hideMode (display|visibility)
15384 * How this component should hidden. Supported values are
15385 * "visibility" (css visibility), "offsets" (negative offset position) and
15386 * "display" (css display) - defaults to "display".
15388 hideMode: 'display',
15391 ctype : "Roo.Component",
15394 * @cfg {String} actionMode
15395 * which property holds the element that used for hide() / show() / disable() / enable()
15401 getActionEl : function(){
15402 return this[this.actionMode];
15405 initComponent : Roo.emptyFn,
15407 * If this is a lazy rendering component, render it to its container element.
15408 * @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.
15410 render : function(container, position){
15416 if(this.fireEvent("beforerender", this) === false){
15420 if(!container && this.el){
15421 this.el = Roo.get(this.el);
15422 container = this.el.dom.parentNode;
15423 this.allowDomMove = false;
15425 this.container = Roo.get(container);
15426 this.rendered = true;
15427 if(position !== undefined){
15428 if(typeof position == 'number'){
15429 position = this.container.dom.childNodes[position];
15431 position = Roo.getDom(position);
15434 this.onRender(this.container, position || null);
15436 this.el.addClass(this.cls);
15440 this.el.applyStyles(this.style);
15443 this.fireEvent("render", this);
15444 this.afterRender(this.container);
15457 // default function is not really useful
15458 onRender : function(ct, position){
15460 this.el = Roo.get(this.el);
15461 if(this.allowDomMove !== false){
15462 ct.dom.insertBefore(this.el.dom, position);
15468 getAutoCreate : function(){
15469 var cfg = typeof this.autoCreate == "object" ?
15470 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15471 if(this.id && !cfg.id){
15478 afterRender : Roo.emptyFn,
15481 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15482 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15484 destroy : function(){
15485 if(this.fireEvent("beforedestroy", this) !== false){
15486 this.purgeListeners();
15487 this.beforeDestroy();
15489 this.el.removeAllListeners();
15491 if(this.actionMode == "container"){
15492 this.container.remove();
15496 Roo.ComponentMgr.unregister(this);
15497 this.fireEvent("destroy", this);
15502 beforeDestroy : function(){
15507 onDestroy : function(){
15512 * Returns the underlying {@link Roo.Element}.
15513 * @return {Roo.Element} The element
15515 getEl : function(){
15520 * Returns the id of this component.
15523 getId : function(){
15528 * Try to focus this component.
15529 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15530 * @return {Roo.Component} this
15532 focus : function(selectText){
15535 if(selectText === true){
15536 this.el.dom.select();
15551 * Disable this component.
15552 * @return {Roo.Component} this
15554 disable : function(){
15558 this.disabled = true;
15559 this.fireEvent("disable", this);
15564 onDisable : function(){
15565 this.getActionEl().addClass(this.disabledClass);
15566 this.el.dom.disabled = true;
15570 * Enable this component.
15571 * @return {Roo.Component} this
15573 enable : function(){
15577 this.disabled = false;
15578 this.fireEvent("enable", this);
15583 onEnable : function(){
15584 this.getActionEl().removeClass(this.disabledClass);
15585 this.el.dom.disabled = false;
15589 * Convenience function for setting disabled/enabled by boolean.
15590 * @param {Boolean} disabled
15592 setDisabled : function(disabled){
15593 this[disabled ? "disable" : "enable"]();
15597 * Show this component.
15598 * @return {Roo.Component} this
15601 if(this.fireEvent("beforeshow", this) !== false){
15602 this.hidden = false;
15606 this.fireEvent("show", this);
15612 onShow : function(){
15613 var ae = this.getActionEl();
15614 if(this.hideMode == 'visibility'){
15615 ae.dom.style.visibility = "visible";
15616 }else if(this.hideMode == 'offsets'){
15617 ae.removeClass('x-hidden');
15619 ae.dom.style.display = "";
15624 * Hide this component.
15625 * @return {Roo.Component} this
15628 if(this.fireEvent("beforehide", this) !== false){
15629 this.hidden = true;
15633 this.fireEvent("hide", this);
15639 onHide : function(){
15640 var ae = this.getActionEl();
15641 if(this.hideMode == 'visibility'){
15642 ae.dom.style.visibility = "hidden";
15643 }else if(this.hideMode == 'offsets'){
15644 ae.addClass('x-hidden');
15646 ae.dom.style.display = "none";
15651 * Convenience function to hide or show this component by boolean.
15652 * @param {Boolean} visible True to show, false to hide
15653 * @return {Roo.Component} this
15655 setVisible: function(visible){
15665 * Returns true if this component is visible.
15667 isVisible : function(){
15668 return this.getActionEl().isVisible();
15671 cloneConfig : function(overrides){
15672 overrides = overrides || {};
15673 var id = overrides.id || Roo.id();
15674 var cfg = Roo.applyIf(overrides, this.initialConfig);
15675 cfg.id = id; // prevent dup id
15676 return new this.constructor(cfg);
15680 * Ext JS Library 1.1.1
15681 * Copyright(c) 2006-2007, Ext JS, LLC.
15683 * Originally Released Under LGPL - original licence link has changed is not relivant.
15686 * <script type="text/javascript">
15690 * @class Roo.BoxComponent
15691 * @extends Roo.Component
15692 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15693 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15694 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15695 * layout containers.
15697 * @param {Roo.Element/String/Object} config The configuration options.
15699 Roo.BoxComponent = function(config){
15700 Roo.Component.call(this, config);
15704 * Fires after the component is resized.
15705 * @param {Roo.Component} this
15706 * @param {Number} adjWidth The box-adjusted width that was set
15707 * @param {Number} adjHeight The box-adjusted height that was set
15708 * @param {Number} rawWidth The width that was originally specified
15709 * @param {Number} rawHeight The height that was originally specified
15714 * Fires after the component is moved.
15715 * @param {Roo.Component} this
15716 * @param {Number} x The new x position
15717 * @param {Number} y The new y position
15723 Roo.extend(Roo.BoxComponent, Roo.Component, {
15724 // private, set in afterRender to signify that the component has been rendered
15726 // private, used to defer height settings to subclasses
15727 deferHeight: false,
15728 /** @cfg {Number} width
15729 * width (optional) size of component
15731 /** @cfg {Number} height
15732 * height (optional) size of component
15736 * Sets the width and height of the component. This method fires the resize event. This method can accept
15737 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15738 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15739 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15740 * @return {Roo.BoxComponent} this
15742 setSize : function(w, h){
15743 // support for standard size objects
15744 if(typeof w == 'object'){
15749 if(!this.boxReady){
15755 // prevent recalcs when not needed
15756 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15759 this.lastSize = {width: w, height: h};
15761 var adj = this.adjustSize(w, h);
15762 var aw = adj.width, ah = adj.height;
15763 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15764 var rz = this.getResizeEl();
15765 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15766 rz.setSize(aw, ah);
15767 }else if(!this.deferHeight && ah !== undefined){
15769 }else if(aw !== undefined){
15772 this.onResize(aw, ah, w, h);
15773 this.fireEvent('resize', this, aw, ah, w, h);
15779 * Gets the current size of the component's underlying element.
15780 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15782 getSize : function(){
15783 return this.el.getSize();
15787 * Gets the current XY position of the component's underlying element.
15788 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15789 * @return {Array} The XY position of the element (e.g., [100, 200])
15791 getPosition : function(local){
15792 if(local === true){
15793 return [this.el.getLeft(true), this.el.getTop(true)];
15795 return this.xy || this.el.getXY();
15799 * Gets the current box measurements of the component's underlying element.
15800 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15801 * @returns {Object} box An object in the format {x, y, width, height}
15803 getBox : function(local){
15804 var s = this.el.getSize();
15806 s.x = this.el.getLeft(true);
15807 s.y = this.el.getTop(true);
15809 var xy = this.xy || this.el.getXY();
15817 * Sets the current box measurements of the component's underlying element.
15818 * @param {Object} box An object in the format {x, y, width, height}
15819 * @returns {Roo.BoxComponent} this
15821 updateBox : function(box){
15822 this.setSize(box.width, box.height);
15823 this.setPagePosition(box.x, box.y);
15828 getResizeEl : function(){
15829 return this.resizeEl || this.el;
15833 getPositionEl : function(){
15834 return this.positionEl || this.el;
15838 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15839 * This method fires the move event.
15840 * @param {Number} left The new left
15841 * @param {Number} top The new top
15842 * @returns {Roo.BoxComponent} this
15844 setPosition : function(x, y){
15847 if(!this.boxReady){
15850 var adj = this.adjustPosition(x, y);
15851 var ax = adj.x, ay = adj.y;
15853 var el = this.getPositionEl();
15854 if(ax !== undefined || ay !== undefined){
15855 if(ax !== undefined && ay !== undefined){
15856 el.setLeftTop(ax, ay);
15857 }else if(ax !== undefined){
15859 }else if(ay !== undefined){
15862 this.onPosition(ax, ay);
15863 this.fireEvent('move', this, ax, ay);
15869 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15870 * This method fires the move event.
15871 * @param {Number} x The new x position
15872 * @param {Number} y The new y position
15873 * @returns {Roo.BoxComponent} this
15875 setPagePosition : function(x, y){
15878 if(!this.boxReady){
15881 if(x === undefined || y === undefined){ // cannot translate undefined points
15884 var p = this.el.translatePoints(x, y);
15885 this.setPosition(p.left, p.top);
15890 onRender : function(ct, position){
15891 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15893 this.resizeEl = Roo.get(this.resizeEl);
15895 if(this.positionEl){
15896 this.positionEl = Roo.get(this.positionEl);
15901 afterRender : function(){
15902 Roo.BoxComponent.superclass.afterRender.call(this);
15903 this.boxReady = true;
15904 this.setSize(this.width, this.height);
15905 if(this.x || this.y){
15906 this.setPosition(this.x, this.y);
15908 if(this.pageX || this.pageY){
15909 this.setPagePosition(this.pageX, this.pageY);
15914 * Force the component's size to recalculate based on the underlying element's current height and width.
15915 * @returns {Roo.BoxComponent} this
15917 syncSize : function(){
15918 delete this.lastSize;
15919 this.setSize(this.el.getWidth(), this.el.getHeight());
15924 * Called after the component is resized, this method is empty by default but can be implemented by any
15925 * subclass that needs to perform custom logic after a resize occurs.
15926 * @param {Number} adjWidth The box-adjusted width that was set
15927 * @param {Number} adjHeight The box-adjusted height that was set
15928 * @param {Number} rawWidth The width that was originally specified
15929 * @param {Number} rawHeight The height that was originally specified
15931 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15936 * Called after the component is moved, this method is empty by default but can be implemented by any
15937 * subclass that needs to perform custom logic after a move occurs.
15938 * @param {Number} x The new x position
15939 * @param {Number} y The new y position
15941 onPosition : function(x, y){
15946 adjustSize : function(w, h){
15947 if(this.autoWidth){
15950 if(this.autoHeight){
15953 return {width : w, height: h};
15957 adjustPosition : function(x, y){
15958 return {x : x, y: y};
15961 * Original code for Roojs - LGPL
15962 * <script type="text/javascript">
15966 * @class Roo.XComponent
15967 * A delayed Element creator...
15968 * Or a way to group chunks of interface together.
15969 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15970 * used in conjunction with XComponent.build() it will create an instance of each element,
15971 * then call addxtype() to build the User interface.
15973 * Mypart.xyx = new Roo.XComponent({
15975 parent : 'Mypart.xyz', // empty == document.element.!!
15979 disabled : function() {}
15981 tree : function() { // return an tree of xtype declared components
15985 xtype : 'NestedLayoutPanel',
15992 * It can be used to build a big heiracy, with parent etc.
15993 * or you can just use this to render a single compoent to a dom element
15994 * MYPART.render(Roo.Element | String(id) | dom_element )
16001 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16002 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16004 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16006 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16007 * - if mulitple topModules exist, the last one is defined as the top module.
16011 * When the top level or multiple modules are to embedded into a existing HTML page,
16012 * the parent element can container '#id' of the element where the module will be drawn.
16016 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16017 * it relies more on a include mechanism, where sub modules are included into an outer page.
16018 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16020 * Bootstrap Roo Included elements
16022 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16023 * hence confusing the component builder as it thinks there are multiple top level elements.
16025 * String Over-ride & Translations
16027 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16028 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16029 * are needed. @see Roo.XComponent.overlayString
16033 * @extends Roo.util.Observable
16035 * @param cfg {Object} configuration of component
16038 Roo.XComponent = function(cfg) {
16039 Roo.apply(this, cfg);
16043 * Fires when this the componnt is built
16044 * @param {Roo.XComponent} c the component
16049 this.region = this.region || 'center'; // default..
16050 Roo.XComponent.register(this);
16051 this.modules = false;
16052 this.el = false; // where the layout goes..
16056 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16059 * The created element (with Roo.factory())
16060 * @type {Roo.Layout}
16066 * for BC - use el in new code
16067 * @type {Roo.Layout}
16073 * for BC - use el in new code
16074 * @type {Roo.Layout}
16079 * @cfg {Function|boolean} disabled
16080 * If this module is disabled by some rule, return true from the funtion
16085 * @cfg {String} parent
16086 * Name of parent element which it get xtype added to..
16091 * @cfg {String} order
16092 * Used to set the order in which elements are created (usefull for multiple tabs)
16097 * @cfg {String} name
16098 * String to display while loading.
16102 * @cfg {String} region
16103 * Region to render component to (defaults to center)
16108 * @cfg {Array} items
16109 * A single item array - the first element is the root of the tree..
16110 * It's done this way to stay compatible with the Xtype system...
16116 * The method that retuns the tree of parts that make up this compoennt
16123 * render element to dom or tree
16124 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16127 render : function(el)
16131 var hp = this.parent ? 1 : 0;
16132 Roo.debug && Roo.log(this);
16134 var tree = this._tree ? this._tree() : this.tree();
16137 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16138 // if parent is a '#.....' string, then let's use that..
16139 var ename = this.parent.substr(1);
16140 this.parent = false;
16141 Roo.debug && Roo.log(ename);
16143 case 'bootstrap-body':
16144 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16145 // this is the BorderLayout standard?
16146 this.parent = { el : true };
16149 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16150 // need to insert stuff...
16152 el : new Roo.bootstrap.layout.Border({
16153 el : document.body,
16159 tabPosition: 'top',
16160 //resizeTabs: true,
16161 alwaysShowTabs: true,
16171 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16172 this.parent = { el : new Roo.bootstrap.Body() };
16173 Roo.debug && Roo.log("setting el to doc body");
16176 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16180 this.parent = { el : true};
16183 el = Roo.get(ename);
16184 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16185 this.parent = { el : true};
16192 if (!el && !this.parent) {
16193 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16198 Roo.debug && Roo.log("EL:");
16199 Roo.debug && Roo.log(el);
16200 Roo.debug && Roo.log("this.parent.el:");
16201 Roo.debug && Roo.log(this.parent.el);
16204 // altertive root elements ??? - we need a better way to indicate these.
16205 var is_alt = Roo.XComponent.is_alt ||
16206 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16207 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16208 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16212 if (!this.parent && is_alt) {
16213 //el = Roo.get(document.body);
16214 this.parent = { el : true };
16219 if (!this.parent) {
16221 Roo.debug && Roo.log("no parent - creating one");
16223 el = el ? Roo.get(el) : false;
16225 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16228 el : new Roo.bootstrap.layout.Border({
16229 el: el || document.body,
16235 tabPosition: 'top',
16236 //resizeTabs: true,
16237 alwaysShowTabs: false,
16240 overflow: 'visible'
16246 // it's a top level one..
16248 el : new Roo.BorderLayout(el || document.body, {
16253 tabPosition: 'top',
16254 //resizeTabs: true,
16255 alwaysShowTabs: el && hp? false : true,
16256 hideTabs: el || !hp ? true : false,
16264 if (!this.parent.el) {
16265 // probably an old style ctor, which has been disabled.
16269 // The 'tree' method is '_tree now'
16271 tree.region = tree.region || this.region;
16272 var is_body = false;
16273 if (this.parent.el === true) {
16274 // bootstrap... - body..
16278 this.parent.el = Roo.factory(tree);
16282 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16283 this.fireEvent('built', this);
16285 this.panel = this.el;
16286 this.layout = this.panel.layout;
16287 this.parentLayout = this.parent.layout || false;
16293 Roo.apply(Roo.XComponent, {
16295 * @property hideProgress
16296 * true to disable the building progress bar.. usefull on single page renders.
16299 hideProgress : false,
16301 * @property buildCompleted
16302 * True when the builder has completed building the interface.
16305 buildCompleted : false,
16308 * @property topModule
16309 * the upper most module - uses document.element as it's constructor.
16316 * @property modules
16317 * array of modules to be created by registration system.
16318 * @type {Array} of Roo.XComponent
16323 * @property elmodules
16324 * array of modules to be created by which use #ID
16325 * @type {Array} of Roo.XComponent
16332 * Is an alternative Root - normally used by bootstrap or other systems,
16333 * where the top element in the tree can wrap 'body'
16334 * @type {boolean} (default false)
16339 * @property build_from_html
16340 * Build elements from html - used by bootstrap HTML stuff
16341 * - this is cleared after build is completed
16342 * @type {boolean} (default false)
16345 build_from_html : false,
16347 * Register components to be built later.
16349 * This solves the following issues
16350 * - Building is not done on page load, but after an authentication process has occured.
16351 * - Interface elements are registered on page load
16352 * - Parent Interface elements may not be loaded before child, so this handles that..
16359 module : 'Pman.Tab.projectMgr',
16361 parent : 'Pman.layout',
16362 disabled : false, // or use a function..
16365 * * @param {Object} details about module
16367 register : function(obj) {
16369 Roo.XComponent.event.fireEvent('register', obj);
16370 switch(typeof(obj.disabled) ) {
16376 if ( obj.disabled() ) {
16382 if (obj.disabled) {
16388 this.modules.push(obj);
16392 * convert a string to an object..
16393 * eg. 'AAA.BBB' -> finds AAA.BBB
16397 toObject : function(str)
16399 if (!str || typeof(str) == 'object') {
16402 if (str.substring(0,1) == '#') {
16406 var ar = str.split('.');
16411 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16413 throw "Module not found : " + str;
16417 throw "Module not found : " + str;
16419 Roo.each(ar, function(e) {
16420 if (typeof(o[e]) == 'undefined') {
16421 throw "Module not found : " + str;
16432 * move modules into their correct place in the tree..
16435 preBuild : function ()
16438 Roo.each(this.modules , function (obj)
16440 Roo.XComponent.event.fireEvent('beforebuild', obj);
16442 var opar = obj.parent;
16444 obj.parent = this.toObject(opar);
16446 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16451 Roo.debug && Roo.log("GOT top level module");
16452 Roo.debug && Roo.log(obj);
16453 obj.modules = new Roo.util.MixedCollection(false,
16454 function(o) { return o.order + '' }
16456 this.topModule = obj;
16459 // parent is a string (usually a dom element name..)
16460 if (typeof(obj.parent) == 'string') {
16461 this.elmodules.push(obj);
16464 if (obj.parent.constructor != Roo.XComponent) {
16465 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16467 if (!obj.parent.modules) {
16468 obj.parent.modules = new Roo.util.MixedCollection(false,
16469 function(o) { return o.order + '' }
16472 if (obj.parent.disabled) {
16473 obj.disabled = true;
16475 obj.parent.modules.add(obj);
16480 * make a list of modules to build.
16481 * @return {Array} list of modules.
16484 buildOrder : function()
16487 var cmp = function(a,b) {
16488 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16490 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16491 throw "No top level modules to build";
16494 // make a flat list in order of modules to build.
16495 var mods = this.topModule ? [ this.topModule ] : [];
16498 // elmodules (is a list of DOM based modules )
16499 Roo.each(this.elmodules, function(e) {
16501 if (!this.topModule &&
16502 typeof(e.parent) == 'string' &&
16503 e.parent.substring(0,1) == '#' &&
16504 Roo.get(e.parent.substr(1))
16507 _this.topModule = e;
16513 // add modules to their parents..
16514 var addMod = function(m) {
16515 Roo.debug && Roo.log("build Order: add: " + m.name);
16518 if (m.modules && !m.disabled) {
16519 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16520 m.modules.keySort('ASC', cmp );
16521 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16523 m.modules.each(addMod);
16525 Roo.debug && Roo.log("build Order: no child modules");
16527 // not sure if this is used any more..
16529 m.finalize.name = m.name + " (clean up) ";
16530 mods.push(m.finalize);
16534 if (this.topModule && this.topModule.modules) {
16535 this.topModule.modules.keySort('ASC', cmp );
16536 this.topModule.modules.each(addMod);
16542 * Build the registered modules.
16543 * @param {Object} parent element.
16544 * @param {Function} optional method to call after module has been added.
16548 build : function(opts)
16551 if (typeof(opts) != 'undefined') {
16552 Roo.apply(this,opts);
16556 var mods = this.buildOrder();
16558 //this.allmods = mods;
16559 //Roo.debug && Roo.log(mods);
16561 if (!mods.length) { // should not happen
16562 throw "NO modules!!!";
16566 var msg = "Building Interface...";
16567 // flash it up as modal - so we store the mask!?
16568 if (!this.hideProgress && Roo.MessageBox) {
16569 Roo.MessageBox.show({ title: 'loading' });
16570 Roo.MessageBox.show({
16571 title: "Please wait...",
16580 var total = mods.length;
16583 var progressRun = function() {
16584 if (!mods.length) {
16585 Roo.debug && Roo.log('hide?');
16586 if (!this.hideProgress && Roo.MessageBox) {
16587 Roo.MessageBox.hide();
16589 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16591 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16597 var m = mods.shift();
16600 Roo.debug && Roo.log(m);
16601 // not sure if this is supported any more.. - modules that are are just function
16602 if (typeof(m) == 'function') {
16604 return progressRun.defer(10, _this);
16608 msg = "Building Interface " + (total - mods.length) +
16610 (m.name ? (' - ' + m.name) : '');
16611 Roo.debug && Roo.log(msg);
16612 if (!_this.hideProgress && Roo.MessageBox) {
16613 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16617 // is the module disabled?
16618 var disabled = (typeof(m.disabled) == 'function') ?
16619 m.disabled.call(m.module.disabled) : m.disabled;
16623 return progressRun(); // we do not update the display!
16631 // it's 10 on top level, and 1 on others??? why...
16632 return progressRun.defer(10, _this);
16635 progressRun.defer(1, _this);
16641 * Overlay a set of modified strings onto a component
16642 * This is dependant on our builder exporting the strings and 'named strings' elements.
16644 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16645 * @param {Object} associative array of 'named' string and it's new value.
16648 overlayStrings : function( component, strings )
16650 if (typeof(component['_named_strings']) == 'undefined') {
16651 throw "ERROR: component does not have _named_strings";
16653 for ( var k in strings ) {
16654 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16655 if (md !== false) {
16656 component['_strings'][md] = strings[k];
16658 Roo.log('could not find named string: ' + k + ' in');
16659 Roo.log(component);
16674 * wrapper for event.on - aliased later..
16675 * Typically use to register a event handler for register:
16677 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16686 Roo.XComponent.event = new Roo.util.Observable({
16690 * Fires when an Component is registered,
16691 * set the disable property on the Component to stop registration.
16692 * @param {Roo.XComponent} c the component being registerd.
16697 * @event beforebuild
16698 * Fires before each Component is built
16699 * can be used to apply permissions.
16700 * @param {Roo.XComponent} c the component being registerd.
16703 'beforebuild' : true,
16705 * @event buildcomplete
16706 * Fires on the top level element when all elements have been built
16707 * @param {Roo.XComponent} the top level component.
16709 'buildcomplete' : true
16714 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16717 * marked - a markdown parser
16718 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16719 * https://github.com/chjj/marked
16725 * Roo.Markdown - is a very crude wrapper around marked..
16729 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16731 * Note: move the sample code to the bottom of this
16732 * file before uncommenting it.
16737 Roo.Markdown.toHtml = function(text) {
16739 var c = new Roo.Markdown.marked.setOptions({
16740 renderer: new Roo.Markdown.marked.Renderer(),
16751 text = text.replace(/\\\n/g,' ');
16752 return Roo.Markdown.marked(text);
16757 // Wraps all "globals" so that the only thing
16758 // exposed is makeHtml().
16763 * Block-Level Grammar
16768 code: /^( {4}[^\n]+\n*)+/,
16770 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16771 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16773 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16774 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16775 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16776 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16777 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16779 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16783 block.bullet = /(?:[*+-]|\d+\.)/;
16784 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16785 block.item = replace(block.item, 'gm')
16786 (/bull/g, block.bullet)
16789 block.list = replace(block.list)
16790 (/bull/g, block.bullet)
16791 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16792 ('def', '\\n+(?=' + block.def.source + ')')
16795 block.blockquote = replace(block.blockquote)
16799 block._tag = '(?!(?:'
16800 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16801 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16802 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16804 block.html = replace(block.html)
16805 ('comment', /<!--[\s\S]*?-->/)
16806 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16807 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16808 (/tag/g, block._tag)
16811 block.paragraph = replace(block.paragraph)
16813 ('heading', block.heading)
16814 ('lheading', block.lheading)
16815 ('blockquote', block.blockquote)
16816 ('tag', '<' + block._tag)
16821 * Normal Block Grammar
16824 block.normal = merge({}, block);
16827 * GFM Block Grammar
16830 block.gfm = merge({}, block.normal, {
16831 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16833 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16836 block.gfm.paragraph = replace(block.paragraph)
16838 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16839 + block.list.source.replace('\\1', '\\3') + '|')
16843 * GFM + Tables Block Grammar
16846 block.tables = merge({}, block.gfm, {
16847 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16848 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16855 function Lexer(options) {
16857 this.tokens.links = {};
16858 this.options = options || marked.defaults;
16859 this.rules = block.normal;
16861 if (this.options.gfm) {
16862 if (this.options.tables) {
16863 this.rules = block.tables;
16865 this.rules = block.gfm;
16871 * Expose Block Rules
16874 Lexer.rules = block;
16877 * Static Lex Method
16880 Lexer.lex = function(src, options) {
16881 var lexer = new Lexer(options);
16882 return lexer.lex(src);
16889 Lexer.prototype.lex = function(src) {
16891 .replace(/\r\n|\r/g, '\n')
16892 .replace(/\t/g, ' ')
16893 .replace(/\u00a0/g, ' ')
16894 .replace(/\u2424/g, '\n');
16896 return this.token(src, true);
16903 Lexer.prototype.token = function(src, top, bq) {
16904 var src = src.replace(/^ +$/gm, '')
16917 if (cap = this.rules.newline.exec(src)) {
16918 src = src.substring(cap[0].length);
16919 if (cap[0].length > 1) {
16927 if (cap = this.rules.code.exec(src)) {
16928 src = src.substring(cap[0].length);
16929 cap = cap[0].replace(/^ {4}/gm, '');
16932 text: !this.options.pedantic
16933 ? cap.replace(/\n+$/, '')
16940 if (cap = this.rules.fences.exec(src)) {
16941 src = src.substring(cap[0].length);
16951 if (cap = this.rules.heading.exec(src)) {
16952 src = src.substring(cap[0].length);
16955 depth: cap[1].length,
16961 // table no leading pipe (gfm)
16962 if (top && (cap = this.rules.nptable.exec(src))) {
16963 src = src.substring(cap[0].length);
16967 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16968 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16969 cells: cap[3].replace(/\n$/, '').split('\n')
16972 for (i = 0; i < item.align.length; i++) {
16973 if (/^ *-+: *$/.test(item.align[i])) {
16974 item.align[i] = 'right';
16975 } else if (/^ *:-+: *$/.test(item.align[i])) {
16976 item.align[i] = 'center';
16977 } else if (/^ *:-+ *$/.test(item.align[i])) {
16978 item.align[i] = 'left';
16980 item.align[i] = null;
16984 for (i = 0; i < item.cells.length; i++) {
16985 item.cells[i] = item.cells[i].split(/ *\| */);
16988 this.tokens.push(item);
16994 if (cap = this.rules.lheading.exec(src)) {
16995 src = src.substring(cap[0].length);
16998 depth: cap[2] === '=' ? 1 : 2,
17005 if (cap = this.rules.hr.exec(src)) {
17006 src = src.substring(cap[0].length);
17014 if (cap = this.rules.blockquote.exec(src)) {
17015 src = src.substring(cap[0].length);
17018 type: 'blockquote_start'
17021 cap = cap[0].replace(/^ *> ?/gm, '');
17023 // Pass `top` to keep the current
17024 // "toplevel" state. This is exactly
17025 // how markdown.pl works.
17026 this.token(cap, top, true);
17029 type: 'blockquote_end'
17036 if (cap = this.rules.list.exec(src)) {
17037 src = src.substring(cap[0].length);
17041 type: 'list_start',
17042 ordered: bull.length > 1
17045 // Get each top-level item.
17046 cap = cap[0].match(this.rules.item);
17052 for (; i < l; i++) {
17055 // Remove the list item's bullet
17056 // so it is seen as the next token.
17057 space = item.length;
17058 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17060 // Outdent whatever the
17061 // list item contains. Hacky.
17062 if (~item.indexOf('\n ')) {
17063 space -= item.length;
17064 item = !this.options.pedantic
17065 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17066 : item.replace(/^ {1,4}/gm, '');
17069 // Determine whether the next list item belongs here.
17070 // Backpedal if it does not belong in this list.
17071 if (this.options.smartLists && i !== l - 1) {
17072 b = block.bullet.exec(cap[i + 1])[0];
17073 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17074 src = cap.slice(i + 1).join('\n') + src;
17079 // Determine whether item is loose or not.
17080 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17081 // for discount behavior.
17082 loose = next || /\n\n(?!\s*$)/.test(item);
17084 next = item.charAt(item.length - 1) === '\n';
17085 if (!loose) { loose = next; }
17090 ? 'loose_item_start'
17091 : 'list_item_start'
17095 this.token(item, false, bq);
17098 type: 'list_item_end'
17110 if (cap = this.rules.html.exec(src)) {
17111 src = src.substring(cap[0].length);
17113 type: this.options.sanitize
17116 pre: !this.options.sanitizer
17117 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17124 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17125 src = src.substring(cap[0].length);
17126 this.tokens.links[cap[1].toLowerCase()] = {
17134 if (top && (cap = this.rules.table.exec(src))) {
17135 src = src.substring(cap[0].length);
17139 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17140 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17141 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17144 for (i = 0; i < item.align.length; i++) {
17145 if (/^ *-+: *$/.test(item.align[i])) {
17146 item.align[i] = 'right';
17147 } else if (/^ *:-+: *$/.test(item.align[i])) {
17148 item.align[i] = 'center';
17149 } else if (/^ *:-+ *$/.test(item.align[i])) {
17150 item.align[i] = 'left';
17152 item.align[i] = null;
17156 for (i = 0; i < item.cells.length; i++) {
17157 item.cells[i] = item.cells[i]
17158 .replace(/^ *\| *| *\| *$/g, '')
17162 this.tokens.push(item);
17167 // top-level paragraph
17168 if (top && (cap = this.rules.paragraph.exec(src))) {
17169 src = src.substring(cap[0].length);
17172 text: cap[1].charAt(cap[1].length - 1) === '\n'
17173 ? cap[1].slice(0, -1)
17180 if (cap = this.rules.text.exec(src)) {
17181 // Top-level should never reach here.
17182 src = src.substring(cap[0].length);
17192 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17196 return this.tokens;
17200 * Inline-Level Grammar
17204 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17205 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17207 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17208 link: /^!?\[(inside)\]\(href\)/,
17209 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17210 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17211 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17212 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17213 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17214 br: /^ {2,}\n(?!\s*$)/,
17216 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17219 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17220 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17222 inline.link = replace(inline.link)
17223 ('inside', inline._inside)
17224 ('href', inline._href)
17227 inline.reflink = replace(inline.reflink)
17228 ('inside', inline._inside)
17232 * Normal Inline Grammar
17235 inline.normal = merge({}, inline);
17238 * Pedantic Inline Grammar
17241 inline.pedantic = merge({}, inline.normal, {
17242 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17243 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17247 * GFM Inline Grammar
17250 inline.gfm = merge({}, inline.normal, {
17251 escape: replace(inline.escape)('])', '~|])')(),
17252 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17253 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17254 text: replace(inline.text)
17256 ('|', '|https?://|')
17261 * GFM + Line Breaks Inline Grammar
17264 inline.breaks = merge({}, inline.gfm, {
17265 br: replace(inline.br)('{2,}', '*')(),
17266 text: replace(inline.gfm.text)('{2,}', '*')()
17270 * Inline Lexer & Compiler
17273 function InlineLexer(links, options) {
17274 this.options = options || marked.defaults;
17275 this.links = links;
17276 this.rules = inline.normal;
17277 this.renderer = this.options.renderer || new Renderer;
17278 this.renderer.options = this.options;
17282 Error('Tokens array requires a `links` property.');
17285 if (this.options.gfm) {
17286 if (this.options.breaks) {
17287 this.rules = inline.breaks;
17289 this.rules = inline.gfm;
17291 } else if (this.options.pedantic) {
17292 this.rules = inline.pedantic;
17297 * Expose Inline Rules
17300 InlineLexer.rules = inline;
17303 * Static Lexing/Compiling Method
17306 InlineLexer.output = function(src, links, options) {
17307 var inline = new InlineLexer(links, options);
17308 return inline.output(src);
17315 InlineLexer.prototype.output = function(src) {
17324 if (cap = this.rules.escape.exec(src)) {
17325 src = src.substring(cap[0].length);
17331 if (cap = this.rules.autolink.exec(src)) {
17332 src = src.substring(cap[0].length);
17333 if (cap[2] === '@') {
17334 text = cap[1].charAt(6) === ':'
17335 ? this.mangle(cap[1].substring(7))
17336 : this.mangle(cap[1]);
17337 href = this.mangle('mailto:') + text;
17339 text = escape(cap[1]);
17342 out += this.renderer.link(href, null, text);
17347 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17348 src = src.substring(cap[0].length);
17349 text = escape(cap[1]);
17351 out += this.renderer.link(href, null, text);
17356 if (cap = this.rules.tag.exec(src)) {
17357 if (!this.inLink && /^<a /i.test(cap[0])) {
17358 this.inLink = true;
17359 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17360 this.inLink = false;
17362 src = src.substring(cap[0].length);
17363 out += this.options.sanitize
17364 ? this.options.sanitizer
17365 ? this.options.sanitizer(cap[0])
17372 if (cap = this.rules.link.exec(src)) {
17373 src = src.substring(cap[0].length);
17374 this.inLink = true;
17375 out += this.outputLink(cap, {
17379 this.inLink = false;
17384 if ((cap = this.rules.reflink.exec(src))
17385 || (cap = this.rules.nolink.exec(src))) {
17386 src = src.substring(cap[0].length);
17387 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17388 link = this.links[link.toLowerCase()];
17389 if (!link || !link.href) {
17390 out += cap[0].charAt(0);
17391 src = cap[0].substring(1) + src;
17394 this.inLink = true;
17395 out += this.outputLink(cap, link);
17396 this.inLink = false;
17401 if (cap = this.rules.strong.exec(src)) {
17402 src = src.substring(cap[0].length);
17403 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17408 if (cap = this.rules.em.exec(src)) {
17409 src = src.substring(cap[0].length);
17410 out += this.renderer.em(this.output(cap[2] || cap[1]));
17415 if (cap = this.rules.code.exec(src)) {
17416 src = src.substring(cap[0].length);
17417 out += this.renderer.codespan(escape(cap[2], true));
17422 if (cap = this.rules.br.exec(src)) {
17423 src = src.substring(cap[0].length);
17424 out += this.renderer.br();
17429 if (cap = this.rules.del.exec(src)) {
17430 src = src.substring(cap[0].length);
17431 out += this.renderer.del(this.output(cap[1]));
17436 if (cap = this.rules.text.exec(src)) {
17437 src = src.substring(cap[0].length);
17438 out += this.renderer.text(escape(this.smartypants(cap[0])));
17444 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17455 InlineLexer.prototype.outputLink = function(cap, link) {
17456 var href = escape(link.href)
17457 , title = link.title ? escape(link.title) : null;
17459 return cap[0].charAt(0) !== '!'
17460 ? this.renderer.link(href, title, this.output(cap[1]))
17461 : this.renderer.image(href, title, escape(cap[1]));
17465 * Smartypants Transformations
17468 InlineLexer.prototype.smartypants = function(text) {
17469 if (!this.options.smartypants) { return text; }
17472 .replace(/---/g, '\u2014')
17474 .replace(/--/g, '\u2013')
17476 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17477 // closing singles & apostrophes
17478 .replace(/'/g, '\u2019')
17480 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17482 .replace(/"/g, '\u201d')
17484 .replace(/\.{3}/g, '\u2026');
17491 InlineLexer.prototype.mangle = function(text) {
17492 if (!this.options.mangle) { return text; }
17498 for (; i < l; i++) {
17499 ch = text.charCodeAt(i);
17500 if (Math.random() > 0.5) {
17501 ch = 'x' + ch.toString(16);
17503 out += '&#' + ch + ';';
17513 function Renderer(options) {
17514 this.options = options || {};
17517 Renderer.prototype.code = function(code, lang, escaped) {
17518 if (this.options.highlight) {
17519 var out = this.options.highlight(code, lang);
17520 if (out != null && out !== code) {
17525 // hack!!! - it's already escapeD?
17530 return '<pre><code>'
17531 + (escaped ? code : escape(code, true))
17532 + '\n</code></pre>';
17535 return '<pre><code class="'
17536 + this.options.langPrefix
17537 + escape(lang, true)
17539 + (escaped ? code : escape(code, true))
17540 + '\n</code></pre>\n';
17543 Renderer.prototype.blockquote = function(quote) {
17544 return '<blockquote>\n' + quote + '</blockquote>\n';
17547 Renderer.prototype.html = function(html) {
17551 Renderer.prototype.heading = function(text, level, raw) {
17555 + this.options.headerPrefix
17556 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17564 Renderer.prototype.hr = function() {
17565 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17568 Renderer.prototype.list = function(body, ordered) {
17569 var type = ordered ? 'ol' : 'ul';
17570 return '<' + type + '>\n' + body + '</' + type + '>\n';
17573 Renderer.prototype.listitem = function(text) {
17574 return '<li>' + text + '</li>\n';
17577 Renderer.prototype.paragraph = function(text) {
17578 return '<p>' + text + '</p>\n';
17581 Renderer.prototype.table = function(header, body) {
17582 return '<table class="table table-striped">\n'
17592 Renderer.prototype.tablerow = function(content) {
17593 return '<tr>\n' + content + '</tr>\n';
17596 Renderer.prototype.tablecell = function(content, flags) {
17597 var type = flags.header ? 'th' : 'td';
17598 var tag = flags.align
17599 ? '<' + type + ' style="text-align:' + flags.align + '">'
17600 : '<' + type + '>';
17601 return tag + content + '</' + type + '>\n';
17604 // span level renderer
17605 Renderer.prototype.strong = function(text) {
17606 return '<strong>' + text + '</strong>';
17609 Renderer.prototype.em = function(text) {
17610 return '<em>' + text + '</em>';
17613 Renderer.prototype.codespan = function(text) {
17614 return '<code>' + text + '</code>';
17617 Renderer.prototype.br = function() {
17618 return this.options.xhtml ? '<br/>' : '<br>';
17621 Renderer.prototype.del = function(text) {
17622 return '<del>' + text + '</del>';
17625 Renderer.prototype.link = function(href, title, text) {
17626 if (this.options.sanitize) {
17628 var prot = decodeURIComponent(unescape(href))
17629 .replace(/[^\w:]/g, '')
17634 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17638 var out = '<a href="' + href + '"';
17640 out += ' title="' + title + '"';
17642 out += '>' + text + '</a>';
17646 Renderer.prototype.image = function(href, title, text) {
17647 var out = '<img src="' + href + '" alt="' + text + '"';
17649 out += ' title="' + title + '"';
17651 out += this.options.xhtml ? '/>' : '>';
17655 Renderer.prototype.text = function(text) {
17660 * Parsing & Compiling
17663 function Parser(options) {
17666 this.options = options || marked.defaults;
17667 this.options.renderer = this.options.renderer || new Renderer;
17668 this.renderer = this.options.renderer;
17669 this.renderer.options = this.options;
17673 * Static Parse Method
17676 Parser.parse = function(src, options, renderer) {
17677 var parser = new Parser(options, renderer);
17678 return parser.parse(src);
17685 Parser.prototype.parse = function(src) {
17686 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17687 this.tokens = src.reverse();
17690 while (this.next()) {
17701 Parser.prototype.next = function() {
17702 return this.token = this.tokens.pop();
17706 * Preview Next Token
17709 Parser.prototype.peek = function() {
17710 return this.tokens[this.tokens.length - 1] || 0;
17714 * Parse Text Tokens
17717 Parser.prototype.parseText = function() {
17718 var body = this.token.text;
17720 while (this.peek().type === 'text') {
17721 body += '\n' + this.next().text;
17724 return this.inline.output(body);
17728 * Parse Current Token
17731 Parser.prototype.tok = function() {
17732 switch (this.token.type) {
17737 return this.renderer.hr();
17740 return this.renderer.heading(
17741 this.inline.output(this.token.text),
17746 return this.renderer.code(this.token.text,
17748 this.token.escaped);
17761 for (i = 0; i < this.token.header.length; i++) {
17762 flags = { header: true, align: this.token.align[i] };
17763 cell += this.renderer.tablecell(
17764 this.inline.output(this.token.header[i]),
17765 { header: true, align: this.token.align[i] }
17768 header += this.renderer.tablerow(cell);
17770 for (i = 0; i < this.token.cells.length; i++) {
17771 row = this.token.cells[i];
17774 for (j = 0; j < row.length; j++) {
17775 cell += this.renderer.tablecell(
17776 this.inline.output(row[j]),
17777 { header: false, align: this.token.align[j] }
17781 body += this.renderer.tablerow(cell);
17783 return this.renderer.table(header, body);
17785 case 'blockquote_start': {
17788 while (this.next().type !== 'blockquote_end') {
17789 body += this.tok();
17792 return this.renderer.blockquote(body);
17794 case 'list_start': {
17796 , ordered = this.token.ordered;
17798 while (this.next().type !== 'list_end') {
17799 body += this.tok();
17802 return this.renderer.list(body, ordered);
17804 case 'list_item_start': {
17807 while (this.next().type !== 'list_item_end') {
17808 body += this.token.type === 'text'
17813 return this.renderer.listitem(body);
17815 case 'loose_item_start': {
17818 while (this.next().type !== 'list_item_end') {
17819 body += this.tok();
17822 return this.renderer.listitem(body);
17825 var html = !this.token.pre && !this.options.pedantic
17826 ? this.inline.output(this.token.text)
17828 return this.renderer.html(html);
17830 case 'paragraph': {
17831 return this.renderer.paragraph(this.inline.output(this.token.text));
17834 return this.renderer.paragraph(this.parseText());
17843 function escape(html, encode) {
17845 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17846 .replace(/</g, '<')
17847 .replace(/>/g, '>')
17848 .replace(/"/g, '"')
17849 .replace(/'/g, ''');
17852 function unescape(html) {
17853 // explicitly match decimal, hex, and named HTML entities
17854 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17855 n = n.toLowerCase();
17856 if (n === 'colon') { return ':'; }
17857 if (n.charAt(0) === '#') {
17858 return n.charAt(1) === 'x'
17859 ? String.fromCharCode(parseInt(n.substring(2), 16))
17860 : String.fromCharCode(+n.substring(1));
17866 function replace(regex, opt) {
17867 regex = regex.source;
17869 return function self(name, val) {
17870 if (!name) { return new RegExp(regex, opt); }
17871 val = val.source || val;
17872 val = val.replace(/(^|[^\[])\^/g, '$1');
17873 regex = regex.replace(name, val);
17881 function merge(obj) {
17886 for (; i < arguments.length; i++) {
17887 target = arguments[i];
17888 for (key in target) {
17889 if (Object.prototype.hasOwnProperty.call(target, key)) {
17890 obj[key] = target[key];
17903 function marked(src, opt, callback) {
17904 if (callback || typeof opt === 'function') {
17910 opt = merge({}, marked.defaults, opt || {});
17912 var highlight = opt.highlight
17918 tokens = Lexer.lex(src, opt)
17920 return callback(e);
17923 pending = tokens.length;
17925 var done = function(err) {
17927 opt.highlight = highlight;
17928 return callback(err);
17934 out = Parser.parse(tokens, opt);
17939 opt.highlight = highlight;
17943 : callback(null, out);
17946 if (!highlight || highlight.length < 3) {
17950 delete opt.highlight;
17952 if (!pending) { return done(); }
17954 for (; i < tokens.length; i++) {
17956 if (token.type !== 'code') {
17957 return --pending || done();
17959 return highlight(token.text, token.lang, function(err, code) {
17960 if (err) { return done(err); }
17961 if (code == null || code === token.text) {
17962 return --pending || done();
17965 token.escaped = true;
17966 --pending || done();
17974 if (opt) { opt = merge({}, marked.defaults, opt); }
17975 return Parser.parse(Lexer.lex(src, opt), opt);
17977 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17978 if ((opt || marked.defaults).silent) {
17979 return '<p>An error occured:</p><pre>'
17980 + escape(e.message + '', true)
17992 marked.setOptions = function(opt) {
17993 merge(marked.defaults, opt);
17997 marked.defaults = {
18008 langPrefix: 'lang-',
18009 smartypants: false,
18011 renderer: new Renderer,
18019 marked.Parser = Parser;
18020 marked.parser = Parser.parse;
18022 marked.Renderer = Renderer;
18024 marked.Lexer = Lexer;
18025 marked.lexer = Lexer.lex;
18027 marked.InlineLexer = InlineLexer;
18028 marked.inlineLexer = InlineLexer.output;
18030 marked.parse = marked;
18032 Roo.Markdown.marked = marked;
18036 * Ext JS Library 1.1.1
18037 * Copyright(c) 2006-2007, Ext JS, LLC.
18039 * Originally Released Under LGPL - original licence link has changed is not relivant.
18042 * <script type="text/javascript">
18048 * These classes are derivatives of the similarly named classes in the YUI Library.
18049 * The original license:
18050 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18051 * Code licensed under the BSD License:
18052 * http://developer.yahoo.net/yui/license.txt
18057 var Event=Roo.EventManager;
18058 var Dom=Roo.lib.Dom;
18061 * @class Roo.dd.DragDrop
18062 * @extends Roo.util.Observable
18063 * Defines the interface and base operation of items that that can be
18064 * dragged or can be drop targets. It was designed to be extended, overriding
18065 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18066 * Up to three html elements can be associated with a DragDrop instance:
18068 * <li>linked element: the element that is passed into the constructor.
18069 * This is the element which defines the boundaries for interaction with
18070 * other DragDrop objects.</li>
18071 * <li>handle element(s): The drag operation only occurs if the element that
18072 * was clicked matches a handle element. By default this is the linked
18073 * element, but there are times that you will want only a portion of the
18074 * linked element to initiate the drag operation, and the setHandleElId()
18075 * method provides a way to define this.</li>
18076 * <li>drag element: this represents the element that would be moved along
18077 * with the cursor during a drag operation. By default, this is the linked
18078 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18079 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18082 * This class should not be instantiated until the onload event to ensure that
18083 * the associated elements are available.
18084 * The following would define a DragDrop obj that would interact with any
18085 * other DragDrop obj in the "group1" group:
18087 * dd = new Roo.dd.DragDrop("div1", "group1");
18089 * Since none of the event handlers have been implemented, nothing would
18090 * actually happen if you were to run the code above. Normally you would
18091 * override this class or one of the default implementations, but you can
18092 * also override the methods you want on an instance of the class...
18094 * dd.onDragDrop = function(e, id) {
18095 * alert("dd was dropped on " + id);
18099 * @param {String} id of the element that is linked to this instance
18100 * @param {String} sGroup the group of related DragDrop objects
18101 * @param {object} config an object containing configurable attributes
18102 * Valid properties for DragDrop:
18103 * padding, isTarget, maintainOffset, primaryButtonOnly
18105 Roo.dd.DragDrop = function(id, sGroup, config) {
18107 this.init(id, sGroup, config);
18112 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18115 * The id of the element associated with this object. This is what we
18116 * refer to as the "linked element" because the size and position of
18117 * this element is used to determine when the drag and drop objects have
18125 * Configuration attributes passed into the constructor
18132 * The id of the element that will be dragged. By default this is same
18133 * as the linked element , but could be changed to another element. Ex:
18135 * @property dragElId
18142 * the id of the element that initiates the drag operation. By default
18143 * this is the linked element, but could be changed to be a child of this
18144 * element. This lets us do things like only starting the drag when the
18145 * header element within the linked html element is clicked.
18146 * @property handleElId
18153 * An associative array of HTML tags that will be ignored if clicked.
18154 * @property invalidHandleTypes
18155 * @type {string: string}
18157 invalidHandleTypes: null,
18160 * An associative array of ids for elements that will be ignored if clicked
18161 * @property invalidHandleIds
18162 * @type {string: string}
18164 invalidHandleIds: null,
18167 * An indexted array of css class names for elements that will be ignored
18169 * @property invalidHandleClasses
18172 invalidHandleClasses: null,
18175 * The linked element's absolute X position at the time the drag was
18177 * @property startPageX
18184 * The linked element's absolute X position at the time the drag was
18186 * @property startPageY
18193 * The group defines a logical collection of DragDrop objects that are
18194 * related. Instances only get events when interacting with other
18195 * DragDrop object in the same group. This lets us define multiple
18196 * groups using a single DragDrop subclass if we want.
18198 * @type {string: string}
18203 * Individual drag/drop instances can be locked. This will prevent
18204 * onmousedown start drag.
18212 * Lock this instance
18215 lock: function() { this.locked = true; },
18218 * Unlock this instace
18221 unlock: function() { this.locked = false; },
18224 * By default, all insances can be a drop target. This can be disabled by
18225 * setting isTarget to false.
18232 * The padding configured for this drag and drop object for calculating
18233 * the drop zone intersection with this object.
18240 * Cached reference to the linked element
18241 * @property _domRef
18247 * Internal typeof flag
18248 * @property __ygDragDrop
18251 __ygDragDrop: true,
18254 * Set to true when horizontal contraints are applied
18255 * @property constrainX
18262 * Set to true when vertical contraints are applied
18263 * @property constrainY
18270 * The left constraint
18278 * The right constraint
18286 * The up constraint
18295 * The down constraint
18303 * Maintain offsets when we resetconstraints. Set to true when you want
18304 * the position of the element relative to its parent to stay the same
18305 * when the page changes
18307 * @property maintainOffset
18310 maintainOffset: false,
18313 * Array of pixel locations the element will snap to if we specified a
18314 * horizontal graduation/interval. This array is generated automatically
18315 * when you define a tick interval.
18322 * Array of pixel locations the element will snap to if we specified a
18323 * vertical graduation/interval. This array is generated automatically
18324 * when you define a tick interval.
18331 * By default the drag and drop instance will only respond to the primary
18332 * button click (left button for a right-handed mouse). Set to true to
18333 * allow drag and drop to start with any mouse click that is propogated
18335 * @property primaryButtonOnly
18338 primaryButtonOnly: true,
18341 * The availabe property is false until the linked dom element is accessible.
18342 * @property available
18348 * By default, drags can only be initiated if the mousedown occurs in the
18349 * region the linked element is. This is done in part to work around a
18350 * bug in some browsers that mis-report the mousedown if the previous
18351 * mouseup happened outside of the window. This property is set to true
18352 * if outer handles are defined.
18354 * @property hasOuterHandles
18358 hasOuterHandles: false,
18361 * Code that executes immediately before the startDrag event
18362 * @method b4StartDrag
18365 b4StartDrag: function(x, y) { },
18368 * Abstract method called after a drag/drop object is clicked
18369 * and the drag or mousedown time thresholds have beeen met.
18370 * @method startDrag
18371 * @param {int} X click location
18372 * @param {int} Y click location
18374 startDrag: function(x, y) { /* override this */ },
18377 * Code that executes immediately before the onDrag event
18381 b4Drag: function(e) { },
18384 * Abstract method called during the onMouseMove event while dragging an
18387 * @param {Event} e the mousemove event
18389 onDrag: function(e) { /* override this */ },
18392 * Abstract method called when this element fist begins hovering over
18393 * another DragDrop obj
18394 * @method onDragEnter
18395 * @param {Event} e the mousemove event
18396 * @param {String|DragDrop[]} id In POINT mode, the element
18397 * id this is hovering over. In INTERSECT mode, an array of one or more
18398 * dragdrop items being hovered over.
18400 onDragEnter: function(e, id) { /* override this */ },
18403 * Code that executes immediately before the onDragOver event
18404 * @method b4DragOver
18407 b4DragOver: function(e) { },
18410 * Abstract method called when this element is hovering over another
18412 * @method onDragOver
18413 * @param {Event} e the mousemove event
18414 * @param {String|DragDrop[]} id In POINT mode, the element
18415 * id this is hovering over. In INTERSECT mode, an array of dd items
18416 * being hovered over.
18418 onDragOver: function(e, id) { /* override this */ },
18421 * Code that executes immediately before the onDragOut event
18422 * @method b4DragOut
18425 b4DragOut: function(e) { },
18428 * Abstract method called when we are no longer hovering over an element
18429 * @method onDragOut
18430 * @param {Event} e the mousemove event
18431 * @param {String|DragDrop[]} id In POINT mode, the element
18432 * id this was hovering over. In INTERSECT mode, an array of dd items
18433 * that the mouse is no longer over.
18435 onDragOut: function(e, id) { /* override this */ },
18438 * Code that executes immediately before the onDragDrop event
18439 * @method b4DragDrop
18442 b4DragDrop: function(e) { },
18445 * Abstract method called when this item is dropped on another DragDrop
18447 * @method onDragDrop
18448 * @param {Event} e the mouseup event
18449 * @param {String|DragDrop[]} id In POINT mode, the element
18450 * id this was dropped on. In INTERSECT mode, an array of dd items this
18453 onDragDrop: function(e, id) { /* override this */ },
18456 * Abstract method called when this item is dropped on an area with no
18458 * @method onInvalidDrop
18459 * @param {Event} e the mouseup event
18461 onInvalidDrop: function(e) { /* override this */ },
18464 * Code that executes immediately before the endDrag event
18465 * @method b4EndDrag
18468 b4EndDrag: function(e) { },
18471 * Fired when we are done dragging the object
18473 * @param {Event} e the mouseup event
18475 endDrag: function(e) { /* override this */ },
18478 * Code executed immediately before the onMouseDown event
18479 * @method b4MouseDown
18480 * @param {Event} e the mousedown event
18483 b4MouseDown: function(e) { },
18486 * Event handler that fires when a drag/drop obj gets a mousedown
18487 * @method onMouseDown
18488 * @param {Event} e the mousedown event
18490 onMouseDown: function(e) { /* override this */ },
18493 * Event handler that fires when a drag/drop obj gets a mouseup
18494 * @method onMouseUp
18495 * @param {Event} e the mouseup event
18497 onMouseUp: function(e) { /* override this */ },
18500 * Override the onAvailable method to do what is needed after the initial
18501 * position was determined.
18502 * @method onAvailable
18504 onAvailable: function () {
18508 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18511 defaultPadding : {left:0, right:0, top:0, bottom:0},
18514 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18518 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18519 { dragElId: "existingProxyDiv" });
18520 dd.startDrag = function(){
18521 this.constrainTo("parent-id");
18524 * Or you can initalize it using the {@link Roo.Element} object:
18526 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18527 startDrag : function(){
18528 this.constrainTo("parent-id");
18532 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18533 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18534 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18535 * an object containing the sides to pad. For example: {right:10, bottom:10}
18536 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18538 constrainTo : function(constrainTo, pad, inContent){
18539 if(typeof pad == "number"){
18540 pad = {left: pad, right:pad, top:pad, bottom:pad};
18542 pad = pad || this.defaultPadding;
18543 var b = Roo.get(this.getEl()).getBox();
18544 var ce = Roo.get(constrainTo);
18545 var s = ce.getScroll();
18546 var c, cd = ce.dom;
18547 if(cd == document.body){
18548 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18551 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18555 var topSpace = b.y - c.y;
18556 var leftSpace = b.x - c.x;
18558 this.resetConstraints();
18559 this.setXConstraint(leftSpace - (pad.left||0), // left
18560 c.width - leftSpace - b.width - (pad.right||0) //right
18562 this.setYConstraint(topSpace - (pad.top||0), //top
18563 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18568 * Returns a reference to the linked element
18570 * @return {HTMLElement} the html element
18572 getEl: function() {
18573 if (!this._domRef) {
18574 this._domRef = Roo.getDom(this.id);
18577 return this._domRef;
18581 * Returns a reference to the actual element to drag. By default this is
18582 * the same as the html element, but it can be assigned to another
18583 * element. An example of this can be found in Roo.dd.DDProxy
18584 * @method getDragEl
18585 * @return {HTMLElement} the html element
18587 getDragEl: function() {
18588 return Roo.getDom(this.dragElId);
18592 * Sets up the DragDrop object. Must be called in the constructor of any
18593 * Roo.dd.DragDrop subclass
18595 * @param id the id of the linked element
18596 * @param {String} sGroup the group of related items
18597 * @param {object} config configuration attributes
18599 init: function(id, sGroup, config) {
18600 this.initTarget(id, sGroup, config);
18601 if (!Roo.isTouch) {
18602 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18604 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18605 // Event.on(this.id, "selectstart", Event.preventDefault);
18609 * Initializes Targeting functionality only... the object does not
18610 * get a mousedown handler.
18611 * @method initTarget
18612 * @param id the id of the linked element
18613 * @param {String} sGroup the group of related items
18614 * @param {object} config configuration attributes
18616 initTarget: function(id, sGroup, config) {
18618 // configuration attributes
18619 this.config = config || {};
18621 // create a local reference to the drag and drop manager
18622 this.DDM = Roo.dd.DDM;
18623 // initialize the groups array
18626 // assume that we have an element reference instead of an id if the
18627 // parameter is not a string
18628 if (typeof id !== "string") {
18635 // add to an interaction group
18636 this.addToGroup((sGroup) ? sGroup : "default");
18638 // We don't want to register this as the handle with the manager
18639 // so we just set the id rather than calling the setter.
18640 this.handleElId = id;
18642 // the linked element is the element that gets dragged by default
18643 this.setDragElId(id);
18645 // by default, clicked anchors will not start drag operations.
18646 this.invalidHandleTypes = { A: "A" };
18647 this.invalidHandleIds = {};
18648 this.invalidHandleClasses = [];
18650 this.applyConfig();
18652 this.handleOnAvailable();
18656 * Applies the configuration parameters that were passed into the constructor.
18657 * This is supposed to happen at each level through the inheritance chain. So
18658 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18659 * DragDrop in order to get all of the parameters that are available in
18661 * @method applyConfig
18663 applyConfig: function() {
18665 // configurable properties:
18666 // padding, isTarget, maintainOffset, primaryButtonOnly
18667 this.padding = this.config.padding || [0, 0, 0, 0];
18668 this.isTarget = (this.config.isTarget !== false);
18669 this.maintainOffset = (this.config.maintainOffset);
18670 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18675 * Executed when the linked element is available
18676 * @method handleOnAvailable
18679 handleOnAvailable: function() {
18680 this.available = true;
18681 this.resetConstraints();
18682 this.onAvailable();
18686 * Configures the padding for the target zone in px. Effectively expands
18687 * (or reduces) the virtual object size for targeting calculations.
18688 * Supports css-style shorthand; if only one parameter is passed, all sides
18689 * will have that padding, and if only two are passed, the top and bottom
18690 * will have the first param, the left and right the second.
18691 * @method setPadding
18692 * @param {int} iTop Top pad
18693 * @param {int} iRight Right pad
18694 * @param {int} iBot Bot pad
18695 * @param {int} iLeft Left pad
18697 setPadding: function(iTop, iRight, iBot, iLeft) {
18698 // this.padding = [iLeft, iRight, iTop, iBot];
18699 if (!iRight && 0 !== iRight) {
18700 this.padding = [iTop, iTop, iTop, iTop];
18701 } else if (!iBot && 0 !== iBot) {
18702 this.padding = [iTop, iRight, iTop, iRight];
18704 this.padding = [iTop, iRight, iBot, iLeft];
18709 * Stores the initial placement of the linked element.
18710 * @method setInitialPosition
18711 * @param {int} diffX the X offset, default 0
18712 * @param {int} diffY the Y offset, default 0
18714 setInitPosition: function(diffX, diffY) {
18715 var el = this.getEl();
18717 if (!this.DDM.verifyEl(el)) {
18721 var dx = diffX || 0;
18722 var dy = diffY || 0;
18724 var p = Dom.getXY( el );
18726 this.initPageX = p[0] - dx;
18727 this.initPageY = p[1] - dy;
18729 this.lastPageX = p[0];
18730 this.lastPageY = p[1];
18733 this.setStartPosition(p);
18737 * Sets the start position of the element. This is set when the obj
18738 * is initialized, the reset when a drag is started.
18739 * @method setStartPosition
18740 * @param pos current position (from previous lookup)
18743 setStartPosition: function(pos) {
18744 var p = pos || Dom.getXY( this.getEl() );
18745 this.deltaSetXY = null;
18747 this.startPageX = p[0];
18748 this.startPageY = p[1];
18752 * Add this instance to a group of related drag/drop objects. All
18753 * instances belong to at least one group, and can belong to as many
18754 * groups as needed.
18755 * @method addToGroup
18756 * @param sGroup {string} the name of the group
18758 addToGroup: function(sGroup) {
18759 this.groups[sGroup] = true;
18760 this.DDM.regDragDrop(this, sGroup);
18764 * Remove's this instance from the supplied interaction group
18765 * @method removeFromGroup
18766 * @param {string} sGroup The group to drop
18768 removeFromGroup: function(sGroup) {
18769 if (this.groups[sGroup]) {
18770 delete this.groups[sGroup];
18773 this.DDM.removeDDFromGroup(this, sGroup);
18777 * Allows you to specify that an element other than the linked element
18778 * will be moved with the cursor during a drag
18779 * @method setDragElId
18780 * @param id {string} the id of the element that will be used to initiate the drag
18782 setDragElId: function(id) {
18783 this.dragElId = id;
18787 * Allows you to specify a child of the linked element that should be
18788 * used to initiate the drag operation. An example of this would be if
18789 * you have a content div with text and links. Clicking anywhere in the
18790 * content area would normally start the drag operation. Use this method
18791 * to specify that an element inside of the content div is the element
18792 * that starts the drag operation.
18793 * @method setHandleElId
18794 * @param id {string} the id of the element that will be used to
18795 * initiate the drag.
18797 setHandleElId: function(id) {
18798 if (typeof id !== "string") {
18801 this.handleElId = id;
18802 this.DDM.regHandle(this.id, id);
18806 * Allows you to set an element outside of the linked element as a drag
18808 * @method setOuterHandleElId
18809 * @param id the id of the element that will be used to initiate the drag
18811 setOuterHandleElId: function(id) {
18812 if (typeof id !== "string") {
18815 Event.on(id, "mousedown",
18816 this.handleMouseDown, this);
18817 this.setHandleElId(id);
18819 this.hasOuterHandles = true;
18823 * Remove all drag and drop hooks for this element
18826 unreg: function() {
18827 Event.un(this.id, "mousedown",
18828 this.handleMouseDown);
18829 Event.un(this.id, "touchstart",
18830 this.handleMouseDown);
18831 this._domRef = null;
18832 this.DDM._remove(this);
18835 destroy : function(){
18840 * Returns true if this instance is locked, or the drag drop mgr is locked
18841 * (meaning that all drag/drop is disabled on the page.)
18843 * @return {boolean} true if this obj or all drag/drop is locked, else
18846 isLocked: function() {
18847 return (this.DDM.isLocked() || this.locked);
18851 * Fired when this object is clicked
18852 * @method handleMouseDown
18854 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18857 handleMouseDown: function(e, oDD){
18859 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18860 //Roo.log('not touch/ button !=0');
18863 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18864 return; // double touch..
18868 if (this.isLocked()) {
18869 //Roo.log('locked');
18873 this.DDM.refreshCache(this.groups);
18874 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18875 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18876 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18877 //Roo.log('no outer handes or not over target');
18880 // Roo.log('check validator');
18881 if (this.clickValidator(e)) {
18882 // Roo.log('validate success');
18883 // set the initial element position
18884 this.setStartPosition();
18887 this.b4MouseDown(e);
18888 this.onMouseDown(e);
18890 this.DDM.handleMouseDown(e, this);
18892 this.DDM.stopEvent(e);
18900 clickValidator: function(e) {
18901 var target = e.getTarget();
18902 return ( this.isValidHandleChild(target) &&
18903 (this.id == this.handleElId ||
18904 this.DDM.handleWasClicked(target, this.id)) );
18908 * Allows you to specify a tag name that should not start a drag operation
18909 * when clicked. This is designed to facilitate embedding links within a
18910 * drag handle that do something other than start the drag.
18911 * @method addInvalidHandleType
18912 * @param {string} tagName the type of element to exclude
18914 addInvalidHandleType: function(tagName) {
18915 var type = tagName.toUpperCase();
18916 this.invalidHandleTypes[type] = type;
18920 * Lets you to specify an element id for a child of a drag handle
18921 * that should not initiate a drag
18922 * @method addInvalidHandleId
18923 * @param {string} id the element id of the element you wish to ignore
18925 addInvalidHandleId: function(id) {
18926 if (typeof id !== "string") {
18929 this.invalidHandleIds[id] = id;
18933 * Lets you specify a css class of elements that will not initiate a drag
18934 * @method addInvalidHandleClass
18935 * @param {string} cssClass the class of the elements you wish to ignore
18937 addInvalidHandleClass: function(cssClass) {
18938 this.invalidHandleClasses.push(cssClass);
18942 * Unsets an excluded tag name set by addInvalidHandleType
18943 * @method removeInvalidHandleType
18944 * @param {string} tagName the type of element to unexclude
18946 removeInvalidHandleType: function(tagName) {
18947 var type = tagName.toUpperCase();
18948 // this.invalidHandleTypes[type] = null;
18949 delete this.invalidHandleTypes[type];
18953 * Unsets an invalid handle id
18954 * @method removeInvalidHandleId
18955 * @param {string} id the id of the element to re-enable
18957 removeInvalidHandleId: function(id) {
18958 if (typeof id !== "string") {
18961 delete this.invalidHandleIds[id];
18965 * Unsets an invalid css class
18966 * @method removeInvalidHandleClass
18967 * @param {string} cssClass the class of the element(s) you wish to
18970 removeInvalidHandleClass: function(cssClass) {
18971 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18972 if (this.invalidHandleClasses[i] == cssClass) {
18973 delete this.invalidHandleClasses[i];
18979 * Checks the tag exclusion list to see if this click should be ignored
18980 * @method isValidHandleChild
18981 * @param {HTMLElement} node the HTMLElement to evaluate
18982 * @return {boolean} true if this is a valid tag type, false if not
18984 isValidHandleChild: function(node) {
18987 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18990 nodeName = node.nodeName.toUpperCase();
18992 nodeName = node.nodeName;
18994 valid = valid && !this.invalidHandleTypes[nodeName];
18995 valid = valid && !this.invalidHandleIds[node.id];
18997 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18998 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19007 * Create the array of horizontal tick marks if an interval was specified
19008 * in setXConstraint().
19009 * @method setXTicks
19012 setXTicks: function(iStartX, iTickSize) {
19014 this.xTickSize = iTickSize;
19018 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19020 this.xTicks[this.xTicks.length] = i;
19025 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19027 this.xTicks[this.xTicks.length] = i;
19032 this.xTicks.sort(this.DDM.numericSort) ;
19036 * Create the array of vertical tick marks if an interval was specified in
19037 * setYConstraint().
19038 * @method setYTicks
19041 setYTicks: function(iStartY, iTickSize) {
19043 this.yTickSize = iTickSize;
19047 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19049 this.yTicks[this.yTicks.length] = i;
19054 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19056 this.yTicks[this.yTicks.length] = i;
19061 this.yTicks.sort(this.DDM.numericSort) ;
19065 * By default, the element can be dragged any place on the screen. Use
19066 * this method to limit the horizontal travel of the element. Pass in
19067 * 0,0 for the parameters if you want to lock the drag to the y axis.
19068 * @method setXConstraint
19069 * @param {int} iLeft the number of pixels the element can move to the left
19070 * @param {int} iRight the number of pixels the element can move to the
19072 * @param {int} iTickSize optional parameter for specifying that the
19074 * should move iTickSize pixels at a time.
19076 setXConstraint: function(iLeft, iRight, iTickSize) {
19077 this.leftConstraint = iLeft;
19078 this.rightConstraint = iRight;
19080 this.minX = this.initPageX - iLeft;
19081 this.maxX = this.initPageX + iRight;
19082 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19084 this.constrainX = true;
19088 * Clears any constraints applied to this instance. Also clears ticks
19089 * since they can't exist independent of a constraint at this time.
19090 * @method clearConstraints
19092 clearConstraints: function() {
19093 this.constrainX = false;
19094 this.constrainY = false;
19099 * Clears any tick interval defined for this instance
19100 * @method clearTicks
19102 clearTicks: function() {
19103 this.xTicks = null;
19104 this.yTicks = null;
19105 this.xTickSize = 0;
19106 this.yTickSize = 0;
19110 * By default, the element can be dragged any place on the screen. Set
19111 * this to limit the vertical travel of the element. Pass in 0,0 for the
19112 * parameters if you want to lock the drag to the x axis.
19113 * @method setYConstraint
19114 * @param {int} iUp the number of pixels the element can move up
19115 * @param {int} iDown the number of pixels the element can move down
19116 * @param {int} iTickSize optional parameter for specifying that the
19117 * element should move iTickSize pixels at a time.
19119 setYConstraint: function(iUp, iDown, iTickSize) {
19120 this.topConstraint = iUp;
19121 this.bottomConstraint = iDown;
19123 this.minY = this.initPageY - iUp;
19124 this.maxY = this.initPageY + iDown;
19125 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19127 this.constrainY = true;
19132 * resetConstraints must be called if you manually reposition a dd element.
19133 * @method resetConstraints
19134 * @param {boolean} maintainOffset
19136 resetConstraints: function() {
19139 // Maintain offsets if necessary
19140 if (this.initPageX || this.initPageX === 0) {
19141 // figure out how much this thing has moved
19142 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19143 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19145 this.setInitPosition(dx, dy);
19147 // This is the first time we have detected the element's position
19149 this.setInitPosition();
19152 if (this.constrainX) {
19153 this.setXConstraint( this.leftConstraint,
19154 this.rightConstraint,
19158 if (this.constrainY) {
19159 this.setYConstraint( this.topConstraint,
19160 this.bottomConstraint,
19166 * Normally the drag element is moved pixel by pixel, but we can specify
19167 * that it move a number of pixels at a time. This method resolves the
19168 * location when we have it set up like this.
19170 * @param {int} val where we want to place the object
19171 * @param {int[]} tickArray sorted array of valid points
19172 * @return {int} the closest tick
19175 getTick: function(val, tickArray) {
19178 // If tick interval is not defined, it is effectively 1 pixel,
19179 // so we return the value passed to us.
19181 } else if (tickArray[0] >= val) {
19182 // The value is lower than the first tick, so we return the first
19184 return tickArray[0];
19186 for (var i=0, len=tickArray.length; i<len; ++i) {
19188 if (tickArray[next] && tickArray[next] >= val) {
19189 var diff1 = val - tickArray[i];
19190 var diff2 = tickArray[next] - val;
19191 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19195 // The value is larger than the last tick, so we return the last
19197 return tickArray[tickArray.length - 1];
19204 * @return {string} string representation of the dd obj
19206 toString: function() {
19207 return ("DragDrop " + this.id);
19215 * Ext JS Library 1.1.1
19216 * Copyright(c) 2006-2007, Ext JS, LLC.
19218 * Originally Released Under LGPL - original licence link has changed is not relivant.
19221 * <script type="text/javascript">
19226 * The drag and drop utility provides a framework for building drag and drop
19227 * applications. In addition to enabling drag and drop for specific elements,
19228 * the drag and drop elements are tracked by the manager class, and the
19229 * interactions between the various elements are tracked during the drag and
19230 * the implementing code is notified about these important moments.
19233 // Only load the library once. Rewriting the manager class would orphan
19234 // existing drag and drop instances.
19235 if (!Roo.dd.DragDropMgr) {
19238 * @class Roo.dd.DragDropMgr
19239 * DragDropMgr is a singleton that tracks the element interaction for
19240 * all DragDrop items in the window. Generally, you will not call
19241 * this class directly, but it does have helper methods that could
19242 * be useful in your DragDrop implementations.
19245 Roo.dd.DragDropMgr = function() {
19247 var Event = Roo.EventManager;
19252 * Two dimensional Array of registered DragDrop objects. The first
19253 * dimension is the DragDrop item group, the second the DragDrop
19256 * @type {string: string}
19263 * Array of element ids defined as drag handles. Used to determine
19264 * if the element that generated the mousedown event is actually the
19265 * handle and not the html element itself.
19266 * @property handleIds
19267 * @type {string: string}
19274 * the DragDrop object that is currently being dragged
19275 * @property dragCurrent
19283 * the DragDrop object(s) that are being hovered over
19284 * @property dragOvers
19292 * the X distance between the cursor and the object being dragged
19301 * the Y distance between the cursor and the object being dragged
19310 * Flag to determine if we should prevent the default behavior of the
19311 * events we define. By default this is true, but this can be set to
19312 * false if you need the default behavior (not recommended)
19313 * @property preventDefault
19317 preventDefault: true,
19320 * Flag to determine if we should stop the propagation of the events
19321 * we generate. This is true by default but you may want to set it to
19322 * false if the html element contains other features that require the
19324 * @property stopPropagation
19328 stopPropagation: true,
19331 * Internal flag that is set to true when drag and drop has been
19333 * @property initialized
19340 * All drag and drop can be disabled.
19348 * Called the first time an element is registered.
19354 this.initialized = true;
19358 * In point mode, drag and drop interaction is defined by the
19359 * location of the cursor during the drag/drop
19367 * In intersect mode, drag and drop interactio nis defined by the
19368 * overlap of two or more drag and drop objects.
19369 * @property INTERSECT
19376 * The current drag and drop mode. Default: POINT
19384 * Runs method on all drag and drop objects
19385 * @method _execOnAll
19389 _execOnAll: function(sMethod, args) {
19390 for (var i in this.ids) {
19391 for (var j in this.ids[i]) {
19392 var oDD = this.ids[i][j];
19393 if (! this.isTypeOfDD(oDD)) {
19396 oDD[sMethod].apply(oDD, args);
19402 * Drag and drop initialization. Sets up the global event handlers
19407 _onLoad: function() {
19411 if (!Roo.isTouch) {
19412 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19413 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19415 Event.on(document, "touchend", this.handleMouseUp, this, true);
19416 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19418 Event.on(window, "unload", this._onUnload, this, true);
19419 Event.on(window, "resize", this._onResize, this, true);
19420 // Event.on(window, "mouseout", this._test);
19425 * Reset constraints on all drag and drop objs
19426 * @method _onResize
19430 _onResize: function(e) {
19431 this._execOnAll("resetConstraints", []);
19435 * Lock all drag and drop functionality
19439 lock: function() { this.locked = true; },
19442 * Unlock all drag and drop functionality
19446 unlock: function() { this.locked = false; },
19449 * Is drag and drop locked?
19451 * @return {boolean} True if drag and drop is locked, false otherwise.
19454 isLocked: function() { return this.locked; },
19457 * Location cache that is set for all drag drop objects when a drag is
19458 * initiated, cleared when the drag is finished.
19459 * @property locationCache
19466 * Set useCache to false if you want to force object the lookup of each
19467 * drag and drop linked element constantly during a drag.
19468 * @property useCache
19475 * The number of pixels that the mouse needs to move after the
19476 * mousedown before the drag is initiated. Default=3;
19477 * @property clickPixelThresh
19481 clickPixelThresh: 3,
19484 * The number of milliseconds after the mousedown event to initiate the
19485 * drag if we don't get a mouseup event. Default=1000
19486 * @property clickTimeThresh
19490 clickTimeThresh: 350,
19493 * Flag that indicates that either the drag pixel threshold or the
19494 * mousdown time threshold has been met
19495 * @property dragThreshMet
19500 dragThreshMet: false,
19503 * Timeout used for the click time threshold
19504 * @property clickTimeout
19509 clickTimeout: null,
19512 * The X position of the mousedown event stored for later use when a
19513 * drag threshold is met.
19522 * The Y position of the mousedown event stored for later use when a
19523 * drag threshold is met.
19532 * Each DragDrop instance must be registered with the DragDropMgr.
19533 * This is executed in DragDrop.init()
19534 * @method regDragDrop
19535 * @param {DragDrop} oDD the DragDrop object to register
19536 * @param {String} sGroup the name of the group this element belongs to
19539 regDragDrop: function(oDD, sGroup) {
19540 if (!this.initialized) { this.init(); }
19542 if (!this.ids[sGroup]) {
19543 this.ids[sGroup] = {};
19545 this.ids[sGroup][oDD.id] = oDD;
19549 * Removes the supplied dd instance from the supplied group. Executed
19550 * by DragDrop.removeFromGroup, so don't call this function directly.
19551 * @method removeDDFromGroup
19555 removeDDFromGroup: function(oDD, sGroup) {
19556 if (!this.ids[sGroup]) {
19557 this.ids[sGroup] = {};
19560 var obj = this.ids[sGroup];
19561 if (obj && obj[oDD.id]) {
19562 delete obj[oDD.id];
19567 * Unregisters a drag and drop item. This is executed in
19568 * DragDrop.unreg, use that method instead of calling this directly.
19573 _remove: function(oDD) {
19574 for (var g in oDD.groups) {
19575 if (g && this.ids[g][oDD.id]) {
19576 delete this.ids[g][oDD.id];
19579 delete this.handleIds[oDD.id];
19583 * Each DragDrop handle element must be registered. This is done
19584 * automatically when executing DragDrop.setHandleElId()
19585 * @method regHandle
19586 * @param {String} sDDId the DragDrop id this element is a handle for
19587 * @param {String} sHandleId the id of the element that is the drag
19591 regHandle: function(sDDId, sHandleId) {
19592 if (!this.handleIds[sDDId]) {
19593 this.handleIds[sDDId] = {};
19595 this.handleIds[sDDId][sHandleId] = sHandleId;
19599 * Utility function to determine if a given element has been
19600 * registered as a drag drop item.
19601 * @method isDragDrop
19602 * @param {String} id the element id to check
19603 * @return {boolean} true if this element is a DragDrop item,
19607 isDragDrop: function(id) {
19608 return ( this.getDDById(id) ) ? true : false;
19612 * Returns the drag and drop instances that are in all groups the
19613 * passed in instance belongs to.
19614 * @method getRelated
19615 * @param {DragDrop} p_oDD the obj to get related data for
19616 * @param {boolean} bTargetsOnly if true, only return targetable objs
19617 * @return {DragDrop[]} the related instances
19620 getRelated: function(p_oDD, bTargetsOnly) {
19622 for (var i in p_oDD.groups) {
19623 for (j in this.ids[i]) {
19624 var dd = this.ids[i][j];
19625 if (! this.isTypeOfDD(dd)) {
19628 if (!bTargetsOnly || dd.isTarget) {
19629 oDDs[oDDs.length] = dd;
19638 * Returns true if the specified dd target is a legal target for
19639 * the specifice drag obj
19640 * @method isLegalTarget
19641 * @param {DragDrop} the drag obj
19642 * @param {DragDrop} the target
19643 * @return {boolean} true if the target is a legal target for the
19647 isLegalTarget: function (oDD, oTargetDD) {
19648 var targets = this.getRelated(oDD, true);
19649 for (var i=0, len=targets.length;i<len;++i) {
19650 if (targets[i].id == oTargetDD.id) {
19659 * My goal is to be able to transparently determine if an object is
19660 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19661 * returns "object", oDD.constructor.toString() always returns
19662 * "DragDrop" and not the name of the subclass. So for now it just
19663 * evaluates a well-known variable in DragDrop.
19664 * @method isTypeOfDD
19665 * @param {Object} the object to evaluate
19666 * @return {boolean} true if typeof oDD = DragDrop
19669 isTypeOfDD: function (oDD) {
19670 return (oDD && oDD.__ygDragDrop);
19674 * Utility function to determine if a given element has been
19675 * registered as a drag drop handle for the given Drag Drop object.
19677 * @param {String} id the element id to check
19678 * @return {boolean} true if this element is a DragDrop handle, false
19682 isHandle: function(sDDId, sHandleId) {
19683 return ( this.handleIds[sDDId] &&
19684 this.handleIds[sDDId][sHandleId] );
19688 * Returns the DragDrop instance for a given id
19689 * @method getDDById
19690 * @param {String} id the id of the DragDrop object
19691 * @return {DragDrop} the drag drop object, null if it is not found
19694 getDDById: function(id) {
19695 for (var i in this.ids) {
19696 if (this.ids[i][id]) {
19697 return this.ids[i][id];
19704 * Fired after a registered DragDrop object gets the mousedown event.
19705 * Sets up the events required to track the object being dragged
19706 * @method handleMouseDown
19707 * @param {Event} e the event
19708 * @param oDD the DragDrop object being dragged
19712 handleMouseDown: function(e, oDD) {
19714 Roo.QuickTips.disable();
19716 this.currentTarget = e.getTarget();
19718 this.dragCurrent = oDD;
19720 var el = oDD.getEl();
19722 // track start position
19723 this.startX = e.getPageX();
19724 this.startY = e.getPageY();
19726 this.deltaX = this.startX - el.offsetLeft;
19727 this.deltaY = this.startY - el.offsetTop;
19729 this.dragThreshMet = false;
19731 this.clickTimeout = setTimeout(
19733 var DDM = Roo.dd.DDM;
19734 DDM.startDrag(DDM.startX, DDM.startY);
19736 this.clickTimeThresh );
19740 * Fired when either the drag pixel threshol or the mousedown hold
19741 * time threshold has been met.
19742 * @method startDrag
19743 * @param x {int} the X position of the original mousedown
19744 * @param y {int} the Y position of the original mousedown
19747 startDrag: function(x, y) {
19748 clearTimeout(this.clickTimeout);
19749 if (this.dragCurrent) {
19750 this.dragCurrent.b4StartDrag(x, y);
19751 this.dragCurrent.startDrag(x, y);
19753 this.dragThreshMet = true;
19757 * Internal function to handle the mouseup event. Will be invoked
19758 * from the context of the document.
19759 * @method handleMouseUp
19760 * @param {Event} e the event
19764 handleMouseUp: function(e) {
19767 Roo.QuickTips.enable();
19769 if (! this.dragCurrent) {
19773 clearTimeout(this.clickTimeout);
19775 if (this.dragThreshMet) {
19776 this.fireEvents(e, true);
19786 * Utility to stop event propagation and event default, if these
19787 * features are turned on.
19788 * @method stopEvent
19789 * @param {Event} e the event as returned by this.getEvent()
19792 stopEvent: function(e){
19793 if(this.stopPropagation) {
19794 e.stopPropagation();
19797 if (this.preventDefault) {
19798 e.preventDefault();
19803 * Internal function to clean up event handlers after the drag
19804 * operation is complete
19806 * @param {Event} e the event
19810 stopDrag: function(e) {
19811 // Fire the drag end event for the item that was dragged
19812 if (this.dragCurrent) {
19813 if (this.dragThreshMet) {
19814 this.dragCurrent.b4EndDrag(e);
19815 this.dragCurrent.endDrag(e);
19818 this.dragCurrent.onMouseUp(e);
19821 this.dragCurrent = null;
19822 this.dragOvers = {};
19826 * Internal function to handle the mousemove event. Will be invoked
19827 * from the context of the html element.
19829 * @TODO figure out what we can do about mouse events lost when the
19830 * user drags objects beyond the window boundary. Currently we can
19831 * detect this in internet explorer by verifying that the mouse is
19832 * down during the mousemove event. Firefox doesn't give us the
19833 * button state on the mousemove event.
19834 * @method handleMouseMove
19835 * @param {Event} e the event
19839 handleMouseMove: function(e) {
19840 if (! this.dragCurrent) {
19844 // var button = e.which || e.button;
19846 // check for IE mouseup outside of page boundary
19847 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19849 return this.handleMouseUp(e);
19852 if (!this.dragThreshMet) {
19853 var diffX = Math.abs(this.startX - e.getPageX());
19854 var diffY = Math.abs(this.startY - e.getPageY());
19855 if (diffX > this.clickPixelThresh ||
19856 diffY > this.clickPixelThresh) {
19857 this.startDrag(this.startX, this.startY);
19861 if (this.dragThreshMet) {
19862 this.dragCurrent.b4Drag(e);
19863 this.dragCurrent.onDrag(e);
19864 if(!this.dragCurrent.moveOnly){
19865 this.fireEvents(e, false);
19875 * Iterates over all of the DragDrop elements to find ones we are
19876 * hovering over or dropping on
19877 * @method fireEvents
19878 * @param {Event} e the event
19879 * @param {boolean} isDrop is this a drop op or a mouseover op?
19883 fireEvents: function(e, isDrop) {
19884 var dc = this.dragCurrent;
19886 // If the user did the mouse up outside of the window, we could
19887 // get here even though we have ended the drag.
19888 if (!dc || dc.isLocked()) {
19892 var pt = e.getPoint();
19894 // cache the previous dragOver array
19900 var enterEvts = [];
19902 // Check to see if the object(s) we were hovering over is no longer
19903 // being hovered over so we can fire the onDragOut event
19904 for (var i in this.dragOvers) {
19906 var ddo = this.dragOvers[i];
19908 if (! this.isTypeOfDD(ddo)) {
19912 if (! this.isOverTarget(pt, ddo, this.mode)) {
19913 outEvts.push( ddo );
19916 oldOvers[i] = true;
19917 delete this.dragOvers[i];
19920 for (var sGroup in dc.groups) {
19922 if ("string" != typeof sGroup) {
19926 for (i in this.ids[sGroup]) {
19927 var oDD = this.ids[sGroup][i];
19928 if (! this.isTypeOfDD(oDD)) {
19932 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19933 if (this.isOverTarget(pt, oDD, this.mode)) {
19934 // look for drop interactions
19936 dropEvts.push( oDD );
19937 // look for drag enter and drag over interactions
19940 // initial drag over: dragEnter fires
19941 if (!oldOvers[oDD.id]) {
19942 enterEvts.push( oDD );
19943 // subsequent drag overs: dragOver fires
19945 overEvts.push( oDD );
19948 this.dragOvers[oDD.id] = oDD;
19956 if (outEvts.length) {
19957 dc.b4DragOut(e, outEvts);
19958 dc.onDragOut(e, outEvts);
19961 if (enterEvts.length) {
19962 dc.onDragEnter(e, enterEvts);
19965 if (overEvts.length) {
19966 dc.b4DragOver(e, overEvts);
19967 dc.onDragOver(e, overEvts);
19970 if (dropEvts.length) {
19971 dc.b4DragDrop(e, dropEvts);
19972 dc.onDragDrop(e, dropEvts);
19976 // fire dragout events
19978 for (i=0, len=outEvts.length; i<len; ++i) {
19979 dc.b4DragOut(e, outEvts[i].id);
19980 dc.onDragOut(e, outEvts[i].id);
19983 // fire enter events
19984 for (i=0,len=enterEvts.length; i<len; ++i) {
19985 // dc.b4DragEnter(e, oDD.id);
19986 dc.onDragEnter(e, enterEvts[i].id);
19989 // fire over events
19990 for (i=0,len=overEvts.length; i<len; ++i) {
19991 dc.b4DragOver(e, overEvts[i].id);
19992 dc.onDragOver(e, overEvts[i].id);
19995 // fire drop events
19996 for (i=0, len=dropEvts.length; i<len; ++i) {
19997 dc.b4DragDrop(e, dropEvts[i].id);
19998 dc.onDragDrop(e, dropEvts[i].id);
20003 // notify about a drop that did not find a target
20004 if (isDrop && !dropEvts.length) {
20005 dc.onInvalidDrop(e);
20011 * Helper function for getting the best match from the list of drag
20012 * and drop objects returned by the drag and drop events when we are
20013 * in INTERSECT mode. It returns either the first object that the
20014 * cursor is over, or the object that has the greatest overlap with
20015 * the dragged element.
20016 * @method getBestMatch
20017 * @param {DragDrop[]} dds The array of drag and drop objects
20019 * @return {DragDrop} The best single match
20022 getBestMatch: function(dds) {
20024 // Return null if the input is not what we expect
20025 //if (!dds || !dds.length || dds.length == 0) {
20027 // If there is only one item, it wins
20028 //} else if (dds.length == 1) {
20030 var len = dds.length;
20035 // Loop through the targeted items
20036 for (var i=0; i<len; ++i) {
20038 // If the cursor is over the object, it wins. If the
20039 // cursor is over multiple matches, the first one we come
20041 if (dd.cursorIsOver) {
20044 // Otherwise the object with the most overlap wins
20047 winner.overlap.getArea() < dd.overlap.getArea()) {
20058 * Refreshes the cache of the top-left and bottom-right points of the
20059 * drag and drop objects in the specified group(s). This is in the
20060 * format that is stored in the drag and drop instance, so typical
20063 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20067 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20069 * @TODO this really should be an indexed array. Alternatively this
20070 * method could accept both.
20071 * @method refreshCache
20072 * @param {Object} groups an associative array of groups to refresh
20075 refreshCache: function(groups) {
20076 for (var sGroup in groups) {
20077 if ("string" != typeof sGroup) {
20080 for (var i in this.ids[sGroup]) {
20081 var oDD = this.ids[sGroup][i];
20083 if (this.isTypeOfDD(oDD)) {
20084 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20085 var loc = this.getLocation(oDD);
20087 this.locationCache[oDD.id] = loc;
20089 delete this.locationCache[oDD.id];
20090 // this will unregister the drag and drop object if
20091 // the element is not in a usable state
20100 * This checks to make sure an element exists and is in the DOM. The
20101 * main purpose is to handle cases where innerHTML is used to remove
20102 * drag and drop objects from the DOM. IE provides an 'unspecified
20103 * error' when trying to access the offsetParent of such an element
20105 * @param {HTMLElement} el the element to check
20106 * @return {boolean} true if the element looks usable
20109 verifyEl: function(el) {
20114 parent = el.offsetParent;
20117 parent = el.offsetParent;
20128 * Returns a Region object containing the drag and drop element's position
20129 * and size, including the padding configured for it
20130 * @method getLocation
20131 * @param {DragDrop} oDD the drag and drop object to get the
20133 * @return {Roo.lib.Region} a Region object representing the total area
20134 * the element occupies, including any padding
20135 * the instance is configured for.
20138 getLocation: function(oDD) {
20139 if (! this.isTypeOfDD(oDD)) {
20143 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20146 pos= Roo.lib.Dom.getXY(el);
20154 x2 = x1 + el.offsetWidth;
20156 y2 = y1 + el.offsetHeight;
20158 t = y1 - oDD.padding[0];
20159 r = x2 + oDD.padding[1];
20160 b = y2 + oDD.padding[2];
20161 l = x1 - oDD.padding[3];
20163 return new Roo.lib.Region( t, r, b, l );
20167 * Checks the cursor location to see if it over the target
20168 * @method isOverTarget
20169 * @param {Roo.lib.Point} pt The point to evaluate
20170 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20171 * @return {boolean} true if the mouse is over the target
20175 isOverTarget: function(pt, oTarget, intersect) {
20176 // use cache if available
20177 var loc = this.locationCache[oTarget.id];
20178 if (!loc || !this.useCache) {
20179 loc = this.getLocation(oTarget);
20180 this.locationCache[oTarget.id] = loc;
20188 oTarget.cursorIsOver = loc.contains( pt );
20190 // DragDrop is using this as a sanity check for the initial mousedown
20191 // in this case we are done. In POINT mode, if the drag obj has no
20192 // contraints, we are also done. Otherwise we need to evaluate the
20193 // location of the target as related to the actual location of the
20194 // dragged element.
20195 var dc = this.dragCurrent;
20196 if (!dc || !dc.getTargetCoord ||
20197 (!intersect && !dc.constrainX && !dc.constrainY)) {
20198 return oTarget.cursorIsOver;
20201 oTarget.overlap = null;
20203 // Get the current location of the drag element, this is the
20204 // location of the mouse event less the delta that represents
20205 // where the original mousedown happened on the element. We
20206 // need to consider constraints and ticks as well.
20207 var pos = dc.getTargetCoord(pt.x, pt.y);
20209 var el = dc.getDragEl();
20210 var curRegion = new Roo.lib.Region( pos.y,
20211 pos.x + el.offsetWidth,
20212 pos.y + el.offsetHeight,
20215 var overlap = curRegion.intersect(loc);
20218 oTarget.overlap = overlap;
20219 return (intersect) ? true : oTarget.cursorIsOver;
20226 * unload event handler
20227 * @method _onUnload
20231 _onUnload: function(e, me) {
20232 Roo.dd.DragDropMgr.unregAll();
20236 * Cleans up the drag and drop events and objects.
20241 unregAll: function() {
20243 if (this.dragCurrent) {
20245 this.dragCurrent = null;
20248 this._execOnAll("unreg", []);
20250 for (i in this.elementCache) {
20251 delete this.elementCache[i];
20254 this.elementCache = {};
20259 * A cache of DOM elements
20260 * @property elementCache
20267 * Get the wrapper for the DOM element specified
20268 * @method getElWrapper
20269 * @param {String} id the id of the element to get
20270 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20272 * @deprecated This wrapper isn't that useful
20275 getElWrapper: function(id) {
20276 var oWrapper = this.elementCache[id];
20277 if (!oWrapper || !oWrapper.el) {
20278 oWrapper = this.elementCache[id] =
20279 new this.ElementWrapper(Roo.getDom(id));
20285 * Returns the actual DOM element
20286 * @method getElement
20287 * @param {String} id the id of the elment to get
20288 * @return {Object} The element
20289 * @deprecated use Roo.getDom instead
20292 getElement: function(id) {
20293 return Roo.getDom(id);
20297 * Returns the style property for the DOM element (i.e.,
20298 * document.getElById(id).style)
20300 * @param {String} id the id of the elment to get
20301 * @return {Object} The style property of the element
20302 * @deprecated use Roo.getDom instead
20305 getCss: function(id) {
20306 var el = Roo.getDom(id);
20307 return (el) ? el.style : null;
20311 * Inner class for cached elements
20312 * @class DragDropMgr.ElementWrapper
20317 ElementWrapper: function(el) {
20322 this.el = el || null;
20327 this.id = this.el && el.id;
20329 * A reference to the style property
20332 this.css = this.el && el.style;
20336 * Returns the X position of an html element
20338 * @param el the element for which to get the position
20339 * @return {int} the X coordinate
20341 * @deprecated use Roo.lib.Dom.getX instead
20344 getPosX: function(el) {
20345 return Roo.lib.Dom.getX(el);
20349 * Returns the Y position of an html element
20351 * @param el the element for which to get the position
20352 * @return {int} the Y coordinate
20353 * @deprecated use Roo.lib.Dom.getY instead
20356 getPosY: function(el) {
20357 return Roo.lib.Dom.getY(el);
20361 * Swap two nodes. In IE, we use the native method, for others we
20362 * emulate the IE behavior
20364 * @param n1 the first node to swap
20365 * @param n2 the other node to swap
20368 swapNode: function(n1, n2) {
20372 var p = n2.parentNode;
20373 var s = n2.nextSibling;
20376 p.insertBefore(n1, n2);
20377 } else if (n2 == n1.nextSibling) {
20378 p.insertBefore(n2, n1);
20380 n1.parentNode.replaceChild(n2, n1);
20381 p.insertBefore(n1, s);
20387 * Returns the current scroll position
20388 * @method getScroll
20392 getScroll: function () {
20393 var t, l, dde=document.documentElement, db=document.body;
20394 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20396 l = dde.scrollLeft;
20403 return { top: t, left: l };
20407 * Returns the specified element style property
20409 * @param {HTMLElement} el the element
20410 * @param {string} styleProp the style property
20411 * @return {string} The value of the style property
20412 * @deprecated use Roo.lib.Dom.getStyle
20415 getStyle: function(el, styleProp) {
20416 return Roo.fly(el).getStyle(styleProp);
20420 * Gets the scrollTop
20421 * @method getScrollTop
20422 * @return {int} the document's scrollTop
20425 getScrollTop: function () { return this.getScroll().top; },
20428 * Gets the scrollLeft
20429 * @method getScrollLeft
20430 * @return {int} the document's scrollTop
20433 getScrollLeft: function () { return this.getScroll().left; },
20436 * Sets the x/y position of an element to the location of the
20439 * @param {HTMLElement} moveEl The element to move
20440 * @param {HTMLElement} targetEl The position reference element
20443 moveToEl: function (moveEl, targetEl) {
20444 var aCoord = Roo.lib.Dom.getXY(targetEl);
20445 Roo.lib.Dom.setXY(moveEl, aCoord);
20449 * Numeric array sort function
20450 * @method numericSort
20453 numericSort: function(a, b) { return (a - b); },
20457 * @property _timeoutCount
20464 * Trying to make the load order less important. Without this we get
20465 * an error if this file is loaded before the Event Utility.
20466 * @method _addListeners
20470 _addListeners: function() {
20471 var DDM = Roo.dd.DDM;
20472 if ( Roo.lib.Event && document ) {
20475 if (DDM._timeoutCount > 2000) {
20477 setTimeout(DDM._addListeners, 10);
20478 if (document && document.body) {
20479 DDM._timeoutCount += 1;
20486 * Recursively searches the immediate parent and all child nodes for
20487 * the handle element in order to determine wheter or not it was
20489 * @method handleWasClicked
20490 * @param node the html element to inspect
20493 handleWasClicked: function(node, id) {
20494 if (this.isHandle(id, node.id)) {
20497 // check to see if this is a text node child of the one we want
20498 var p = node.parentNode;
20501 if (this.isHandle(id, p.id)) {
20516 // shorter alias, save a few bytes
20517 Roo.dd.DDM = Roo.dd.DragDropMgr;
20518 Roo.dd.DDM._addListeners();
20522 * Ext JS Library 1.1.1
20523 * Copyright(c) 2006-2007, Ext JS, LLC.
20525 * Originally Released Under LGPL - original licence link has changed is not relivant.
20528 * <script type="text/javascript">
20533 * A DragDrop implementation where the linked element follows the
20534 * mouse cursor during a drag.
20535 * @extends Roo.dd.DragDrop
20537 * @param {String} id the id of the linked element
20538 * @param {String} sGroup the group of related DragDrop items
20539 * @param {object} config an object containing configurable attributes
20540 * Valid properties for DD:
20543 Roo.dd.DD = function(id, sGroup, config) {
20545 this.init(id, sGroup, config);
20549 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20552 * When set to true, the utility automatically tries to scroll the browser
20553 * window wehn a drag and drop element is dragged near the viewport boundary.
20554 * Defaults to true.
20561 * Sets the pointer offset to the distance between the linked element's top
20562 * left corner and the location the element was clicked
20563 * @method autoOffset
20564 * @param {int} iPageX the X coordinate of the click
20565 * @param {int} iPageY the Y coordinate of the click
20567 autoOffset: function(iPageX, iPageY) {
20568 var x = iPageX - this.startPageX;
20569 var y = iPageY - this.startPageY;
20570 this.setDelta(x, y);
20574 * Sets the pointer offset. You can call this directly to force the
20575 * offset to be in a particular location (e.g., pass in 0,0 to set it
20576 * to the center of the object)
20578 * @param {int} iDeltaX the distance from the left
20579 * @param {int} iDeltaY the distance from the top
20581 setDelta: function(iDeltaX, iDeltaY) {
20582 this.deltaX = iDeltaX;
20583 this.deltaY = iDeltaY;
20587 * Sets the drag element to the location of the mousedown or click event,
20588 * maintaining the cursor location relative to the location on the element
20589 * that was clicked. Override this if you want to place the element in a
20590 * location other than where the cursor is.
20591 * @method setDragElPos
20592 * @param {int} iPageX the X coordinate of the mousedown or drag event
20593 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20595 setDragElPos: function(iPageX, iPageY) {
20596 // the first time we do this, we are going to check to make sure
20597 // the element has css positioning
20599 var el = this.getDragEl();
20600 this.alignElWithMouse(el, iPageX, iPageY);
20604 * Sets the element to the location of the mousedown or click event,
20605 * maintaining the cursor location relative to the location on the element
20606 * that was clicked. Override this if you want to place the element in a
20607 * location other than where the cursor is.
20608 * @method alignElWithMouse
20609 * @param {HTMLElement} el the element to move
20610 * @param {int} iPageX the X coordinate of the mousedown or drag event
20611 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20613 alignElWithMouse: function(el, iPageX, iPageY) {
20614 var oCoord = this.getTargetCoord(iPageX, iPageY);
20615 var fly = el.dom ? el : Roo.fly(el);
20616 if (!this.deltaSetXY) {
20617 var aCoord = [oCoord.x, oCoord.y];
20619 var newLeft = fly.getLeft(true);
20620 var newTop = fly.getTop(true);
20621 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20623 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20626 this.cachePosition(oCoord.x, oCoord.y);
20627 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20632 * Saves the most recent position so that we can reset the constraints and
20633 * tick marks on-demand. We need to know this so that we can calculate the
20634 * number of pixels the element is offset from its original position.
20635 * @method cachePosition
20636 * @param iPageX the current x position (optional, this just makes it so we
20637 * don't have to look it up again)
20638 * @param iPageY the current y position (optional, this just makes it so we
20639 * don't have to look it up again)
20641 cachePosition: function(iPageX, iPageY) {
20643 this.lastPageX = iPageX;
20644 this.lastPageY = iPageY;
20646 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20647 this.lastPageX = aCoord[0];
20648 this.lastPageY = aCoord[1];
20653 * Auto-scroll the window if the dragged object has been moved beyond the
20654 * visible window boundary.
20655 * @method autoScroll
20656 * @param {int} x the drag element's x position
20657 * @param {int} y the drag element's y position
20658 * @param {int} h the height of the drag element
20659 * @param {int} w the width of the drag element
20662 autoScroll: function(x, y, h, w) {
20665 // The client height
20666 var clientH = Roo.lib.Dom.getViewWidth();
20668 // The client width
20669 var clientW = Roo.lib.Dom.getViewHeight();
20671 // The amt scrolled down
20672 var st = this.DDM.getScrollTop();
20674 // The amt scrolled right
20675 var sl = this.DDM.getScrollLeft();
20677 // Location of the bottom of the element
20680 // Location of the right of the element
20683 // The distance from the cursor to the bottom of the visible area,
20684 // adjusted so that we don't scroll if the cursor is beyond the
20685 // element drag constraints
20686 var toBot = (clientH + st - y - this.deltaY);
20688 // The distance from the cursor to the right of the visible area
20689 var toRight = (clientW + sl - x - this.deltaX);
20692 // How close to the edge the cursor must be before we scroll
20693 // var thresh = (document.all) ? 100 : 40;
20696 // How many pixels to scroll per autoscroll op. This helps to reduce
20697 // clunky scrolling. IE is more sensitive about this ... it needs this
20698 // value to be higher.
20699 var scrAmt = (document.all) ? 80 : 30;
20701 // Scroll down if we are near the bottom of the visible page and the
20702 // obj extends below the crease
20703 if ( bot > clientH && toBot < thresh ) {
20704 window.scrollTo(sl, st + scrAmt);
20707 // Scroll up if the window is scrolled down and the top of the object
20708 // goes above the top border
20709 if ( y < st && st > 0 && y - st < thresh ) {
20710 window.scrollTo(sl, st - scrAmt);
20713 // Scroll right if the obj is beyond the right border and the cursor is
20714 // near the border.
20715 if ( right > clientW && toRight < thresh ) {
20716 window.scrollTo(sl + scrAmt, st);
20719 // Scroll left if the window has been scrolled to the right and the obj
20720 // extends past the left border
20721 if ( x < sl && sl > 0 && x - sl < thresh ) {
20722 window.scrollTo(sl - scrAmt, st);
20728 * Finds the location the element should be placed if we want to move
20729 * it to where the mouse location less the click offset would place us.
20730 * @method getTargetCoord
20731 * @param {int} iPageX the X coordinate of the click
20732 * @param {int} iPageY the Y coordinate of the click
20733 * @return an object that contains the coordinates (Object.x and Object.y)
20736 getTargetCoord: function(iPageX, iPageY) {
20739 var x = iPageX - this.deltaX;
20740 var y = iPageY - this.deltaY;
20742 if (this.constrainX) {
20743 if (x < this.minX) { x = this.minX; }
20744 if (x > this.maxX) { x = this.maxX; }
20747 if (this.constrainY) {
20748 if (y < this.minY) { y = this.minY; }
20749 if (y > this.maxY) { y = this.maxY; }
20752 x = this.getTick(x, this.xTicks);
20753 y = this.getTick(y, this.yTicks);
20760 * Sets up config options specific to this class. Overrides
20761 * Roo.dd.DragDrop, but all versions of this method through the
20762 * inheritance chain are called
20764 applyConfig: function() {
20765 Roo.dd.DD.superclass.applyConfig.call(this);
20766 this.scroll = (this.config.scroll !== false);
20770 * Event that fires prior to the onMouseDown event. Overrides
20773 b4MouseDown: function(e) {
20774 // this.resetConstraints();
20775 this.autoOffset(e.getPageX(),
20780 * Event that fires prior to the onDrag event. Overrides
20783 b4Drag: function(e) {
20784 this.setDragElPos(e.getPageX(),
20788 toString: function() {
20789 return ("DD " + this.id);
20792 //////////////////////////////////////////////////////////////////////////
20793 // Debugging ygDragDrop events that can be overridden
20794 //////////////////////////////////////////////////////////////////////////
20796 startDrag: function(x, y) {
20799 onDrag: function(e) {
20802 onDragEnter: function(e, id) {
20805 onDragOver: function(e, id) {
20808 onDragOut: function(e, id) {
20811 onDragDrop: function(e, id) {
20814 endDrag: function(e) {
20821 * Ext JS Library 1.1.1
20822 * Copyright(c) 2006-2007, Ext JS, LLC.
20824 * Originally Released Under LGPL - original licence link has changed is not relivant.
20827 * <script type="text/javascript">
20831 * @class Roo.dd.DDProxy
20832 * A DragDrop implementation that inserts an empty, bordered div into
20833 * the document that follows the cursor during drag operations. At the time of
20834 * the click, the frame div is resized to the dimensions of the linked html
20835 * element, and moved to the exact location of the linked element.
20837 * References to the "frame" element refer to the single proxy element that
20838 * was created to be dragged in place of all DDProxy elements on the
20841 * @extends Roo.dd.DD
20843 * @param {String} id the id of the linked html element
20844 * @param {String} sGroup the group of related DragDrop objects
20845 * @param {object} config an object containing configurable attributes
20846 * Valid properties for DDProxy in addition to those in DragDrop:
20847 * resizeFrame, centerFrame, dragElId
20849 Roo.dd.DDProxy = function(id, sGroup, config) {
20851 this.init(id, sGroup, config);
20857 * The default drag frame div id
20858 * @property Roo.dd.DDProxy.dragElId
20862 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20864 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20867 * By default we resize the drag frame to be the same size as the element
20868 * we want to drag (this is to get the frame effect). We can turn it off
20869 * if we want a different behavior.
20870 * @property resizeFrame
20876 * By default the frame is positioned exactly where the drag element is, so
20877 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20878 * you do not have constraints on the obj is to have the drag frame centered
20879 * around the cursor. Set centerFrame to true for this effect.
20880 * @property centerFrame
20883 centerFrame: false,
20886 * Creates the proxy element if it does not yet exist
20887 * @method createFrame
20889 createFrame: function() {
20891 var body = document.body;
20893 if (!body || !body.firstChild) {
20894 setTimeout( function() { self.createFrame(); }, 50 );
20898 var div = this.getDragEl();
20901 div = document.createElement("div");
20902 div.id = this.dragElId;
20905 s.position = "absolute";
20906 s.visibility = "hidden";
20908 s.border = "2px solid #aaa";
20911 // appendChild can blow up IE if invoked prior to the window load event
20912 // while rendering a table. It is possible there are other scenarios
20913 // that would cause this to happen as well.
20914 body.insertBefore(div, body.firstChild);
20919 * Initialization for the drag frame element. Must be called in the
20920 * constructor of all subclasses
20921 * @method initFrame
20923 initFrame: function() {
20924 this.createFrame();
20927 applyConfig: function() {
20928 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20930 this.resizeFrame = (this.config.resizeFrame !== false);
20931 this.centerFrame = (this.config.centerFrame);
20932 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20936 * Resizes the drag frame to the dimensions of the clicked object, positions
20937 * it over the object, and finally displays it
20938 * @method showFrame
20939 * @param {int} iPageX X click position
20940 * @param {int} iPageY Y click position
20943 showFrame: function(iPageX, iPageY) {
20944 var el = this.getEl();
20945 var dragEl = this.getDragEl();
20946 var s = dragEl.style;
20948 this._resizeProxy();
20950 if (this.centerFrame) {
20951 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20952 Math.round(parseInt(s.height, 10)/2) );
20955 this.setDragElPos(iPageX, iPageY);
20957 Roo.fly(dragEl).show();
20961 * The proxy is automatically resized to the dimensions of the linked
20962 * element when a drag is initiated, unless resizeFrame is set to false
20963 * @method _resizeProxy
20966 _resizeProxy: function() {
20967 if (this.resizeFrame) {
20968 var el = this.getEl();
20969 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20973 // overrides Roo.dd.DragDrop
20974 b4MouseDown: function(e) {
20975 var x = e.getPageX();
20976 var y = e.getPageY();
20977 this.autoOffset(x, y);
20978 this.setDragElPos(x, y);
20981 // overrides Roo.dd.DragDrop
20982 b4StartDrag: function(x, y) {
20983 // show the drag frame
20984 this.showFrame(x, y);
20987 // overrides Roo.dd.DragDrop
20988 b4EndDrag: function(e) {
20989 Roo.fly(this.getDragEl()).hide();
20992 // overrides Roo.dd.DragDrop
20993 // By default we try to move the element to the last location of the frame.
20994 // This is so that the default behavior mirrors that of Roo.dd.DD.
20995 endDrag: function(e) {
20997 var lel = this.getEl();
20998 var del = this.getDragEl();
21000 // Show the drag frame briefly so we can get its position
21001 del.style.visibility = "";
21004 // Hide the linked element before the move to get around a Safari
21006 lel.style.visibility = "hidden";
21007 Roo.dd.DDM.moveToEl(lel, del);
21008 del.style.visibility = "hidden";
21009 lel.style.visibility = "";
21014 beforeMove : function(){
21018 afterDrag : function(){
21022 toString: function() {
21023 return ("DDProxy " + this.id);
21029 * Ext JS Library 1.1.1
21030 * Copyright(c) 2006-2007, Ext JS, LLC.
21032 * Originally Released Under LGPL - original licence link has changed is not relivant.
21035 * <script type="text/javascript">
21039 * @class Roo.dd.DDTarget
21040 * A DragDrop implementation that does not move, but can be a drop
21041 * target. You would get the same result by simply omitting implementation
21042 * for the event callbacks, but this way we reduce the processing cost of the
21043 * event listener and the callbacks.
21044 * @extends Roo.dd.DragDrop
21046 * @param {String} id the id of the element that is a drop target
21047 * @param {String} sGroup the group of related DragDrop objects
21048 * @param {object} config an object containing configurable attributes
21049 * Valid properties for DDTarget in addition to those in
21053 Roo.dd.DDTarget = function(id, sGroup, config) {
21055 this.initTarget(id, sGroup, config);
21057 if (config.listeners || config.events) {
21058 Roo.dd.DragDrop.superclass.constructor.call(this, {
21059 listeners : config.listeners || {},
21060 events : config.events || {}
21065 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21066 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21067 toString: function() {
21068 return ("DDTarget " + this.id);
21073 * Ext JS Library 1.1.1
21074 * Copyright(c) 2006-2007, Ext JS, LLC.
21076 * Originally Released Under LGPL - original licence link has changed is not relivant.
21079 * <script type="text/javascript">
21084 * @class Roo.dd.ScrollManager
21085 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21086 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21089 Roo.dd.ScrollManager = function(){
21090 var ddm = Roo.dd.DragDropMgr;
21097 var onStop = function(e){
21102 var triggerRefresh = function(){
21103 if(ddm.dragCurrent){
21104 ddm.refreshCache(ddm.dragCurrent.groups);
21108 var doScroll = function(){
21109 if(ddm.dragCurrent){
21110 var dds = Roo.dd.ScrollManager;
21112 if(proc.el.scroll(proc.dir, dds.increment)){
21116 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21121 var clearProc = function(){
21123 clearInterval(proc.id);
21130 var startProc = function(el, dir){
21131 Roo.log('scroll startproc');
21135 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21138 var onFire = function(e, isDrop){
21140 if(isDrop || !ddm.dragCurrent){ return; }
21141 var dds = Roo.dd.ScrollManager;
21142 if(!dragEl || dragEl != ddm.dragCurrent){
21143 dragEl = ddm.dragCurrent;
21144 // refresh regions on drag start
21145 dds.refreshCache();
21148 var xy = Roo.lib.Event.getXY(e);
21149 var pt = new Roo.lib.Point(xy[0], xy[1]);
21150 for(var id in els){
21151 var el = els[id], r = el._region;
21152 if(r && r.contains(pt) && el.isScrollable()){
21153 if(r.bottom - pt.y <= dds.thresh){
21155 startProc(el, "down");
21158 }else if(r.right - pt.x <= dds.thresh){
21160 startProc(el, "left");
21163 }else if(pt.y - r.top <= dds.thresh){
21165 startProc(el, "up");
21168 }else if(pt.x - r.left <= dds.thresh){
21170 startProc(el, "right");
21179 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21180 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21184 * Registers new overflow element(s) to auto scroll
21185 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21187 register : function(el){
21188 if(el instanceof Array){
21189 for(var i = 0, len = el.length; i < len; i++) {
21190 this.register(el[i]);
21196 Roo.dd.ScrollManager.els = els;
21200 * Unregisters overflow element(s) so they are no longer scrolled
21201 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21203 unregister : function(el){
21204 if(el instanceof Array){
21205 for(var i = 0, len = el.length; i < len; i++) {
21206 this.unregister(el[i]);
21215 * The number of pixels from the edge of a container the pointer needs to be to
21216 * trigger scrolling (defaults to 25)
21222 * The number of pixels to scroll in each scroll increment (defaults to 50)
21228 * The frequency of scrolls in milliseconds (defaults to 500)
21234 * True to animate the scroll (defaults to true)
21240 * The animation duration in seconds -
21241 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21247 * Manually trigger a cache refresh.
21249 refreshCache : function(){
21250 for(var id in els){
21251 if(typeof els[id] == 'object'){ // for people extending the object prototype
21252 els[id]._region = els[id].getRegion();
21259 * Ext JS Library 1.1.1
21260 * Copyright(c) 2006-2007, Ext JS, LLC.
21262 * Originally Released Under LGPL - original licence link has changed is not relivant.
21265 * <script type="text/javascript">
21270 * @class Roo.dd.Registry
21271 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21272 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21275 Roo.dd.Registry = function(){
21278 var autoIdSeed = 0;
21280 var getId = function(el, autogen){
21281 if(typeof el == "string"){
21285 if(!id && autogen !== false){
21286 id = "roodd-" + (++autoIdSeed);
21294 * Register a drag drop element
21295 * @param {String|HTMLElement} element The id or DOM node to register
21296 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21297 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21298 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21299 * populated in the data object (if applicable):
21301 Value Description<br />
21302 --------- ------------------------------------------<br />
21303 handles Array of DOM nodes that trigger dragging<br />
21304 for the element being registered<br />
21305 isHandle True if the element passed in triggers<br />
21306 dragging itself, else false
21309 register : function(el, data){
21311 if(typeof el == "string"){
21312 el = document.getElementById(el);
21315 elements[getId(el)] = data;
21316 if(data.isHandle !== false){
21317 handles[data.ddel.id] = data;
21320 var hs = data.handles;
21321 for(var i = 0, len = hs.length; i < len; i++){
21322 handles[getId(hs[i])] = data;
21328 * Unregister a drag drop element
21329 * @param {String|HTMLElement} element The id or DOM node to unregister
21331 unregister : function(el){
21332 var id = getId(el, false);
21333 var data = elements[id];
21335 delete elements[id];
21337 var hs = data.handles;
21338 for(var i = 0, len = hs.length; i < len; i++){
21339 delete handles[getId(hs[i], false)];
21346 * Returns the handle registered for a DOM Node by id
21347 * @param {String|HTMLElement} id The DOM node or id to look up
21348 * @return {Object} handle The custom handle data
21350 getHandle : function(id){
21351 if(typeof id != "string"){ // must be element?
21354 return handles[id];
21358 * Returns the handle that is registered for the DOM node that is the target of the event
21359 * @param {Event} e The event
21360 * @return {Object} handle The custom handle data
21362 getHandleFromEvent : function(e){
21363 var t = Roo.lib.Event.getTarget(e);
21364 return t ? handles[t.id] : null;
21368 * Returns a custom data object that is registered for a DOM node by id
21369 * @param {String|HTMLElement} id The DOM node or id to look up
21370 * @return {Object} data The custom data
21372 getTarget : function(id){
21373 if(typeof id != "string"){ // must be element?
21376 return elements[id];
21380 * Returns a custom data object that is registered for the DOM node that is the target of the event
21381 * @param {Event} e The event
21382 * @return {Object} data The custom data
21384 getTargetFromEvent : function(e){
21385 var t = Roo.lib.Event.getTarget(e);
21386 return t ? elements[t.id] || handles[t.id] : null;
21391 * Ext JS Library 1.1.1
21392 * Copyright(c) 2006-2007, Ext JS, LLC.
21394 * Originally Released Under LGPL - original licence link has changed is not relivant.
21397 * <script type="text/javascript">
21402 * @class Roo.dd.StatusProxy
21403 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21404 * default drag proxy used by all Roo.dd components.
21406 * @param {Object} config
21408 Roo.dd.StatusProxy = function(config){
21409 Roo.apply(this, config);
21410 this.id = this.id || Roo.id();
21411 this.el = new Roo.Layer({
21413 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21414 {tag: "div", cls: "x-dd-drop-icon"},
21415 {tag: "div", cls: "x-dd-drag-ghost"}
21418 shadow: !config || config.shadow !== false
21420 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21421 this.dropStatus = this.dropNotAllowed;
21424 Roo.dd.StatusProxy.prototype = {
21426 * @cfg {String} dropAllowed
21427 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21429 dropAllowed : "x-dd-drop-ok",
21431 * @cfg {String} dropNotAllowed
21432 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21434 dropNotAllowed : "x-dd-drop-nodrop",
21437 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21438 * over the current target element.
21439 * @param {String} cssClass The css class for the new drop status indicator image
21441 setStatus : function(cssClass){
21442 cssClass = cssClass || this.dropNotAllowed;
21443 if(this.dropStatus != cssClass){
21444 this.el.replaceClass(this.dropStatus, cssClass);
21445 this.dropStatus = cssClass;
21450 * Resets the status indicator to the default dropNotAllowed value
21451 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21453 reset : function(clearGhost){
21454 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21455 this.dropStatus = this.dropNotAllowed;
21457 this.ghost.update("");
21462 * Updates the contents of the ghost element
21463 * @param {String} html The html that will replace the current innerHTML of the ghost element
21465 update : function(html){
21466 if(typeof html == "string"){
21467 this.ghost.update(html);
21469 this.ghost.update("");
21470 html.style.margin = "0";
21471 this.ghost.dom.appendChild(html);
21473 // ensure float = none set?? cant remember why though.
21474 var el = this.ghost.dom.firstChild;
21476 Roo.fly(el).setStyle('float', 'none');
21481 * Returns the underlying proxy {@link Roo.Layer}
21482 * @return {Roo.Layer} el
21484 getEl : function(){
21489 * Returns the ghost element
21490 * @return {Roo.Element} el
21492 getGhost : function(){
21498 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21500 hide : function(clear){
21508 * Stops the repair animation if it's currently running
21511 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21517 * Displays this proxy
21524 * Force the Layer to sync its shadow and shim positions to the element
21531 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21532 * invalid drop operation by the item being dragged.
21533 * @param {Array} xy The XY position of the element ([x, y])
21534 * @param {Function} callback The function to call after the repair is complete
21535 * @param {Object} scope The scope in which to execute the callback
21537 repair : function(xy, callback, scope){
21538 this.callback = callback;
21539 this.scope = scope;
21540 if(xy && this.animRepair !== false){
21541 this.el.addClass("x-dd-drag-repair");
21542 this.el.hideUnders(true);
21543 this.anim = this.el.shift({
21544 duration: this.repairDuration || .5,
21548 callback: this.afterRepair,
21552 this.afterRepair();
21557 afterRepair : function(){
21559 if(typeof this.callback == "function"){
21560 this.callback.call(this.scope || this);
21562 this.callback = null;
21567 * Ext JS Library 1.1.1
21568 * Copyright(c) 2006-2007, Ext JS, LLC.
21570 * Originally Released Under LGPL - original licence link has changed is not relivant.
21573 * <script type="text/javascript">
21577 * @class Roo.dd.DragSource
21578 * @extends Roo.dd.DDProxy
21579 * A simple class that provides the basic implementation needed to make any element draggable.
21581 * @param {String/HTMLElement/Element} el The container element
21582 * @param {Object} config
21584 Roo.dd.DragSource = function(el, config){
21585 this.el = Roo.get(el);
21586 this.dragData = {};
21588 Roo.apply(this, config);
21591 this.proxy = new Roo.dd.StatusProxy();
21594 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21595 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21597 this.dragging = false;
21600 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21602 * @cfg {String} dropAllowed
21603 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21605 dropAllowed : "x-dd-drop-ok",
21607 * @cfg {String} dropNotAllowed
21608 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21610 dropNotAllowed : "x-dd-drop-nodrop",
21613 * Returns the data object associated with this drag source
21614 * @return {Object} data An object containing arbitrary data
21616 getDragData : function(e){
21617 return this.dragData;
21621 onDragEnter : function(e, id){
21622 var target = Roo.dd.DragDropMgr.getDDById(id);
21623 this.cachedTarget = target;
21624 if(this.beforeDragEnter(target, e, id) !== false){
21625 if(target.isNotifyTarget){
21626 var status = target.notifyEnter(this, e, this.dragData);
21627 this.proxy.setStatus(status);
21629 this.proxy.setStatus(this.dropAllowed);
21632 if(this.afterDragEnter){
21634 * An empty function by default, but provided so that you can perform a custom action
21635 * when the dragged item enters the drop target by providing an implementation.
21636 * @param {Roo.dd.DragDrop} target The drop target
21637 * @param {Event} e The event object
21638 * @param {String} id The id of the dragged element
21639 * @method afterDragEnter
21641 this.afterDragEnter(target, e, id);
21647 * An empty function by default, but provided so that you can perform a custom action
21648 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21649 * @param {Roo.dd.DragDrop} target The drop target
21650 * @param {Event} e The event object
21651 * @param {String} id The id of the dragged element
21652 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21654 beforeDragEnter : function(target, e, id){
21659 alignElWithMouse: function() {
21660 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21665 onDragOver : function(e, id){
21666 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21667 if(this.beforeDragOver(target, e, id) !== false){
21668 if(target.isNotifyTarget){
21669 var status = target.notifyOver(this, e, this.dragData);
21670 this.proxy.setStatus(status);
21673 if(this.afterDragOver){
21675 * An empty function by default, but provided so that you can perform a custom action
21676 * while the dragged item is over the drop target by providing an implementation.
21677 * @param {Roo.dd.DragDrop} target The drop target
21678 * @param {Event} e The event object
21679 * @param {String} id The id of the dragged element
21680 * @method afterDragOver
21682 this.afterDragOver(target, e, id);
21688 * An empty function by default, but provided so that you can perform a custom action
21689 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21690 * @param {Roo.dd.DragDrop} target The drop target
21691 * @param {Event} e The event object
21692 * @param {String} id The id of the dragged element
21693 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21695 beforeDragOver : function(target, e, id){
21700 onDragOut : function(e, id){
21701 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21702 if(this.beforeDragOut(target, e, id) !== false){
21703 if(target.isNotifyTarget){
21704 target.notifyOut(this, e, this.dragData);
21706 this.proxy.reset();
21707 if(this.afterDragOut){
21709 * An empty function by default, but provided so that you can perform a custom action
21710 * after the dragged item is dragged out of the target without dropping.
21711 * @param {Roo.dd.DragDrop} target The drop target
21712 * @param {Event} e The event object
21713 * @param {String} id The id of the dragged element
21714 * @method afterDragOut
21716 this.afterDragOut(target, e, id);
21719 this.cachedTarget = null;
21723 * An empty function by default, but provided so that you can perform a custom action before the dragged
21724 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21725 * @param {Roo.dd.DragDrop} target The drop target
21726 * @param {Event} e The event object
21727 * @param {String} id The id of the dragged element
21728 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21730 beforeDragOut : function(target, e, id){
21735 onDragDrop : function(e, id){
21736 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21737 if(this.beforeDragDrop(target, e, id) !== false){
21738 if(target.isNotifyTarget){
21739 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21740 this.onValidDrop(target, e, id);
21742 this.onInvalidDrop(target, e, id);
21745 this.onValidDrop(target, e, id);
21748 if(this.afterDragDrop){
21750 * An empty function by default, but provided so that you can perform a custom action
21751 * after a valid drag drop has occurred by providing an implementation.
21752 * @param {Roo.dd.DragDrop} target The drop target
21753 * @param {Event} e The event object
21754 * @param {String} id The id of the dropped element
21755 * @method afterDragDrop
21757 this.afterDragDrop(target, e, id);
21760 delete this.cachedTarget;
21764 * An empty function by default, but provided so that you can perform a custom action before the dragged
21765 * item is dropped onto the target and optionally cancel the onDragDrop.
21766 * @param {Roo.dd.DragDrop} target The drop target
21767 * @param {Event} e The event object
21768 * @param {String} id The id of the dragged element
21769 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21771 beforeDragDrop : function(target, e, id){
21776 onValidDrop : function(target, e, id){
21778 if(this.afterValidDrop){
21780 * An empty function by default, but provided so that you can perform a custom action
21781 * after a valid drop has occurred by providing an implementation.
21782 * @param {Object} target The target DD
21783 * @param {Event} e The event object
21784 * @param {String} id The id of the dropped element
21785 * @method afterInvalidDrop
21787 this.afterValidDrop(target, e, id);
21792 getRepairXY : function(e, data){
21793 return this.el.getXY();
21797 onInvalidDrop : function(target, e, id){
21798 this.beforeInvalidDrop(target, e, id);
21799 if(this.cachedTarget){
21800 if(this.cachedTarget.isNotifyTarget){
21801 this.cachedTarget.notifyOut(this, e, this.dragData);
21803 this.cacheTarget = null;
21805 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21807 if(this.afterInvalidDrop){
21809 * An empty function by default, but provided so that you can perform a custom action
21810 * after an invalid drop has occurred by providing an implementation.
21811 * @param {Event} e The event object
21812 * @param {String} id The id of the dropped element
21813 * @method afterInvalidDrop
21815 this.afterInvalidDrop(e, id);
21820 afterRepair : function(){
21822 this.el.highlight(this.hlColor || "c3daf9");
21824 this.dragging = false;
21828 * An empty function by default, but provided so that you can perform a custom action after an invalid
21829 * drop has occurred.
21830 * @param {Roo.dd.DragDrop} target The drop target
21831 * @param {Event} e The event object
21832 * @param {String} id The id of the dragged element
21833 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21835 beforeInvalidDrop : function(target, e, id){
21840 handleMouseDown : function(e){
21841 if(this.dragging) {
21844 var data = this.getDragData(e);
21845 if(data && this.onBeforeDrag(data, e) !== false){
21846 this.dragData = data;
21848 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21853 * An empty function by default, but provided so that you can perform a custom action before the initial
21854 * drag event begins and optionally cancel it.
21855 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21856 * @param {Event} e The event object
21857 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21859 onBeforeDrag : function(data, e){
21864 * An empty function by default, but provided so that you can perform a custom action once the initial
21865 * drag event has begun. The drag cannot be canceled from this function.
21866 * @param {Number} x The x position of the click on the dragged object
21867 * @param {Number} y The y position of the click on the dragged object
21869 onStartDrag : Roo.emptyFn,
21871 // private - YUI override
21872 startDrag : function(x, y){
21873 this.proxy.reset();
21874 this.dragging = true;
21875 this.proxy.update("");
21876 this.onInitDrag(x, y);
21881 onInitDrag : function(x, y){
21882 var clone = this.el.dom.cloneNode(true);
21883 clone.id = Roo.id(); // prevent duplicate ids
21884 this.proxy.update(clone);
21885 this.onStartDrag(x, y);
21890 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21891 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21893 getProxy : function(){
21898 * Hides the drag source's {@link Roo.dd.StatusProxy}
21900 hideProxy : function(){
21902 this.proxy.reset(true);
21903 this.dragging = false;
21907 triggerCacheRefresh : function(){
21908 Roo.dd.DDM.refreshCache(this.groups);
21911 // private - override to prevent hiding
21912 b4EndDrag: function(e) {
21915 // private - override to prevent moving
21916 endDrag : function(e){
21917 this.onEndDrag(this.dragData, e);
21921 onEndDrag : function(data, e){
21924 // private - pin to cursor
21925 autoOffset : function(x, y) {
21926 this.setDelta(-12, -20);
21930 * Ext JS Library 1.1.1
21931 * Copyright(c) 2006-2007, Ext JS, LLC.
21933 * Originally Released Under LGPL - original licence link has changed is not relivant.
21936 * <script type="text/javascript">
21941 * @class Roo.dd.DropTarget
21942 * @extends Roo.dd.DDTarget
21943 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21944 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21946 * @param {String/HTMLElement/Element} el The container element
21947 * @param {Object} config
21949 Roo.dd.DropTarget = function(el, config){
21950 this.el = Roo.get(el);
21952 var listeners = false; ;
21953 if (config && config.listeners) {
21954 listeners= config.listeners;
21955 delete config.listeners;
21957 Roo.apply(this, config);
21959 if(this.containerScroll){
21960 Roo.dd.ScrollManager.register(this.el);
21964 * @scope Roo.dd.DropTarget
21969 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21970 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21971 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21973 * IMPORTANT : it should set this.overClass and this.dropAllowed
21975 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21976 * @param {Event} e The event
21977 * @param {Object} data An object containing arbitrary data supplied by the drag source
21983 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21984 * This method will be called on every mouse movement while the drag source is over the drop target.
21985 * This default implementation simply returns the dropAllowed config value.
21987 * IMPORTANT : it should set this.dropAllowed
21989 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21990 * @param {Event} e The event
21991 * @param {Object} data An object containing arbitrary data supplied by the drag source
21997 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21998 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21999 * overClass (if any) from the drop element.
22001 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22002 * @param {Event} e The event
22003 * @param {Object} data An object containing arbitrary data supplied by the drag source
22009 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22010 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22011 * implementation that does something to process the drop event and returns true so that the drag source's
22012 * repair action does not run.
22014 * IMPORTANT : it should set this.success
22016 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22017 * @param {Event} e The event
22018 * @param {Object} data An object containing arbitrary data supplied by the drag source
22024 Roo.dd.DropTarget.superclass.constructor.call( this,
22026 this.ddGroup || this.group,
22029 listeners : listeners || {}
22037 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22039 * @cfg {String} overClass
22040 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22043 * @cfg {String} ddGroup
22044 * The drag drop group to handle drop events for
22048 * @cfg {String} dropAllowed
22049 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22051 dropAllowed : "x-dd-drop-ok",
22053 * @cfg {String} dropNotAllowed
22054 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22056 dropNotAllowed : "x-dd-drop-nodrop",
22058 * @cfg {boolean} success
22059 * set this after drop listener..
22063 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22064 * if the drop point is valid for over/enter..
22071 isNotifyTarget : true,
22076 notifyEnter : function(dd, e, data)
22079 this.fireEvent('enter', dd, e, data);
22080 if(this.overClass){
22081 this.el.addClass(this.overClass);
22083 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22084 this.valid ? this.dropAllowed : this.dropNotAllowed
22091 notifyOver : function(dd, e, data)
22094 this.fireEvent('over', dd, e, data);
22095 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22096 this.valid ? this.dropAllowed : this.dropNotAllowed
22103 notifyOut : function(dd, e, data)
22105 this.fireEvent('out', dd, e, data);
22106 if(this.overClass){
22107 this.el.removeClass(this.overClass);
22114 notifyDrop : function(dd, e, data)
22116 this.success = false;
22117 this.fireEvent('drop', dd, e, data);
22118 return this.success;
22122 * Ext JS Library 1.1.1
22123 * Copyright(c) 2006-2007, Ext JS, LLC.
22125 * Originally Released Under LGPL - original licence link has changed is not relivant.
22128 * <script type="text/javascript">
22133 * @class Roo.dd.DragZone
22134 * @extends Roo.dd.DragSource
22135 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22136 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22138 * @param {String/HTMLElement/Element} el The container element
22139 * @param {Object} config
22141 Roo.dd.DragZone = function(el, config){
22142 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22143 if(this.containerScroll){
22144 Roo.dd.ScrollManager.register(this.el);
22148 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22150 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22151 * for auto scrolling during drag operations.
22154 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22155 * method after a failed drop (defaults to "c3daf9" - light blue)
22159 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22160 * for a valid target to drag based on the mouse down. Override this method
22161 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22162 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22163 * @param {EventObject} e The mouse down event
22164 * @return {Object} The dragData
22166 getDragData : function(e){
22167 return Roo.dd.Registry.getHandleFromEvent(e);
22171 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22172 * this.dragData.ddel
22173 * @param {Number} x The x position of the click on the dragged object
22174 * @param {Number} y The y position of the click on the dragged object
22175 * @return {Boolean} true to continue the drag, false to cancel
22177 onInitDrag : function(x, y){
22178 this.proxy.update(this.dragData.ddel.cloneNode(true));
22179 this.onStartDrag(x, y);
22184 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22186 afterRepair : function(){
22188 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22190 this.dragging = false;
22194 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22195 * the XY of this.dragData.ddel
22196 * @param {EventObject} e The mouse up event
22197 * @return {Array} The xy location (e.g. [100, 200])
22199 getRepairXY : function(e){
22200 return Roo.Element.fly(this.dragData.ddel).getXY();
22204 * Ext JS Library 1.1.1
22205 * Copyright(c) 2006-2007, Ext JS, LLC.
22207 * Originally Released Under LGPL - original licence link has changed is not relivant.
22210 * <script type="text/javascript">
22213 * @class Roo.dd.DropZone
22214 * @extends Roo.dd.DropTarget
22215 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22216 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22218 * @param {String/HTMLElement/Element} el The container element
22219 * @param {Object} config
22221 Roo.dd.DropZone = function(el, config){
22222 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22225 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22227 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22228 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22229 * provide your own custom lookup.
22230 * @param {Event} e The event
22231 * @return {Object} data The custom data
22233 getTargetFromEvent : function(e){
22234 return Roo.dd.Registry.getTargetFromEvent(e);
22238 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22239 * that it has registered. This method has no default implementation and should be overridden to provide
22240 * node-specific processing if necessary.
22241 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22242 * {@link #getTargetFromEvent} for this node)
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
22247 onNodeEnter : function(n, dd, e, data){
22252 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22253 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22254 * overridden to provide the proper feedback.
22255 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22256 * {@link #getTargetFromEvent} for this node)
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 onNodeOver : function(n, dd, e, data){
22264 return this.dropAllowed;
22268 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22269 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22270 * node-specific processing if necessary.
22271 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22272 * {@link #getTargetFromEvent} for this node)
22273 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22274 * @param {Event} e The event
22275 * @param {Object} data An object containing arbitrary data supplied by the drag source
22277 onNodeOut : function(n, dd, e, data){
22282 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22283 * the drop node. The default implementation returns false, so it should be overridden to provide the
22284 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22285 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22286 * {@link #getTargetFromEvent} for this node)
22287 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22288 * @param {Event} e The event
22289 * @param {Object} data An object containing arbitrary data supplied by the drag source
22290 * @return {Boolean} True if the drop was valid, else false
22292 onNodeDrop : function(n, dd, e, data){
22297 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22298 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22299 * it should be overridden to provide the proper feedback if necessary.
22300 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22301 * @param {Event} e The event
22302 * @param {Object} data An object containing arbitrary data supplied by the drag source
22303 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22304 * underlying {@link Roo.dd.StatusProxy} can be updated
22306 onContainerOver : function(dd, e, data){
22307 return this.dropNotAllowed;
22311 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22312 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22313 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22314 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22315 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22316 * @param {Event} e The event
22317 * @param {Object} data An object containing arbitrary data supplied by the drag source
22318 * @return {Boolean} True if the drop was valid, else false
22320 onContainerDrop : function(dd, e, data){
22325 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22326 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22327 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22328 * you should override this method and provide a custom implementation.
22329 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22330 * @param {Event} e The event
22331 * @param {Object} data An object containing arbitrary data supplied by the drag source
22332 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22333 * underlying {@link Roo.dd.StatusProxy} can be updated
22335 notifyEnter : function(dd, e, data){
22336 return this.dropNotAllowed;
22340 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22341 * This method will be called on every mouse movement while the drag source is over the drop zone.
22342 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22343 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22344 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22345 * registered node, it will call {@link #onContainerOver}.
22346 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22347 * @param {Event} e The event
22348 * @param {Object} data An object containing arbitrary data supplied by the drag source
22349 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22350 * underlying {@link Roo.dd.StatusProxy} can be updated
22352 notifyOver : function(dd, e, data){
22353 var n = this.getTargetFromEvent(e);
22354 if(!n){ // not over valid drop target
22355 if(this.lastOverNode){
22356 this.onNodeOut(this.lastOverNode, dd, e, data);
22357 this.lastOverNode = null;
22359 return this.onContainerOver(dd, e, data);
22361 if(this.lastOverNode != n){
22362 if(this.lastOverNode){
22363 this.onNodeOut(this.lastOverNode, dd, e, data);
22365 this.onNodeEnter(n, dd, e, data);
22366 this.lastOverNode = n;
22368 return this.onNodeOver(n, dd, e, data);
22372 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22373 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22374 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22375 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22376 * @param {Event} e The event
22377 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22379 notifyOut : function(dd, e, data){
22380 if(this.lastOverNode){
22381 this.onNodeOut(this.lastOverNode, dd, e, data);
22382 this.lastOverNode = null;
22387 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22388 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22389 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22390 * otherwise it will call {@link #onContainerDrop}.
22391 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22392 * @param {Event} e The event
22393 * @param {Object} data An object containing arbitrary data supplied by the drag source
22394 * @return {Boolean} True if the drop was valid, else false
22396 notifyDrop : function(dd, e, data){
22397 if(this.lastOverNode){
22398 this.onNodeOut(this.lastOverNode, dd, e, data);
22399 this.lastOverNode = null;
22401 var n = this.getTargetFromEvent(e);
22403 this.onNodeDrop(n, dd, e, data) :
22404 this.onContainerDrop(dd, e, data);
22408 triggerCacheRefresh : function(){
22409 Roo.dd.DDM.refreshCache(this.groups);
22413 * Ext JS Library 1.1.1
22414 * Copyright(c) 2006-2007, Ext JS, LLC.
22416 * Originally Released Under LGPL - original licence link has changed is not relivant.
22419 * <script type="text/javascript">
22424 * @class Roo.data.SortTypes
22426 * Defines the default sorting (casting?) comparison functions used when sorting data.
22428 Roo.data.SortTypes = {
22430 * Default sort that does nothing
22431 * @param {Mixed} s The value being converted
22432 * @return {Mixed} The comparison value
22434 none : function(s){
22439 * The regular expression used to strip tags
22443 stripTagsRE : /<\/?[^>]+>/gi,
22446 * Strips all HTML tags to sort on text only
22447 * @param {Mixed} s The value being converted
22448 * @return {String} The comparison value
22450 asText : function(s){
22451 return String(s).replace(this.stripTagsRE, "");
22455 * Strips all HTML tags to sort on text only - Case insensitive
22456 * @param {Mixed} s The value being converted
22457 * @return {String} The comparison value
22459 asUCText : function(s){
22460 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22464 * Case insensitive string
22465 * @param {Mixed} s The value being converted
22466 * @return {String} The comparison value
22468 asUCString : function(s) {
22469 return String(s).toUpperCase();
22474 * @param {Mixed} s The value being converted
22475 * @return {Number} The comparison value
22477 asDate : function(s) {
22481 if(s instanceof Date){
22482 return s.getTime();
22484 return Date.parse(String(s));
22489 * @param {Mixed} s The value being converted
22490 * @return {Float} The comparison value
22492 asFloat : function(s) {
22493 var val = parseFloat(String(s).replace(/,/g, ""));
22502 * @param {Mixed} s The value being converted
22503 * @return {Number} The comparison value
22505 asInt : function(s) {
22506 var val = parseInt(String(s).replace(/,/g, ""));
22514 * Ext JS Library 1.1.1
22515 * Copyright(c) 2006-2007, Ext JS, LLC.
22517 * Originally Released Under LGPL - original licence link has changed is not relivant.
22520 * <script type="text/javascript">
22524 * @class Roo.data.Record
22525 * Instances of this class encapsulate both record <em>definition</em> information, and record
22526 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22527 * to access Records cached in an {@link Roo.data.Store} object.<br>
22529 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22530 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22533 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22535 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22536 * {@link #create}. The parameters are the same.
22537 * @param {Array} data An associative Array of data values keyed by the field name.
22538 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22539 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22540 * not specified an integer id is generated.
22542 Roo.data.Record = function(data, id){
22543 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22548 * Generate a constructor for a specific record layout.
22549 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22550 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22551 * Each field definition object may contain the following properties: <ul>
22552 * <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,
22553 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22554 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22555 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22556 * is being used, then this is a string containing the javascript expression to reference the data relative to
22557 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22558 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22559 * this may be omitted.</p></li>
22560 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22561 * <ul><li>auto (Default, implies no conversion)</li>
22566 * <li>date</li></ul></p></li>
22567 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22568 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22569 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22570 * by the Reader into an object that will be stored in the Record. It is passed the
22571 * following parameters:<ul>
22572 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22574 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22576 * <br>usage:<br><pre><code>
22577 var TopicRecord = Roo.data.Record.create(
22578 {name: 'title', mapping: 'topic_title'},
22579 {name: 'author', mapping: 'username'},
22580 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22581 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22582 {name: 'lastPoster', mapping: 'user2'},
22583 {name: 'excerpt', mapping: 'post_text'}
22586 var myNewRecord = new TopicRecord({
22587 title: 'Do my job please',
22590 lastPost: new Date(),
22591 lastPoster: 'Animal',
22592 excerpt: 'No way dude!'
22594 myStore.add(myNewRecord);
22599 Roo.data.Record.create = function(o){
22600 var f = function(){
22601 f.superclass.constructor.apply(this, arguments);
22603 Roo.extend(f, Roo.data.Record);
22604 var p = f.prototype;
22605 p.fields = new Roo.util.MixedCollection(false, function(field){
22608 for(var i = 0, len = o.length; i < len; i++){
22609 p.fields.add(new Roo.data.Field(o[i]));
22611 f.getField = function(name){
22612 return p.fields.get(name);
22617 Roo.data.Record.AUTO_ID = 1000;
22618 Roo.data.Record.EDIT = 'edit';
22619 Roo.data.Record.REJECT = 'reject';
22620 Roo.data.Record.COMMIT = 'commit';
22622 Roo.data.Record.prototype = {
22624 * Readonly flag - true if this record has been modified.
22633 join : function(store){
22634 this.store = store;
22638 * Set the named field to the specified value.
22639 * @param {String} name The name of the field to set.
22640 * @param {Object} value The value to set the field to.
22642 set : function(name, value){
22643 if(this.data[name] == value){
22647 if(!this.modified){
22648 this.modified = {};
22650 if(typeof this.modified[name] == 'undefined'){
22651 this.modified[name] = this.data[name];
22653 this.data[name] = value;
22654 if(!this.editing && this.store){
22655 this.store.afterEdit(this);
22660 * Get the value of the named field.
22661 * @param {String} name The name of the field to get the value of.
22662 * @return {Object} The value of the field.
22664 get : function(name){
22665 return this.data[name];
22669 beginEdit : function(){
22670 this.editing = true;
22671 this.modified = {};
22675 cancelEdit : function(){
22676 this.editing = false;
22677 delete this.modified;
22681 endEdit : function(){
22682 this.editing = false;
22683 if(this.dirty && this.store){
22684 this.store.afterEdit(this);
22689 * Usually called by the {@link Roo.data.Store} which owns the Record.
22690 * Rejects all changes made to the Record since either creation, or the last commit operation.
22691 * Modified fields are reverted to their original values.
22693 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22694 * of reject operations.
22696 reject : function(){
22697 var m = this.modified;
22699 if(typeof m[n] != "function"){
22700 this.data[n] = m[n];
22703 this.dirty = false;
22704 delete this.modified;
22705 this.editing = false;
22707 this.store.afterReject(this);
22712 * Usually called by the {@link Roo.data.Store} which owns the Record.
22713 * Commits all changes made to the Record since either creation, or the last commit operation.
22715 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22716 * of commit operations.
22718 commit : function(){
22719 this.dirty = false;
22720 delete this.modified;
22721 this.editing = false;
22723 this.store.afterCommit(this);
22728 hasError : function(){
22729 return this.error != null;
22733 clearError : function(){
22738 * Creates a copy of this record.
22739 * @param {String} id (optional) A new record id if you don't want to use this record's id
22742 copy : function(newId) {
22743 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22747 * Ext JS Library 1.1.1
22748 * Copyright(c) 2006-2007, Ext JS, LLC.
22750 * Originally Released Under LGPL - original licence link has changed is not relivant.
22753 * <script type="text/javascript">
22759 * @class Roo.data.Store
22760 * @extends Roo.util.Observable
22761 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22762 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22764 * 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
22765 * has no knowledge of the format of the data returned by the Proxy.<br>
22767 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22768 * instances from the data object. These records are cached and made available through accessor functions.
22770 * Creates a new Store.
22771 * @param {Object} config A config object containing the objects needed for the Store to access data,
22772 * and read the data into Records.
22774 Roo.data.Store = function(config){
22775 this.data = new Roo.util.MixedCollection(false);
22776 this.data.getKey = function(o){
22779 this.baseParams = {};
22781 this.paramNames = {
22786 "multisort" : "_multisort"
22789 if(config && config.data){
22790 this.inlineData = config.data;
22791 delete config.data;
22794 Roo.apply(this, config);
22796 if(this.reader){ // reader passed
22797 this.reader = Roo.factory(this.reader, Roo.data);
22798 this.reader.xmodule = this.xmodule || false;
22799 if(!this.recordType){
22800 this.recordType = this.reader.recordType;
22802 if(this.reader.onMetaChange){
22803 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22807 if(this.recordType){
22808 this.fields = this.recordType.prototype.fields;
22810 this.modified = [];
22814 * @event datachanged
22815 * Fires when the data cache has changed, and a widget which is using this Store
22816 * as a Record cache should refresh its view.
22817 * @param {Store} this
22819 datachanged : true,
22821 * @event metachange
22822 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22823 * @param {Store} this
22824 * @param {Object} meta The JSON metadata
22829 * Fires when Records have been added to the Store
22830 * @param {Store} this
22831 * @param {Roo.data.Record[]} records The array of Records added
22832 * @param {Number} index The index at which the record(s) were added
22837 * Fires when a Record has been removed from the Store
22838 * @param {Store} this
22839 * @param {Roo.data.Record} record The Record that was removed
22840 * @param {Number} index The index at which the record was removed
22845 * Fires when a Record has been updated
22846 * @param {Store} this
22847 * @param {Roo.data.Record} record The Record that was updated
22848 * @param {String} operation The update operation being performed. Value may be one of:
22850 Roo.data.Record.EDIT
22851 Roo.data.Record.REJECT
22852 Roo.data.Record.COMMIT
22858 * Fires when the data cache has been cleared.
22859 * @param {Store} this
22863 * @event beforeload
22864 * Fires before a request is made for a new data object. If the beforeload handler returns false
22865 * the load action will be canceled.
22866 * @param {Store} this
22867 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22871 * @event beforeloadadd
22872 * Fires after a new set of Records has been loaded.
22873 * @param {Store} this
22874 * @param {Roo.data.Record[]} records The Records that were loaded
22875 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22877 beforeloadadd : true,
22880 * Fires after a new set of Records has been loaded, before they are added to the store.
22881 * @param {Store} this
22882 * @param {Roo.data.Record[]} records The Records that were loaded
22883 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22884 * @params {Object} return from reader
22888 * @event loadexception
22889 * Fires if an exception occurs in the Proxy during loading.
22890 * Called with the signature of the Proxy's "loadexception" event.
22891 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22894 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22895 * @param {Object} load options
22896 * @param {Object} jsonData from your request (normally this contains the Exception)
22898 loadexception : true
22902 this.proxy = Roo.factory(this.proxy, Roo.data);
22903 this.proxy.xmodule = this.xmodule || false;
22904 this.relayEvents(this.proxy, ["loadexception"]);
22906 this.sortToggle = {};
22907 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22909 Roo.data.Store.superclass.constructor.call(this);
22911 if(this.inlineData){
22912 this.loadData(this.inlineData);
22913 delete this.inlineData;
22917 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22919 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22920 * without a remote query - used by combo/forms at present.
22924 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22927 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22930 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22931 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22934 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22935 * on any HTTP request
22938 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22941 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22945 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22946 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22948 remoteSort : false,
22951 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22952 * loaded or when a record is removed. (defaults to false).
22954 pruneModifiedRecords : false,
22957 lastOptions : null,
22960 * Add Records to the Store and fires the add event.
22961 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22963 add : function(records){
22964 records = [].concat(records);
22965 for(var i = 0, len = records.length; i < len; i++){
22966 records[i].join(this);
22968 var index = this.data.length;
22969 this.data.addAll(records);
22970 this.fireEvent("add", this, records, index);
22974 * Remove a Record from the Store and fires the remove event.
22975 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22977 remove : function(record){
22978 var index = this.data.indexOf(record);
22979 this.data.removeAt(index);
22981 if(this.pruneModifiedRecords){
22982 this.modified.remove(record);
22984 this.fireEvent("remove", this, record, index);
22988 * Remove all Records from the Store and fires the clear event.
22990 removeAll : function(){
22992 if(this.pruneModifiedRecords){
22993 this.modified = [];
22995 this.fireEvent("clear", this);
22999 * Inserts Records to the Store at the given index and fires the add event.
23000 * @param {Number} index The start index at which to insert the passed Records.
23001 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23003 insert : function(index, records){
23004 records = [].concat(records);
23005 for(var i = 0, len = records.length; i < len; i++){
23006 this.data.insert(index, records[i]);
23007 records[i].join(this);
23009 this.fireEvent("add", this, records, index);
23013 * Get the index within the cache of the passed Record.
23014 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23015 * @return {Number} The index of the passed Record. Returns -1 if not found.
23017 indexOf : function(record){
23018 return this.data.indexOf(record);
23022 * Get the index within the cache of the Record with the passed id.
23023 * @param {String} id The id of the Record to find.
23024 * @return {Number} The index of the Record. Returns -1 if not found.
23026 indexOfId : function(id){
23027 return this.data.indexOfKey(id);
23031 * Get the Record with the specified id.
23032 * @param {String} id The id of the Record to find.
23033 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23035 getById : function(id){
23036 return this.data.key(id);
23040 * Get the Record at the specified index.
23041 * @param {Number} index The index of the Record to find.
23042 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23044 getAt : function(index){
23045 return this.data.itemAt(index);
23049 * Returns a range of Records between specified indices.
23050 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23051 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23052 * @return {Roo.data.Record[]} An array of Records
23054 getRange : function(start, end){
23055 return this.data.getRange(start, end);
23059 storeOptions : function(o){
23060 o = Roo.apply({}, o);
23063 this.lastOptions = o;
23067 * Loads the Record cache from the configured Proxy using the configured Reader.
23069 * If using remote paging, then the first load call must specify the <em>start</em>
23070 * and <em>limit</em> properties in the options.params property to establish the initial
23071 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23073 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23074 * and this call will return before the new data has been loaded. Perform any post-processing
23075 * in a callback function, or in a "load" event handler.</strong>
23077 * @param {Object} options An object containing properties which control loading options:<ul>
23078 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23079 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23080 * passed the following arguments:<ul>
23081 * <li>r : Roo.data.Record[]</li>
23082 * <li>options: Options object from the load call</li>
23083 * <li>success: Boolean success indicator</li></ul></li>
23084 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23085 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23088 load : function(options){
23089 options = options || {};
23090 if(this.fireEvent("beforeload", this, options) !== false){
23091 this.storeOptions(options);
23092 var p = Roo.apply(options.params || {}, this.baseParams);
23093 // if meta was not loaded from remote source.. try requesting it.
23094 if (!this.reader.metaFromRemote) {
23095 p._requestMeta = 1;
23097 if(this.sortInfo && this.remoteSort){
23098 var pn = this.paramNames;
23099 p[pn["sort"]] = this.sortInfo.field;
23100 p[pn["dir"]] = this.sortInfo.direction;
23102 if (this.multiSort) {
23103 var pn = this.paramNames;
23104 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23107 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23112 * Reloads the Record cache from the configured Proxy using the configured Reader and
23113 * the options from the last load operation performed.
23114 * @param {Object} options (optional) An object containing properties which may override the options
23115 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23116 * the most recently used options are reused).
23118 reload : function(options){
23119 this.load(Roo.applyIf(options||{}, this.lastOptions));
23123 // Called as a callback by the Reader during a load operation.
23124 loadRecords : function(o, options, success){
23125 if(!o || success === false){
23126 if(success !== false){
23127 this.fireEvent("load", this, [], options, o);
23129 if(options.callback){
23130 options.callback.call(options.scope || this, [], options, false);
23134 // if data returned failure - throw an exception.
23135 if (o.success === false) {
23136 // show a message if no listener is registered.
23137 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23138 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23140 // loadmask wil be hooked into this..
23141 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23144 var r = o.records, t = o.totalRecords || r.length;
23146 this.fireEvent("beforeloadadd", this, r, options, o);
23148 if(!options || options.add !== true){
23149 if(this.pruneModifiedRecords){
23150 this.modified = [];
23152 for(var i = 0, len = r.length; i < len; i++){
23156 this.data = this.snapshot;
23157 delete this.snapshot;
23160 this.data.addAll(r);
23161 this.totalLength = t;
23163 this.fireEvent("datachanged", this);
23165 this.totalLength = Math.max(t, this.data.length+r.length);
23169 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23171 var e = new Roo.data.Record({});
23173 e.set(this.parent.displayField, this.parent.emptyTitle);
23174 e.set(this.parent.valueField, '');
23179 this.fireEvent("load", this, r, options, o);
23180 if(options.callback){
23181 options.callback.call(options.scope || this, r, options, true);
23187 * Loads data from a passed data block. A Reader which understands the format of the data
23188 * must have been configured in the constructor.
23189 * @param {Object} data The data block from which to read the Records. The format of the data expected
23190 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23191 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23193 loadData : function(o, append){
23194 var r = this.reader.readRecords(o);
23195 this.loadRecords(r, {add: append}, true);
23199 * Gets the number of cached records.
23201 * <em>If using paging, this may not be the total size of the dataset. If the data object
23202 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23203 * the data set size</em>
23205 getCount : function(){
23206 return this.data.length || 0;
23210 * Gets the total number of records in the dataset as returned by the server.
23212 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23213 * the dataset size</em>
23215 getTotalCount : function(){
23216 return this.totalLength || 0;
23220 * Returns the sort state of the Store as an object with two properties:
23222 field {String} The name of the field by which the Records are sorted
23223 direction {String} The sort order, "ASC" or "DESC"
23226 getSortState : function(){
23227 return this.sortInfo;
23231 applySort : function(){
23232 if(this.sortInfo && !this.remoteSort){
23233 var s = this.sortInfo, f = s.field;
23234 var st = this.fields.get(f).sortType;
23235 var fn = function(r1, r2){
23236 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23237 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23239 this.data.sort(s.direction, fn);
23240 if(this.snapshot && this.snapshot != this.data){
23241 this.snapshot.sort(s.direction, fn);
23247 * Sets the default sort column and order to be used by the next load operation.
23248 * @param {String} fieldName The name of the field to sort by.
23249 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23251 setDefaultSort : function(field, dir){
23252 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23256 * Sort the Records.
23257 * If remote sorting is used, the sort is performed on the server, and the cache is
23258 * reloaded. If local sorting is used, the cache is sorted internally.
23259 * @param {String} fieldName The name of the field to sort by.
23260 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23262 sort : function(fieldName, dir){
23263 var f = this.fields.get(fieldName);
23265 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23267 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23268 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23273 this.sortToggle[f.name] = dir;
23274 this.sortInfo = {field: f.name, direction: dir};
23275 if(!this.remoteSort){
23277 this.fireEvent("datachanged", this);
23279 this.load(this.lastOptions);
23284 * Calls the specified function for each of the Records in the cache.
23285 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23286 * Returning <em>false</em> aborts and exits the iteration.
23287 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23289 each : function(fn, scope){
23290 this.data.each(fn, scope);
23294 * Gets all records modified since the last commit. Modified records are persisted across load operations
23295 * (e.g., during paging).
23296 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23298 getModifiedRecords : function(){
23299 return this.modified;
23303 createFilterFn : function(property, value, anyMatch){
23304 if(!value.exec){ // not a regex
23305 value = String(value);
23306 if(value.length == 0){
23309 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23311 return function(r){
23312 return value.test(r.data[property]);
23317 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23318 * @param {String} property A field on your records
23319 * @param {Number} start The record index to start at (defaults to 0)
23320 * @param {Number} end The last record index to include (defaults to length - 1)
23321 * @return {Number} The sum
23323 sum : function(property, start, end){
23324 var rs = this.data.items, v = 0;
23325 start = start || 0;
23326 end = (end || end === 0) ? end : rs.length-1;
23328 for(var i = start; i <= end; i++){
23329 v += (rs[i].data[property] || 0);
23335 * Filter the records by a specified property.
23336 * @param {String} field A field on your records
23337 * @param {String/RegExp} value Either a string that the field
23338 * should start with or a RegExp to test against the field
23339 * @param {Boolean} anyMatch True to match any part not just the beginning
23341 filter : function(property, value, anyMatch){
23342 var fn = this.createFilterFn(property, value, anyMatch);
23343 return fn ? this.filterBy(fn) : this.clearFilter();
23347 * Filter by a function. The specified function will be called with each
23348 * record in this data source. If the function returns true the record is included,
23349 * otherwise it is filtered.
23350 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23351 * @param {Object} scope (optional) The scope of the function (defaults to this)
23353 filterBy : function(fn, scope){
23354 this.snapshot = this.snapshot || this.data;
23355 this.data = this.queryBy(fn, scope||this);
23356 this.fireEvent("datachanged", this);
23360 * Query the records by a specified property.
23361 * @param {String} field A field on your records
23362 * @param {String/RegExp} value Either a string that the field
23363 * should start with or a RegExp to test against the field
23364 * @param {Boolean} anyMatch True to match any part not just the beginning
23365 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23367 query : function(property, value, anyMatch){
23368 var fn = this.createFilterFn(property, value, anyMatch);
23369 return fn ? this.queryBy(fn) : this.data.clone();
23373 * Query by a function. The specified function will be called with each
23374 * record in this data source. If the function returns true the record is included
23376 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23377 * @param {Object} scope (optional) The scope of the function (defaults to this)
23378 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23380 queryBy : function(fn, scope){
23381 var data = this.snapshot || this.data;
23382 return data.filterBy(fn, scope||this);
23386 * Collects unique values for a particular dataIndex from this store.
23387 * @param {String} dataIndex The property to collect
23388 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23389 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23390 * @return {Array} An array of the unique values
23392 collect : function(dataIndex, allowNull, bypassFilter){
23393 var d = (bypassFilter === true && this.snapshot) ?
23394 this.snapshot.items : this.data.items;
23395 var v, sv, r = [], l = {};
23396 for(var i = 0, len = d.length; i < len; i++){
23397 v = d[i].data[dataIndex];
23399 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23408 * Revert to a view of the Record cache with no filtering applied.
23409 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23411 clearFilter : function(suppressEvent){
23412 if(this.snapshot && this.snapshot != this.data){
23413 this.data = this.snapshot;
23414 delete this.snapshot;
23415 if(suppressEvent !== true){
23416 this.fireEvent("datachanged", this);
23422 afterEdit : function(record){
23423 if(this.modified.indexOf(record) == -1){
23424 this.modified.push(record);
23426 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23430 afterReject : function(record){
23431 this.modified.remove(record);
23432 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23436 afterCommit : function(record){
23437 this.modified.remove(record);
23438 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23442 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23443 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23445 commitChanges : function(){
23446 var m = this.modified.slice(0);
23447 this.modified = [];
23448 for(var i = 0, len = m.length; i < len; i++){
23454 * Cancel outstanding changes on all changed records.
23456 rejectChanges : function(){
23457 var m = this.modified.slice(0);
23458 this.modified = [];
23459 for(var i = 0, len = m.length; i < len; i++){
23464 onMetaChange : function(meta, rtype, o){
23465 this.recordType = rtype;
23466 this.fields = rtype.prototype.fields;
23467 delete this.snapshot;
23468 this.sortInfo = meta.sortInfo || this.sortInfo;
23469 this.modified = [];
23470 this.fireEvent('metachange', this, this.reader.meta);
23473 moveIndex : function(data, type)
23475 var index = this.indexOf(data);
23477 var newIndex = index + type;
23481 this.insert(newIndex, data);
23486 * Ext JS Library 1.1.1
23487 * Copyright(c) 2006-2007, Ext JS, LLC.
23489 * Originally Released Under LGPL - original licence link has changed is not relivant.
23492 * <script type="text/javascript">
23496 * @class Roo.data.SimpleStore
23497 * @extends Roo.data.Store
23498 * Small helper class to make creating Stores from Array data easier.
23499 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23500 * @cfg {Array} fields An array of field definition objects, or field name strings.
23501 * @cfg {Array} data The multi-dimensional array of data
23503 * @param {Object} config
23505 Roo.data.SimpleStore = function(config){
23506 Roo.data.SimpleStore.superclass.constructor.call(this, {
23508 reader: new Roo.data.ArrayReader({
23511 Roo.data.Record.create(config.fields)
23513 proxy : new Roo.data.MemoryProxy(config.data)
23517 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23519 * Ext JS Library 1.1.1
23520 * Copyright(c) 2006-2007, Ext JS, LLC.
23522 * Originally Released Under LGPL - original licence link has changed is not relivant.
23525 * <script type="text/javascript">
23530 * @extends Roo.data.Store
23531 * @class Roo.data.JsonStore
23532 * Small helper class to make creating Stores for JSON data easier. <br/>
23534 var store = new Roo.data.JsonStore({
23535 url: 'get-images.php',
23537 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23540 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23541 * JsonReader and HttpProxy (unless inline data is provided).</b>
23542 * @cfg {Array} fields An array of field definition objects, or field name strings.
23544 * @param {Object} config
23546 Roo.data.JsonStore = function(c){
23547 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23548 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23549 reader: new Roo.data.JsonReader(c, c.fields)
23552 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23554 * Ext JS Library 1.1.1
23555 * Copyright(c) 2006-2007, Ext JS, LLC.
23557 * Originally Released Under LGPL - original licence link has changed is not relivant.
23560 * <script type="text/javascript">
23564 Roo.data.Field = function(config){
23565 if(typeof config == "string"){
23566 config = {name: config};
23568 Roo.apply(this, config);
23571 this.type = "auto";
23574 var st = Roo.data.SortTypes;
23575 // named sortTypes are supported, here we look them up
23576 if(typeof this.sortType == "string"){
23577 this.sortType = st[this.sortType];
23580 // set default sortType for strings and dates
23581 if(!this.sortType){
23584 this.sortType = st.asUCString;
23587 this.sortType = st.asDate;
23590 this.sortType = st.none;
23595 var stripRe = /[\$,%]/g;
23597 // prebuilt conversion function for this field, instead of
23598 // switching every time we're reading a value
23600 var cv, dateFormat = this.dateFormat;
23605 cv = function(v){ return v; };
23608 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23612 return v !== undefined && v !== null && v !== '' ?
23613 parseInt(String(v).replace(stripRe, ""), 10) : '';
23618 return v !== undefined && v !== null && v !== '' ?
23619 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23624 cv = function(v){ return v === true || v === "true" || v == 1; };
23631 if(v instanceof Date){
23635 if(dateFormat == "timestamp"){
23636 return new Date(v*1000);
23638 return Date.parseDate(v, dateFormat);
23640 var parsed = Date.parse(v);
23641 return parsed ? new Date(parsed) : null;
23650 Roo.data.Field.prototype = {
23658 * Ext JS Library 1.1.1
23659 * Copyright(c) 2006-2007, Ext JS, LLC.
23661 * Originally Released Under LGPL - original licence link has changed is not relivant.
23664 * <script type="text/javascript">
23667 // Base class for reading structured data from a data source. This class is intended to be
23668 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23671 * @class Roo.data.DataReader
23672 * Base class for reading structured data from a data source. This class is intended to be
23673 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23676 Roo.data.DataReader = function(meta, recordType){
23680 this.recordType = recordType instanceof Array ?
23681 Roo.data.Record.create(recordType) : recordType;
23684 Roo.data.DataReader.prototype = {
23686 * Create an empty record
23687 * @param {Object} data (optional) - overlay some values
23688 * @return {Roo.data.Record} record created.
23690 newRow : function(d) {
23692 this.recordType.prototype.fields.each(function(c) {
23694 case 'int' : da[c.name] = 0; break;
23695 case 'date' : da[c.name] = new Date(); break;
23696 case 'float' : da[c.name] = 0.0; break;
23697 case 'boolean' : da[c.name] = false; break;
23698 default : da[c.name] = ""; break;
23702 return new this.recordType(Roo.apply(da, d));
23707 * Ext JS Library 1.1.1
23708 * Copyright(c) 2006-2007, Ext JS, LLC.
23710 * Originally Released Under LGPL - original licence link has changed is not relivant.
23713 * <script type="text/javascript">
23717 * @class Roo.data.DataProxy
23718 * @extends Roo.data.Observable
23719 * This class is an abstract base class for implementations which provide retrieval of
23720 * unformatted data objects.<br>
23722 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23723 * (of the appropriate type which knows how to parse the data object) to provide a block of
23724 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23726 * Custom implementations must implement the load method as described in
23727 * {@link Roo.data.HttpProxy#load}.
23729 Roo.data.DataProxy = function(){
23732 * @event beforeload
23733 * Fires before a network request is made to retrieve a data object.
23734 * @param {Object} This DataProxy object.
23735 * @param {Object} params The params parameter to the load function.
23740 * Fires before the load method's callback is called.
23741 * @param {Object} This DataProxy object.
23742 * @param {Object} o The data object.
23743 * @param {Object} arg The callback argument object passed to the load function.
23747 * @event loadexception
23748 * Fires if an Exception occurs during data retrieval.
23749 * @param {Object} This DataProxy object.
23750 * @param {Object} o The data object.
23751 * @param {Object} arg The callback argument object passed to the load function.
23752 * @param {Object} e The Exception.
23754 loadexception : true
23756 Roo.data.DataProxy.superclass.constructor.call(this);
23759 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23762 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23766 * Ext JS Library 1.1.1
23767 * Copyright(c) 2006-2007, Ext JS, LLC.
23769 * Originally Released Under LGPL - original licence link has changed is not relivant.
23772 * <script type="text/javascript">
23775 * @class Roo.data.MemoryProxy
23776 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23777 * to the Reader when its load method is called.
23779 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23781 Roo.data.MemoryProxy = function(data){
23785 Roo.data.MemoryProxy.superclass.constructor.call(this);
23789 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23792 * Load data from the requested source (in this case an in-memory
23793 * data object passed to the constructor), read the data object into
23794 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23795 * process that block using the passed callback.
23796 * @param {Object} params This parameter is not used by the MemoryProxy class.
23797 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23798 * object into a block of Roo.data.Records.
23799 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23800 * The function must be passed <ul>
23801 * <li>The Record block object</li>
23802 * <li>The "arg" argument from the load function</li>
23803 * <li>A boolean success indicator</li>
23805 * @param {Object} scope The scope in which to call the callback
23806 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23808 load : function(params, reader, callback, scope, arg){
23809 params = params || {};
23812 result = reader.readRecords(this.data);
23814 this.fireEvent("loadexception", this, arg, null, e);
23815 callback.call(scope, null, arg, false);
23818 callback.call(scope, result, arg, true);
23822 update : function(params, records){
23827 * Ext JS Library 1.1.1
23828 * Copyright(c) 2006-2007, Ext JS, LLC.
23830 * Originally Released Under LGPL - original licence link has changed is not relivant.
23833 * <script type="text/javascript">
23836 * @class Roo.data.HttpProxy
23837 * @extends Roo.data.DataProxy
23838 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23839 * configured to reference a certain URL.<br><br>
23841 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23842 * from which the running page was served.<br><br>
23844 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23846 * Be aware that to enable the browser to parse an XML document, the server must set
23847 * the Content-Type header in the HTTP response to "text/xml".
23849 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23850 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23851 * will be used to make the request.
23853 Roo.data.HttpProxy = function(conn){
23854 Roo.data.HttpProxy.superclass.constructor.call(this);
23855 // is conn a conn config or a real conn?
23857 this.useAjax = !conn || !conn.events;
23861 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23862 // thse are take from connection...
23865 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23868 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23869 * extra parameters to each request made by this object. (defaults to undefined)
23872 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23873 * to each request made by this object. (defaults to undefined)
23876 * @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)
23879 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23882 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23888 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23892 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23893 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23894 * a finer-grained basis than the DataProxy events.
23896 getConnection : function(){
23897 return this.useAjax ? Roo.Ajax : this.conn;
23901 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23902 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23903 * process that block using the passed callback.
23904 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23905 * for the request to the remote server.
23906 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23907 * object into a block of Roo.data.Records.
23908 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23909 * The function must be passed <ul>
23910 * <li>The Record block object</li>
23911 * <li>The "arg" argument from the load function</li>
23912 * <li>A boolean success indicator</li>
23914 * @param {Object} scope The scope in which to call the callback
23915 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23917 load : function(params, reader, callback, scope, arg){
23918 if(this.fireEvent("beforeload", this, params) !== false){
23920 params : params || {},
23922 callback : callback,
23927 callback : this.loadResponse,
23931 Roo.applyIf(o, this.conn);
23932 if(this.activeRequest){
23933 Roo.Ajax.abort(this.activeRequest);
23935 this.activeRequest = Roo.Ajax.request(o);
23937 this.conn.request(o);
23940 callback.call(scope||this, null, arg, false);
23945 loadResponse : function(o, success, response){
23946 delete this.activeRequest;
23948 this.fireEvent("loadexception", this, o, response);
23949 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23954 result = o.reader.read(response);
23956 this.fireEvent("loadexception", this, o, response, e);
23957 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23961 this.fireEvent("load", this, o, o.request.arg);
23962 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23966 update : function(dataSet){
23971 updateResponse : function(dataSet){
23976 * Ext JS Library 1.1.1
23977 * Copyright(c) 2006-2007, Ext JS, LLC.
23979 * Originally Released Under LGPL - original licence link has changed is not relivant.
23982 * <script type="text/javascript">
23986 * @class Roo.data.ScriptTagProxy
23987 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23988 * other than the originating domain of the running page.<br><br>
23990 * <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
23991 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23993 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23994 * source code that is used as the source inside a <script> tag.<br><br>
23996 * In order for the browser to process the returned data, the server must wrap the data object
23997 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23998 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23999 * depending on whether the callback name was passed:
24002 boolean scriptTag = false;
24003 String cb = request.getParameter("callback");
24006 response.setContentType("text/javascript");
24008 response.setContentType("application/x-json");
24010 Writer out = response.getWriter();
24012 out.write(cb + "(");
24014 out.print(dataBlock.toJsonString());
24021 * @param {Object} config A configuration object.
24023 Roo.data.ScriptTagProxy = function(config){
24024 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24025 Roo.apply(this, config);
24026 this.head = document.getElementsByTagName("head")[0];
24029 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24031 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24033 * @cfg {String} url The URL from which to request the data object.
24036 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24040 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24041 * the server the name of the callback function set up by the load call to process the returned data object.
24042 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24043 * javascript output which calls this named function passing the data object as its only parameter.
24045 callbackParam : "callback",
24047 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24048 * name to the request.
24053 * Load data from the configured URL, read the data object into
24054 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24055 * process that block using the passed callback.
24056 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24057 * for the request to the remote server.
24058 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24059 * object into a block of Roo.data.Records.
24060 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24061 * The function must be passed <ul>
24062 * <li>The Record block object</li>
24063 * <li>The "arg" argument from the load function</li>
24064 * <li>A boolean success indicator</li>
24066 * @param {Object} scope The scope in which to call the callback
24067 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24069 load : function(params, reader, callback, scope, arg){
24070 if(this.fireEvent("beforeload", this, params) !== false){
24072 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24074 var url = this.url;
24075 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24077 url += "&_dc=" + (new Date().getTime());
24079 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24082 cb : "stcCallback"+transId,
24083 scriptId : "stcScript"+transId,
24087 callback : callback,
24093 window[trans.cb] = function(o){
24094 conn.handleResponse(o, trans);
24097 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24099 if(this.autoAbort !== false){
24103 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24105 var script = document.createElement("script");
24106 script.setAttribute("src", url);
24107 script.setAttribute("type", "text/javascript");
24108 script.setAttribute("id", trans.scriptId);
24109 this.head.appendChild(script);
24111 this.trans = trans;
24113 callback.call(scope||this, null, arg, false);
24118 isLoading : function(){
24119 return this.trans ? true : false;
24123 * Abort the current server request.
24125 abort : function(){
24126 if(this.isLoading()){
24127 this.destroyTrans(this.trans);
24132 destroyTrans : function(trans, isLoaded){
24133 this.head.removeChild(document.getElementById(trans.scriptId));
24134 clearTimeout(trans.timeoutId);
24136 window[trans.cb] = undefined;
24138 delete window[trans.cb];
24141 // if hasn't been loaded, wait for load to remove it to prevent script error
24142 window[trans.cb] = function(){
24143 window[trans.cb] = undefined;
24145 delete window[trans.cb];
24152 handleResponse : function(o, trans){
24153 this.trans = false;
24154 this.destroyTrans(trans, true);
24157 result = trans.reader.readRecords(o);
24159 this.fireEvent("loadexception", this, o, trans.arg, e);
24160 trans.callback.call(trans.scope||window, null, trans.arg, false);
24163 this.fireEvent("load", this, o, trans.arg);
24164 trans.callback.call(trans.scope||window, result, trans.arg, true);
24168 handleFailure : function(trans){
24169 this.trans = false;
24170 this.destroyTrans(trans, false);
24171 this.fireEvent("loadexception", this, null, trans.arg);
24172 trans.callback.call(trans.scope||window, null, trans.arg, false);
24176 * Ext JS Library 1.1.1
24177 * Copyright(c) 2006-2007, Ext JS, LLC.
24179 * Originally Released Under LGPL - original licence link has changed is not relivant.
24182 * <script type="text/javascript">
24186 * @class Roo.data.JsonReader
24187 * @extends Roo.data.DataReader
24188 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24189 * based on mappings in a provided Roo.data.Record constructor.
24191 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24192 * in the reply previously.
24197 var RecordDef = Roo.data.Record.create([
24198 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24199 {name: 'occupation'} // This field will use "occupation" as the mapping.
24201 var myReader = new Roo.data.JsonReader({
24202 totalProperty: "results", // The property which contains the total dataset size (optional)
24203 root: "rows", // The property which contains an Array of row objects
24204 id: "id" // The property within each row object that provides an ID for the record (optional)
24208 * This would consume a JSON file like this:
24210 { 'results': 2, 'rows': [
24211 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24212 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24215 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24216 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24217 * paged from the remote server.
24218 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24219 * @cfg {String} root name of the property which contains the Array of row objects.
24220 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24221 * @cfg {Array} fields Array of field definition objects
24223 * Create a new JsonReader
24224 * @param {Object} meta Metadata configuration options
24225 * @param {Object} recordType Either an Array of field definition objects,
24226 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24228 Roo.data.JsonReader = function(meta, recordType){
24231 // set some defaults:
24232 Roo.applyIf(meta, {
24233 totalProperty: 'total',
24234 successProperty : 'success',
24239 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24241 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24244 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24245 * Used by Store query builder to append _requestMeta to params.
24248 metaFromRemote : false,
24250 * This method is only used by a DataProxy which has retrieved data from a remote server.
24251 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24252 * @return {Object} data A data block which is used by an Roo.data.Store object as
24253 * a cache of Roo.data.Records.
24255 read : function(response){
24256 var json = response.responseText;
24258 var o = /* eval:var:o */ eval("("+json+")");
24260 throw {message: "JsonReader.read: Json object not found"};
24266 this.metaFromRemote = true;
24267 this.meta = o.metaData;
24268 this.recordType = Roo.data.Record.create(o.metaData.fields);
24269 this.onMetaChange(this.meta, this.recordType, o);
24271 return this.readRecords(o);
24274 // private function a store will implement
24275 onMetaChange : function(meta, recordType, o){
24282 simpleAccess: function(obj, subsc) {
24289 getJsonAccessor: function(){
24291 return function(expr) {
24293 return(re.test(expr))
24294 ? new Function("obj", "return obj." + expr)
24299 return Roo.emptyFn;
24304 * Create a data block containing Roo.data.Records from an XML document.
24305 * @param {Object} o An object which contains an Array of row objects in the property specified
24306 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24307 * which contains the total size of the dataset.
24308 * @return {Object} data A data block which is used by an Roo.data.Store object as
24309 * a cache of Roo.data.Records.
24311 readRecords : function(o){
24313 * After any data loads, the raw JSON data is available for further custom processing.
24317 var s = this.meta, Record = this.recordType,
24318 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24320 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24322 if(s.totalProperty) {
24323 this.getTotal = this.getJsonAccessor(s.totalProperty);
24325 if(s.successProperty) {
24326 this.getSuccess = this.getJsonAccessor(s.successProperty);
24328 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24330 var g = this.getJsonAccessor(s.id);
24331 this.getId = function(rec) {
24333 return (r === undefined || r === "") ? null : r;
24336 this.getId = function(){return null;};
24339 for(var jj = 0; jj < fl; jj++){
24341 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24342 this.ef[jj] = this.getJsonAccessor(map);
24346 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24347 if(s.totalProperty){
24348 var vt = parseInt(this.getTotal(o), 10);
24353 if(s.successProperty){
24354 var vs = this.getSuccess(o);
24355 if(vs === false || vs === 'false'){
24360 for(var i = 0; i < c; i++){
24363 var id = this.getId(n);
24364 for(var j = 0; j < fl; j++){
24366 var v = this.ef[j](n);
24368 Roo.log('missing convert for ' + f.name);
24372 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24374 var record = new Record(values, id);
24376 records[i] = record;
24382 totalRecords : totalRecords
24387 * Ext JS Library 1.1.1
24388 * Copyright(c) 2006-2007, Ext JS, LLC.
24390 * Originally Released Under LGPL - original licence link has changed is not relivant.
24393 * <script type="text/javascript">
24397 * @class Roo.data.XmlReader
24398 * @extends Roo.data.DataReader
24399 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24400 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24402 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24403 * header in the HTTP response must be set to "text/xml".</em>
24407 var RecordDef = Roo.data.Record.create([
24408 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24409 {name: 'occupation'} // This field will use "occupation" as the mapping.
24411 var myReader = new Roo.data.XmlReader({
24412 totalRecords: "results", // The element which contains the total dataset size (optional)
24413 record: "row", // The repeated element which contains row information
24414 id: "id" // The element within the row that provides an ID for the record (optional)
24418 * This would consume an XML file like this:
24422 <results>2</results>
24425 <name>Bill</name>
24426 <occupation>Gardener</occupation>
24430 <name>Ben</name>
24431 <occupation>Horticulturalist</occupation>
24435 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24436 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24437 * paged from the remote server.
24438 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24439 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24440 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24441 * a record identifier value.
24443 * Create a new XmlReader
24444 * @param {Object} meta Metadata configuration options
24445 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24446 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24447 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24449 Roo.data.XmlReader = function(meta, recordType){
24451 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24453 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24455 * This method is only used by a DataProxy which has retrieved data from a remote server.
24456 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24457 * to contain a method called 'responseXML' that returns an XML document object.
24458 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24459 * a cache of Roo.data.Records.
24461 read : function(response){
24462 var doc = response.responseXML;
24464 throw {message: "XmlReader.read: XML Document not available"};
24466 return this.readRecords(doc);
24470 * Create a data block containing Roo.data.Records from an XML document.
24471 * @param {Object} doc A parsed XML document.
24472 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24473 * a cache of Roo.data.Records.
24475 readRecords : function(doc){
24477 * After any data loads/reads, the raw XML Document is available for further custom processing.
24478 * @type XMLDocument
24480 this.xmlData = doc;
24481 var root = doc.documentElement || doc;
24482 var q = Roo.DomQuery;
24483 var recordType = this.recordType, fields = recordType.prototype.fields;
24484 var sid = this.meta.id;
24485 var totalRecords = 0, success = true;
24486 if(this.meta.totalRecords){
24487 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24490 if(this.meta.success){
24491 var sv = q.selectValue(this.meta.success, root, true);
24492 success = sv !== false && sv !== 'false';
24495 var ns = q.select(this.meta.record, root);
24496 for(var i = 0, len = ns.length; i < len; i++) {
24499 var id = sid ? q.selectValue(sid, n) : undefined;
24500 for(var j = 0, jlen = fields.length; j < jlen; j++){
24501 var f = fields.items[j];
24502 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24504 values[f.name] = v;
24506 var record = new recordType(values, id);
24508 records[records.length] = record;
24514 totalRecords : totalRecords || records.length
24519 * Ext JS Library 1.1.1
24520 * Copyright(c) 2006-2007, Ext JS, LLC.
24522 * Originally Released Under LGPL - original licence link has changed is not relivant.
24525 * <script type="text/javascript">
24529 * @class Roo.data.ArrayReader
24530 * @extends Roo.data.DataReader
24531 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24532 * Each element of that Array represents a row of data fields. The
24533 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24534 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24538 var RecordDef = Roo.data.Record.create([
24539 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24540 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24542 var myReader = new Roo.data.ArrayReader({
24543 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24547 * This would consume an Array like this:
24549 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24551 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24553 * Create a new JsonReader
24554 * @param {Object} meta Metadata configuration options.
24555 * @param {Object} recordType Either an Array of field definition objects
24556 * as specified to {@link Roo.data.Record#create},
24557 * or an {@link Roo.data.Record} object
24558 * created using {@link Roo.data.Record#create}.
24560 Roo.data.ArrayReader = function(meta, recordType){
24561 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24564 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24566 * Create a data block containing Roo.data.Records from an XML document.
24567 * @param {Object} o An Array of row objects which represents the dataset.
24568 * @return {Object} data A data block which is used by an Roo.data.Store object as
24569 * a cache of Roo.data.Records.
24571 readRecords : function(o){
24572 var sid = this.meta ? this.meta.id : null;
24573 var recordType = this.recordType, fields = recordType.prototype.fields;
24576 for(var i = 0; i < root.length; i++){
24579 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24580 for(var j = 0, jlen = fields.length; j < jlen; j++){
24581 var f = fields.items[j];
24582 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24583 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24585 values[f.name] = v;
24587 var record = new recordType(values, id);
24589 records[records.length] = record;
24593 totalRecords : records.length
24598 * Ext JS Library 1.1.1
24599 * Copyright(c) 2006-2007, Ext JS, LLC.
24601 * Originally Released Under LGPL - original licence link has changed is not relivant.
24604 * <script type="text/javascript">
24609 * @class Roo.data.Tree
24610 * @extends Roo.util.Observable
24611 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24612 * in the tree have most standard DOM functionality.
24614 * @param {Node} root (optional) The root node
24616 Roo.data.Tree = function(root){
24617 this.nodeHash = {};
24619 * The root node for this tree
24624 this.setRootNode(root);
24629 * Fires when a new child node is appended to a node in this tree.
24630 * @param {Tree} tree The owner tree
24631 * @param {Node} parent The parent node
24632 * @param {Node} node The newly appended node
24633 * @param {Number} index The index of the newly appended node
24638 * Fires when a child node is removed from a node in this tree.
24639 * @param {Tree} tree The owner tree
24640 * @param {Node} parent The parent node
24641 * @param {Node} node The child node removed
24646 * Fires when a node is moved to a new location in the tree
24647 * @param {Tree} tree The owner tree
24648 * @param {Node} node The node moved
24649 * @param {Node} oldParent The old parent of this node
24650 * @param {Node} newParent The new parent of this node
24651 * @param {Number} index The index it was moved to
24656 * Fires when a new child node is inserted in a node in this tree.
24657 * @param {Tree} tree The owner tree
24658 * @param {Node} parent The parent node
24659 * @param {Node} node The child node inserted
24660 * @param {Node} refNode The child node the node was inserted before
24664 * @event beforeappend
24665 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24666 * @param {Tree} tree The owner tree
24667 * @param {Node} parent The parent node
24668 * @param {Node} node The child node to be appended
24670 "beforeappend" : true,
24672 * @event beforeremove
24673 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24674 * @param {Tree} tree The owner tree
24675 * @param {Node} parent The parent node
24676 * @param {Node} node The child node to be removed
24678 "beforeremove" : true,
24680 * @event beforemove
24681 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24682 * @param {Tree} tree The owner tree
24683 * @param {Node} node The node being moved
24684 * @param {Node} oldParent The parent of the node
24685 * @param {Node} newParent The new parent the node is moving to
24686 * @param {Number} index The index it is being moved to
24688 "beforemove" : true,
24690 * @event beforeinsert
24691 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24692 * @param {Tree} tree The owner tree
24693 * @param {Node} parent The parent node
24694 * @param {Node} node The child node to be inserted
24695 * @param {Node} refNode The child node the node is being inserted before
24697 "beforeinsert" : true
24700 Roo.data.Tree.superclass.constructor.call(this);
24703 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24704 pathSeparator: "/",
24706 proxyNodeEvent : function(){
24707 return this.fireEvent.apply(this, arguments);
24711 * Returns the root node for this tree.
24714 getRootNode : function(){
24719 * Sets the root node for this tree.
24720 * @param {Node} node
24723 setRootNode : function(node){
24725 node.ownerTree = this;
24726 node.isRoot = true;
24727 this.registerNode(node);
24732 * Gets a node in this tree by its id.
24733 * @param {String} id
24736 getNodeById : function(id){
24737 return this.nodeHash[id];
24740 registerNode : function(node){
24741 this.nodeHash[node.id] = node;
24744 unregisterNode : function(node){
24745 delete this.nodeHash[node.id];
24748 toString : function(){
24749 return "[Tree"+(this.id?" "+this.id:"")+"]";
24754 * @class Roo.data.Node
24755 * @extends Roo.util.Observable
24756 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24757 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24759 * @param {Object} attributes The attributes/config for the node
24761 Roo.data.Node = function(attributes){
24763 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24766 this.attributes = attributes || {};
24767 this.leaf = this.attributes.leaf;
24769 * The node id. @type String
24771 this.id = this.attributes.id;
24773 this.id = Roo.id(null, "ynode-");
24774 this.attributes.id = this.id;
24779 * All child nodes of this node. @type Array
24781 this.childNodes = [];
24782 if(!this.childNodes.indexOf){ // indexOf is a must
24783 this.childNodes.indexOf = function(o){
24784 for(var i = 0, len = this.length; i < len; i++){
24793 * The parent node for this node. @type Node
24795 this.parentNode = null;
24797 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24799 this.firstChild = null;
24801 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24803 this.lastChild = null;
24805 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24807 this.previousSibling = null;
24809 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24811 this.nextSibling = null;
24816 * Fires when a new child node is appended
24817 * @param {Tree} tree The owner tree
24818 * @param {Node} this This node
24819 * @param {Node} node The newly appended node
24820 * @param {Number} index The index of the newly appended node
24825 * Fires when a child node is removed
24826 * @param {Tree} tree The owner tree
24827 * @param {Node} this This node
24828 * @param {Node} node The removed node
24833 * Fires when this node is moved to a new location in the tree
24834 * @param {Tree} tree The owner tree
24835 * @param {Node} this This node
24836 * @param {Node} oldParent The old parent of this node
24837 * @param {Node} newParent The new parent of this node
24838 * @param {Number} index The index it was moved to
24843 * Fires when a new child node is inserted.
24844 * @param {Tree} tree The owner tree
24845 * @param {Node} this This node
24846 * @param {Node} node The child node inserted
24847 * @param {Node} refNode The child node the node was inserted before
24851 * @event beforeappend
24852 * Fires before a new child is appended, return false to cancel the append.
24853 * @param {Tree} tree The owner tree
24854 * @param {Node} this This node
24855 * @param {Node} node The child node to be appended
24857 "beforeappend" : true,
24859 * @event beforeremove
24860 * Fires before a child is removed, return false to cancel the remove.
24861 * @param {Tree} tree The owner tree
24862 * @param {Node} this This node
24863 * @param {Node} node The child node to be removed
24865 "beforeremove" : true,
24867 * @event beforemove
24868 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24869 * @param {Tree} tree The owner tree
24870 * @param {Node} this This node
24871 * @param {Node} oldParent The parent of this node
24872 * @param {Node} newParent The new parent this node is moving to
24873 * @param {Number} index The index it is being moved to
24875 "beforemove" : true,
24877 * @event beforeinsert
24878 * Fires before a new child is inserted, return false to cancel the insert.
24879 * @param {Tree} tree The owner tree
24880 * @param {Node} this This node
24881 * @param {Node} node The child node to be inserted
24882 * @param {Node} refNode The child node the node is being inserted before
24884 "beforeinsert" : true
24886 this.listeners = this.attributes.listeners;
24887 Roo.data.Node.superclass.constructor.call(this);
24890 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24891 fireEvent : function(evtName){
24892 // first do standard event for this node
24893 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24896 // then bubble it up to the tree if the event wasn't cancelled
24897 var ot = this.getOwnerTree();
24899 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24907 * Returns true if this node is a leaf
24908 * @return {Boolean}
24910 isLeaf : function(){
24911 return this.leaf === true;
24915 setFirstChild : function(node){
24916 this.firstChild = node;
24920 setLastChild : function(node){
24921 this.lastChild = node;
24926 * Returns true if this node is the last child of its parent
24927 * @return {Boolean}
24929 isLast : function(){
24930 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24934 * Returns true if this node is the first child of its parent
24935 * @return {Boolean}
24937 isFirst : function(){
24938 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24941 hasChildNodes : function(){
24942 return !this.isLeaf() && this.childNodes.length > 0;
24946 * Insert node(s) as the last child node of this node.
24947 * @param {Node/Array} node The node or Array of nodes to append
24948 * @return {Node} The appended node if single append, or null if an array was passed
24950 appendChild : function(node){
24952 if(node instanceof Array){
24954 }else if(arguments.length > 1){
24957 // if passed an array or multiple args do them one by one
24959 for(var i = 0, len = multi.length; i < len; i++) {
24960 this.appendChild(multi[i]);
24963 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24966 var index = this.childNodes.length;
24967 var oldParent = node.parentNode;
24968 // it's a move, make sure we move it cleanly
24970 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24973 oldParent.removeChild(node);
24975 index = this.childNodes.length;
24977 this.setFirstChild(node);
24979 this.childNodes.push(node);
24980 node.parentNode = this;
24981 var ps = this.childNodes[index-1];
24983 node.previousSibling = ps;
24984 ps.nextSibling = node;
24986 node.previousSibling = null;
24988 node.nextSibling = null;
24989 this.setLastChild(node);
24990 node.setOwnerTree(this.getOwnerTree());
24991 this.fireEvent("append", this.ownerTree, this, node, index);
24993 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25000 * Removes a child node from this node.
25001 * @param {Node} node The node to remove
25002 * @return {Node} The removed node
25004 removeChild : function(node){
25005 var index = this.childNodes.indexOf(node);
25009 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25013 // remove it from childNodes collection
25014 this.childNodes.splice(index, 1);
25017 if(node.previousSibling){
25018 node.previousSibling.nextSibling = node.nextSibling;
25020 if(node.nextSibling){
25021 node.nextSibling.previousSibling = node.previousSibling;
25024 // update child refs
25025 if(this.firstChild == node){
25026 this.setFirstChild(node.nextSibling);
25028 if(this.lastChild == node){
25029 this.setLastChild(node.previousSibling);
25032 node.setOwnerTree(null);
25033 // clear any references from the node
25034 node.parentNode = null;
25035 node.previousSibling = null;
25036 node.nextSibling = null;
25037 this.fireEvent("remove", this.ownerTree, this, node);
25042 * Inserts the first node before the second node in this nodes childNodes collection.
25043 * @param {Node} node The node to insert
25044 * @param {Node} refNode The node to insert before (if null the node is appended)
25045 * @return {Node} The inserted node
25047 insertBefore : function(node, refNode){
25048 if(!refNode){ // like standard Dom, refNode can be null for append
25049 return this.appendChild(node);
25052 if(node == refNode){
25056 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25059 var index = this.childNodes.indexOf(refNode);
25060 var oldParent = node.parentNode;
25061 var refIndex = index;
25063 // when moving internally, indexes will change after remove
25064 if(oldParent == this && this.childNodes.indexOf(node) < index){
25068 // it's a move, make sure we move it cleanly
25070 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25073 oldParent.removeChild(node);
25076 this.setFirstChild(node);
25078 this.childNodes.splice(refIndex, 0, node);
25079 node.parentNode = this;
25080 var ps = this.childNodes[refIndex-1];
25082 node.previousSibling = ps;
25083 ps.nextSibling = node;
25085 node.previousSibling = null;
25087 node.nextSibling = refNode;
25088 refNode.previousSibling = node;
25089 node.setOwnerTree(this.getOwnerTree());
25090 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25092 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25098 * Returns the child node at the specified index.
25099 * @param {Number} index
25102 item : function(index){
25103 return this.childNodes[index];
25107 * Replaces one child node in this node with another.
25108 * @param {Node} newChild The replacement node
25109 * @param {Node} oldChild The node to replace
25110 * @return {Node} The replaced node
25112 replaceChild : function(newChild, oldChild){
25113 this.insertBefore(newChild, oldChild);
25114 this.removeChild(oldChild);
25119 * Returns the index of a child node
25120 * @param {Node} node
25121 * @return {Number} The index of the node or -1 if it was not found
25123 indexOf : function(child){
25124 return this.childNodes.indexOf(child);
25128 * Returns the tree this node is in.
25131 getOwnerTree : function(){
25132 // if it doesn't have one, look for one
25133 if(!this.ownerTree){
25137 this.ownerTree = p.ownerTree;
25143 return this.ownerTree;
25147 * Returns depth of this node (the root node has a depth of 0)
25150 getDepth : function(){
25153 while(p.parentNode){
25161 setOwnerTree : function(tree){
25162 // if it's move, we need to update everyone
25163 if(tree != this.ownerTree){
25164 if(this.ownerTree){
25165 this.ownerTree.unregisterNode(this);
25167 this.ownerTree = tree;
25168 var cs = this.childNodes;
25169 for(var i = 0, len = cs.length; i < len; i++) {
25170 cs[i].setOwnerTree(tree);
25173 tree.registerNode(this);
25179 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25180 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25181 * @return {String} The path
25183 getPath : function(attr){
25184 attr = attr || "id";
25185 var p = this.parentNode;
25186 var b = [this.attributes[attr]];
25188 b.unshift(p.attributes[attr]);
25191 var sep = this.getOwnerTree().pathSeparator;
25192 return sep + b.join(sep);
25196 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25197 * function call will be the scope provided or the current node. The arguments to the function
25198 * will be the args provided or the current node. If the function returns false at any point,
25199 * the bubble is stopped.
25200 * @param {Function} fn The function to call
25201 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25202 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25204 bubble : function(fn, scope, args){
25207 if(fn.call(scope || p, args || p) === false){
25215 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25216 * function call will be the scope provided or the current node. The arguments to the function
25217 * will be the args provided or the current node. If the function returns false at any point,
25218 * the cascade is stopped on that branch.
25219 * @param {Function} fn The function to call
25220 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25221 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25223 cascade : function(fn, scope, args){
25224 if(fn.call(scope || this, args || this) !== false){
25225 var cs = this.childNodes;
25226 for(var i = 0, len = cs.length; i < len; i++) {
25227 cs[i].cascade(fn, scope, args);
25233 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25234 * function call will be the scope provided or the current node. The arguments to the function
25235 * will be the args provided or the current node. If the function returns false at any point,
25236 * the iteration stops.
25237 * @param {Function} fn The function to call
25238 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25239 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25241 eachChild : function(fn, scope, args){
25242 var cs = this.childNodes;
25243 for(var i = 0, len = cs.length; i < len; i++) {
25244 if(fn.call(scope || this, args || cs[i]) === false){
25251 * Finds the first child that has the attribute with the specified value.
25252 * @param {String} attribute The attribute name
25253 * @param {Mixed} value The value to search for
25254 * @return {Node} The found child or null if none was found
25256 findChild : function(attribute, value){
25257 var cs = this.childNodes;
25258 for(var i = 0, len = cs.length; i < len; i++) {
25259 if(cs[i].attributes[attribute] == value){
25267 * Finds the first child by a custom function. The child matches if the function passed
25269 * @param {Function} fn
25270 * @param {Object} scope (optional)
25271 * @return {Node} The found child or null if none was found
25273 findChildBy : function(fn, scope){
25274 var cs = this.childNodes;
25275 for(var i = 0, len = cs.length; i < len; i++) {
25276 if(fn.call(scope||cs[i], cs[i]) === true){
25284 * Sorts this nodes children using the supplied sort function
25285 * @param {Function} fn
25286 * @param {Object} scope (optional)
25288 sort : function(fn, scope){
25289 var cs = this.childNodes;
25290 var len = cs.length;
25292 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25294 for(var i = 0; i < len; i++){
25296 n.previousSibling = cs[i-1];
25297 n.nextSibling = cs[i+1];
25299 this.setFirstChild(n);
25302 this.setLastChild(n);
25309 * Returns true if this node is an ancestor (at any point) of the passed node.
25310 * @param {Node} node
25311 * @return {Boolean}
25313 contains : function(node){
25314 return node.isAncestor(this);
25318 * Returns true if the passed node is an ancestor (at any point) of this node.
25319 * @param {Node} node
25320 * @return {Boolean}
25322 isAncestor : function(node){
25323 var p = this.parentNode;
25333 toString : function(){
25334 return "[Node"+(this.id?" "+this.id:"")+"]";
25338 * Ext JS Library 1.1.1
25339 * Copyright(c) 2006-2007, Ext JS, LLC.
25341 * Originally Released Under LGPL - original licence link has changed is not relivant.
25344 * <script type="text/javascript">
25349 * @extends Roo.Element
25350 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25351 * automatic maintaining of shadow/shim positions.
25352 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25353 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25354 * you can pass a string with a CSS class name. False turns off the shadow.
25355 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25356 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25357 * @cfg {String} cls CSS class to add to the element
25358 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25359 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25361 * @param {Object} config An object with config options.
25362 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25365 Roo.Layer = function(config, existingEl){
25366 config = config || {};
25367 var dh = Roo.DomHelper;
25368 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25370 this.dom = Roo.getDom(existingEl);
25373 var o = config.dh || {tag: "div", cls: "x-layer"};
25374 this.dom = dh.append(pel, o);
25377 this.addClass(config.cls);
25379 this.constrain = config.constrain !== false;
25380 this.visibilityMode = Roo.Element.VISIBILITY;
25382 this.id = this.dom.id = config.id;
25384 this.id = Roo.id(this.dom);
25386 this.zindex = config.zindex || this.getZIndex();
25387 this.position("absolute", this.zindex);
25389 this.shadowOffset = config.shadowOffset || 4;
25390 this.shadow = new Roo.Shadow({
25391 offset : this.shadowOffset,
25392 mode : config.shadow
25395 this.shadowOffset = 0;
25397 this.useShim = config.shim !== false && Roo.useShims;
25398 this.useDisplay = config.useDisplay;
25402 var supr = Roo.Element.prototype;
25404 // shims are shared among layer to keep from having 100 iframes
25407 Roo.extend(Roo.Layer, Roo.Element, {
25409 getZIndex : function(){
25410 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25413 getShim : function(){
25420 var shim = shims.shift();
25422 shim = this.createShim();
25423 shim.enableDisplayMode('block');
25424 shim.dom.style.display = 'none';
25425 shim.dom.style.visibility = 'visible';
25427 var pn = this.dom.parentNode;
25428 if(shim.dom.parentNode != pn){
25429 pn.insertBefore(shim.dom, this.dom);
25431 shim.setStyle('z-index', this.getZIndex()-2);
25436 hideShim : function(){
25438 this.shim.setDisplayed(false);
25439 shims.push(this.shim);
25444 disableShadow : function(){
25446 this.shadowDisabled = true;
25447 this.shadow.hide();
25448 this.lastShadowOffset = this.shadowOffset;
25449 this.shadowOffset = 0;
25453 enableShadow : function(show){
25455 this.shadowDisabled = false;
25456 this.shadowOffset = this.lastShadowOffset;
25457 delete this.lastShadowOffset;
25465 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25466 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25467 sync : function(doShow){
25468 var sw = this.shadow;
25469 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25470 var sh = this.getShim();
25472 var w = this.getWidth(),
25473 h = this.getHeight();
25475 var l = this.getLeft(true),
25476 t = this.getTop(true);
25478 if(sw && !this.shadowDisabled){
25479 if(doShow && !sw.isVisible()){
25482 sw.realign(l, t, w, h);
25488 // fit the shim behind the shadow, so it is shimmed too
25489 var a = sw.adjusts, s = sh.dom.style;
25490 s.left = (Math.min(l, l+a.l))+"px";
25491 s.top = (Math.min(t, t+a.t))+"px";
25492 s.width = (w+a.w)+"px";
25493 s.height = (h+a.h)+"px";
25500 sh.setLeftTop(l, t);
25507 destroy : function(){
25510 this.shadow.hide();
25512 this.removeAllListeners();
25513 var pn = this.dom.parentNode;
25515 pn.removeChild(this.dom);
25517 Roo.Element.uncache(this.id);
25520 remove : function(){
25525 beginUpdate : function(){
25526 this.updating = true;
25530 endUpdate : function(){
25531 this.updating = false;
25536 hideUnders : function(negOffset){
25538 this.shadow.hide();
25544 constrainXY : function(){
25545 if(this.constrain){
25546 var vw = Roo.lib.Dom.getViewWidth(),
25547 vh = Roo.lib.Dom.getViewHeight();
25548 var s = Roo.get(document).getScroll();
25550 var xy = this.getXY();
25551 var x = xy[0], y = xy[1];
25552 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25553 // only move it if it needs it
25555 // first validate right/bottom
25556 if((x + w) > vw+s.left){
25557 x = vw - w - this.shadowOffset;
25560 if((y + h) > vh+s.top){
25561 y = vh - h - this.shadowOffset;
25564 // then make sure top/left isn't negative
25575 var ay = this.avoidY;
25576 if(y <= ay && (y+h) >= ay){
25582 supr.setXY.call(this, xy);
25588 isVisible : function(){
25589 return this.visible;
25593 showAction : function(){
25594 this.visible = true; // track visibility to prevent getStyle calls
25595 if(this.useDisplay === true){
25596 this.setDisplayed("");
25597 }else if(this.lastXY){
25598 supr.setXY.call(this, this.lastXY);
25599 }else if(this.lastLT){
25600 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25605 hideAction : function(){
25606 this.visible = false;
25607 if(this.useDisplay === true){
25608 this.setDisplayed(false);
25610 this.setLeftTop(-10000,-10000);
25614 // overridden Element method
25615 setVisible : function(v, a, d, c, e){
25620 var cb = function(){
25625 }.createDelegate(this);
25626 supr.setVisible.call(this, true, true, d, cb, e);
25629 this.hideUnders(true);
25638 }.createDelegate(this);
25640 supr.setVisible.call(this, v, a, d, cb, e);
25649 storeXY : function(xy){
25650 delete this.lastLT;
25654 storeLeftTop : function(left, top){
25655 delete this.lastXY;
25656 this.lastLT = [left, top];
25660 beforeFx : function(){
25661 this.beforeAction();
25662 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25666 afterFx : function(){
25667 Roo.Layer.superclass.afterFx.apply(this, arguments);
25668 this.sync(this.isVisible());
25672 beforeAction : function(){
25673 if(!this.updating && this.shadow){
25674 this.shadow.hide();
25678 // overridden Element method
25679 setLeft : function(left){
25680 this.storeLeftTop(left, this.getTop(true));
25681 supr.setLeft.apply(this, arguments);
25685 setTop : function(top){
25686 this.storeLeftTop(this.getLeft(true), top);
25687 supr.setTop.apply(this, arguments);
25691 setLeftTop : function(left, top){
25692 this.storeLeftTop(left, top);
25693 supr.setLeftTop.apply(this, arguments);
25697 setXY : function(xy, a, d, c, e){
25699 this.beforeAction();
25701 var cb = this.createCB(c);
25702 supr.setXY.call(this, xy, a, d, cb, e);
25709 createCB : function(c){
25720 // overridden Element method
25721 setX : function(x, a, d, c, e){
25722 this.setXY([x, this.getY()], a, d, c, e);
25725 // overridden Element method
25726 setY : function(y, a, d, c, e){
25727 this.setXY([this.getX(), y], a, d, c, e);
25730 // overridden Element method
25731 setSize : function(w, h, a, d, c, e){
25732 this.beforeAction();
25733 var cb = this.createCB(c);
25734 supr.setSize.call(this, w, h, a, d, cb, e);
25740 // overridden Element method
25741 setWidth : function(w, a, d, c, e){
25742 this.beforeAction();
25743 var cb = this.createCB(c);
25744 supr.setWidth.call(this, w, a, d, cb, e);
25750 // overridden Element method
25751 setHeight : function(h, a, d, c, e){
25752 this.beforeAction();
25753 var cb = this.createCB(c);
25754 supr.setHeight.call(this, h, a, d, cb, e);
25760 // overridden Element method
25761 setBounds : function(x, y, w, h, a, d, c, e){
25762 this.beforeAction();
25763 var cb = this.createCB(c);
25765 this.storeXY([x, y]);
25766 supr.setXY.call(this, [x, y]);
25767 supr.setSize.call(this, w, h, a, d, cb, e);
25770 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25776 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25777 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25778 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25779 * @param {Number} zindex The new z-index to set
25780 * @return {this} The Layer
25782 setZIndex : function(zindex){
25783 this.zindex = zindex;
25784 this.setStyle("z-index", zindex + 2);
25786 this.shadow.setZIndex(zindex + 1);
25789 this.shim.setStyle("z-index", zindex);
25795 * Ext JS Library 1.1.1
25796 * Copyright(c) 2006-2007, Ext JS, LLC.
25798 * Originally Released Under LGPL - original licence link has changed is not relivant.
25801 * <script type="text/javascript">
25806 * @class Roo.Shadow
25807 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25808 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25809 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25811 * Create a new Shadow
25812 * @param {Object} config The config object
25814 Roo.Shadow = function(config){
25815 Roo.apply(this, config);
25816 if(typeof this.mode != "string"){
25817 this.mode = this.defaultMode;
25819 var o = this.offset, a = {h: 0};
25820 var rad = Math.floor(this.offset/2);
25821 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25827 a.l -= this.offset + rad;
25828 a.t -= this.offset + rad;
25839 a.l -= (this.offset - rad);
25840 a.t -= this.offset + rad;
25842 a.w -= (this.offset - rad)*2;
25853 a.l -= (this.offset - rad);
25854 a.t -= (this.offset - rad);
25856 a.w -= (this.offset + rad + 1);
25857 a.h -= (this.offset + rad);
25866 Roo.Shadow.prototype = {
25868 * @cfg {String} mode
25869 * The shadow display mode. Supports the following options:<br />
25870 * sides: Shadow displays on both sides and bottom only<br />
25871 * frame: Shadow displays equally on all four sides<br />
25872 * drop: Traditional bottom-right drop shadow (default)
25875 * @cfg {String} offset
25876 * The number of pixels to offset the shadow from the element (defaults to 4)
25881 defaultMode: "drop",
25884 * Displays the shadow under the target element
25885 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25887 show : function(target){
25888 target = Roo.get(target);
25890 this.el = Roo.Shadow.Pool.pull();
25891 if(this.el.dom.nextSibling != target.dom){
25892 this.el.insertBefore(target);
25895 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25897 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25900 target.getLeft(true),
25901 target.getTop(true),
25905 this.el.dom.style.display = "block";
25909 * Returns true if the shadow is visible, else false
25911 isVisible : function(){
25912 return this.el ? true : false;
25916 * Direct alignment when values are already available. Show must be called at least once before
25917 * calling this method to ensure it is initialized.
25918 * @param {Number} left The target element left position
25919 * @param {Number} top The target element top position
25920 * @param {Number} width The target element width
25921 * @param {Number} height The target element height
25923 realign : function(l, t, w, h){
25927 var a = this.adjusts, d = this.el.dom, s = d.style;
25929 s.left = (l+a.l)+"px";
25930 s.top = (t+a.t)+"px";
25931 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25933 if(s.width != sws || s.height != shs){
25937 var cn = d.childNodes;
25938 var sww = Math.max(0, (sw-12))+"px";
25939 cn[0].childNodes[1].style.width = sww;
25940 cn[1].childNodes[1].style.width = sww;
25941 cn[2].childNodes[1].style.width = sww;
25942 cn[1].style.height = Math.max(0, (sh-12))+"px";
25948 * Hides this shadow
25952 this.el.dom.style.display = "none";
25953 Roo.Shadow.Pool.push(this.el);
25959 * Adjust the z-index of this shadow
25960 * @param {Number} zindex The new z-index
25962 setZIndex : function(z){
25965 this.el.setStyle("z-index", z);
25970 // Private utility class that manages the internal Shadow cache
25971 Roo.Shadow.Pool = function(){
25973 var markup = Roo.isIE ?
25974 '<div class="x-ie-shadow"></div>' :
25975 '<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>';
25978 var sh = p.shift();
25980 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25981 sh.autoBoxAdjust = false;
25986 push : function(sh){
25992 * Ext JS Library 1.1.1
25993 * Copyright(c) 2006-2007, Ext JS, LLC.
25995 * Originally Released Under LGPL - original licence link has changed is not relivant.
25998 * <script type="text/javascript">
26003 * @class Roo.SplitBar
26004 * @extends Roo.util.Observable
26005 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26009 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26010 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26011 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26012 split.minSize = 100;
26013 split.maxSize = 600;
26014 split.animate = true;
26015 split.on('moved', splitterMoved);
26018 * Create a new SplitBar
26019 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26020 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26021 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26022 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26023 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26024 position of the SplitBar).
26026 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26029 this.el = Roo.get(dragElement, true);
26030 this.el.dom.unselectable = "on";
26032 this.resizingEl = Roo.get(resizingElement, true);
26036 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26037 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26040 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26043 * The minimum size of the resizing element. (Defaults to 0)
26049 * The maximum size of the resizing element. (Defaults to 2000)
26052 this.maxSize = 2000;
26055 * Whether to animate the transition to the new size
26058 this.animate = false;
26061 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26064 this.useShim = false;
26069 if(!existingProxy){
26071 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26073 this.proxy = Roo.get(existingProxy).dom;
26076 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26079 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26082 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26085 this.dragSpecs = {};
26088 * @private The adapter to use to positon and resize elements
26090 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26091 this.adapter.init(this);
26093 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26095 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26096 this.el.addClass("x-splitbar-h");
26099 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26100 this.el.addClass("x-splitbar-v");
26106 * Fires when the splitter is moved (alias for {@link #event-moved})
26107 * @param {Roo.SplitBar} this
26108 * @param {Number} newSize the new width or height
26113 * Fires when the splitter is moved
26114 * @param {Roo.SplitBar} this
26115 * @param {Number} newSize the new width or height
26119 * @event beforeresize
26120 * Fires before the splitter is dragged
26121 * @param {Roo.SplitBar} this
26123 "beforeresize" : true,
26125 "beforeapply" : true
26128 Roo.util.Observable.call(this);
26131 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26132 onStartProxyDrag : function(x, y){
26133 this.fireEvent("beforeresize", this);
26135 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26137 o.enableDisplayMode("block");
26138 // all splitbars share the same overlay
26139 Roo.SplitBar.prototype.overlay = o;
26141 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26142 this.overlay.show();
26143 Roo.get(this.proxy).setDisplayed("block");
26144 var size = this.adapter.getElementSize(this);
26145 this.activeMinSize = this.getMinimumSize();;
26146 this.activeMaxSize = this.getMaximumSize();;
26147 var c1 = size - this.activeMinSize;
26148 var c2 = Math.max(this.activeMaxSize - size, 0);
26149 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26150 this.dd.resetConstraints();
26151 this.dd.setXConstraint(
26152 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26153 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26155 this.dd.setYConstraint(0, 0);
26157 this.dd.resetConstraints();
26158 this.dd.setXConstraint(0, 0);
26159 this.dd.setYConstraint(
26160 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26161 this.placement == Roo.SplitBar.TOP ? c2 : c1
26164 this.dragSpecs.startSize = size;
26165 this.dragSpecs.startPoint = [x, y];
26166 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26170 * @private Called after the drag operation by the DDProxy
26172 onEndProxyDrag : function(e){
26173 Roo.get(this.proxy).setDisplayed(false);
26174 var endPoint = Roo.lib.Event.getXY(e);
26176 this.overlay.hide();
26179 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26180 newSize = this.dragSpecs.startSize +
26181 (this.placement == Roo.SplitBar.LEFT ?
26182 endPoint[0] - this.dragSpecs.startPoint[0] :
26183 this.dragSpecs.startPoint[0] - endPoint[0]
26186 newSize = this.dragSpecs.startSize +
26187 (this.placement == Roo.SplitBar.TOP ?
26188 endPoint[1] - this.dragSpecs.startPoint[1] :
26189 this.dragSpecs.startPoint[1] - endPoint[1]
26192 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26193 if(newSize != this.dragSpecs.startSize){
26194 if(this.fireEvent('beforeapply', this, newSize) !== false){
26195 this.adapter.setElementSize(this, newSize);
26196 this.fireEvent("moved", this, newSize);
26197 this.fireEvent("resize", this, newSize);
26203 * Get the adapter this SplitBar uses
26204 * @return The adapter object
26206 getAdapter : function(){
26207 return this.adapter;
26211 * Set the adapter this SplitBar uses
26212 * @param {Object} adapter A SplitBar adapter object
26214 setAdapter : function(adapter){
26215 this.adapter = adapter;
26216 this.adapter.init(this);
26220 * Gets the minimum size for the resizing element
26221 * @return {Number} The minimum size
26223 getMinimumSize : function(){
26224 return this.minSize;
26228 * Sets the minimum size for the resizing element
26229 * @param {Number} minSize The minimum size
26231 setMinimumSize : function(minSize){
26232 this.minSize = minSize;
26236 * Gets the maximum size for the resizing element
26237 * @return {Number} The maximum size
26239 getMaximumSize : function(){
26240 return this.maxSize;
26244 * Sets the maximum size for the resizing element
26245 * @param {Number} maxSize The maximum size
26247 setMaximumSize : function(maxSize){
26248 this.maxSize = maxSize;
26252 * Sets the initialize size for the resizing element
26253 * @param {Number} size The initial size
26255 setCurrentSize : function(size){
26256 var oldAnimate = this.animate;
26257 this.animate = false;
26258 this.adapter.setElementSize(this, size);
26259 this.animate = oldAnimate;
26263 * Destroy this splitbar.
26264 * @param {Boolean} removeEl True to remove the element
26266 destroy : function(removeEl){
26268 this.shim.remove();
26271 this.proxy.parentNode.removeChild(this.proxy);
26279 * @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.
26281 Roo.SplitBar.createProxy = function(dir){
26282 var proxy = new Roo.Element(document.createElement("div"));
26283 proxy.unselectable();
26284 var cls = 'x-splitbar-proxy';
26285 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26286 document.body.appendChild(proxy.dom);
26291 * @class Roo.SplitBar.BasicLayoutAdapter
26292 * Default Adapter. It assumes the splitter and resizing element are not positioned
26293 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26295 Roo.SplitBar.BasicLayoutAdapter = function(){
26298 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26299 // do nothing for now
26300 init : function(s){
26304 * Called before drag operations to get the current size of the resizing element.
26305 * @param {Roo.SplitBar} s The SplitBar using this adapter
26307 getElementSize : function(s){
26308 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26309 return s.resizingEl.getWidth();
26311 return s.resizingEl.getHeight();
26316 * Called after drag operations to set the size of the resizing element.
26317 * @param {Roo.SplitBar} s The SplitBar using this adapter
26318 * @param {Number} newSize The new size to set
26319 * @param {Function} onComplete A function to be invoked when resizing is complete
26321 setElementSize : function(s, newSize, onComplete){
26322 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26324 s.resizingEl.setWidth(newSize);
26326 onComplete(s, newSize);
26329 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26334 s.resizingEl.setHeight(newSize);
26336 onComplete(s, newSize);
26339 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26346 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26347 * @extends Roo.SplitBar.BasicLayoutAdapter
26348 * Adapter that moves the splitter element to align with the resized sizing element.
26349 * Used with an absolute positioned SplitBar.
26350 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26351 * document.body, make sure you assign an id to the body element.
26353 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26354 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26355 this.container = Roo.get(container);
26358 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26359 init : function(s){
26360 this.basic.init(s);
26363 getElementSize : function(s){
26364 return this.basic.getElementSize(s);
26367 setElementSize : function(s, newSize, onComplete){
26368 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26371 moveSplitter : function(s){
26372 var yes = Roo.SplitBar;
26373 switch(s.placement){
26375 s.el.setX(s.resizingEl.getRight());
26378 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26381 s.el.setY(s.resizingEl.getBottom());
26384 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26391 * Orientation constant - Create a vertical SplitBar
26395 Roo.SplitBar.VERTICAL = 1;
26398 * Orientation constant - Create a horizontal SplitBar
26402 Roo.SplitBar.HORIZONTAL = 2;
26405 * Placement constant - The resizing element is to the left of the splitter element
26409 Roo.SplitBar.LEFT = 1;
26412 * Placement constant - The resizing element is to the right of the splitter element
26416 Roo.SplitBar.RIGHT = 2;
26419 * Placement constant - The resizing element is positioned above the splitter element
26423 Roo.SplitBar.TOP = 3;
26426 * Placement constant - The resizing element is positioned under splitter element
26430 Roo.SplitBar.BOTTOM = 4;
26433 * Ext JS Library 1.1.1
26434 * Copyright(c) 2006-2007, Ext JS, LLC.
26436 * Originally Released Under LGPL - original licence link has changed is not relivant.
26439 * <script type="text/javascript">
26444 * @extends Roo.util.Observable
26445 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26446 * This class also supports single and multi selection modes. <br>
26447 * Create a data model bound view:
26449 var store = new Roo.data.Store(...);
26451 var view = new Roo.View({
26453 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26455 singleSelect: true,
26456 selectedClass: "ydataview-selected",
26460 // listen for node click?
26461 view.on("click", function(vw, index, node, e){
26462 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26466 dataModel.load("foobar.xml");
26468 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26470 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26471 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26473 * Note: old style constructor is still suported (container, template, config)
26476 * Create a new View
26477 * @param {Object} config The config object
26480 Roo.View = function(config, depreciated_tpl, depreciated_config){
26482 this.parent = false;
26484 if (typeof(depreciated_tpl) == 'undefined') {
26485 // new way.. - universal constructor.
26486 Roo.apply(this, config);
26487 this.el = Roo.get(this.el);
26490 this.el = Roo.get(config);
26491 this.tpl = depreciated_tpl;
26492 Roo.apply(this, depreciated_config);
26494 this.wrapEl = this.el.wrap().wrap();
26495 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26498 if(typeof(this.tpl) == "string"){
26499 this.tpl = new Roo.Template(this.tpl);
26501 // support xtype ctors..
26502 this.tpl = new Roo.factory(this.tpl, Roo);
26506 this.tpl.compile();
26511 * @event beforeclick
26512 * Fires before a click is processed. Returns false to cancel the default action.
26513 * @param {Roo.View} this
26514 * @param {Number} index The index of the target node
26515 * @param {HTMLElement} node The target node
26516 * @param {Roo.EventObject} e The raw event object
26518 "beforeclick" : true,
26521 * Fires when a template node is clicked.
26522 * @param {Roo.View} this
26523 * @param {Number} index The index of the target node
26524 * @param {HTMLElement} node The target node
26525 * @param {Roo.EventObject} e The raw event object
26530 * Fires when a template node is double clicked.
26531 * @param {Roo.View} this
26532 * @param {Number} index The index of the target node
26533 * @param {HTMLElement} node The target node
26534 * @param {Roo.EventObject} e The raw event object
26538 * @event contextmenu
26539 * Fires when a template node is right clicked.
26540 * @param {Roo.View} this
26541 * @param {Number} index The index of the target node
26542 * @param {HTMLElement} node The target node
26543 * @param {Roo.EventObject} e The raw event object
26545 "contextmenu" : true,
26547 * @event selectionchange
26548 * Fires when the selected nodes change.
26549 * @param {Roo.View} this
26550 * @param {Array} selections Array of the selected nodes
26552 "selectionchange" : true,
26555 * @event beforeselect
26556 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26557 * @param {Roo.View} this
26558 * @param {HTMLElement} node The node to be selected
26559 * @param {Array} selections Array of currently selected nodes
26561 "beforeselect" : true,
26563 * @event preparedata
26564 * Fires on every row to render, to allow you to change the data.
26565 * @param {Roo.View} this
26566 * @param {Object} data to be rendered (change this)
26568 "preparedata" : true
26576 "click": this.onClick,
26577 "dblclick": this.onDblClick,
26578 "contextmenu": this.onContextMenu,
26582 this.selections = [];
26584 this.cmp = new Roo.CompositeElementLite([]);
26586 this.store = Roo.factory(this.store, Roo.data);
26587 this.setStore(this.store, true);
26590 if ( this.footer && this.footer.xtype) {
26592 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26594 this.footer.dataSource = this.store;
26595 this.footer.container = fctr;
26596 this.footer = Roo.factory(this.footer, Roo);
26597 fctr.insertFirst(this.el);
26599 // this is a bit insane - as the paging toolbar seems to detach the el..
26600 // dom.parentNode.parentNode.parentNode
26601 // they get detached?
26605 Roo.View.superclass.constructor.call(this);
26610 Roo.extend(Roo.View, Roo.util.Observable, {
26613 * @cfg {Roo.data.Store} store Data store to load data from.
26618 * @cfg {String|Roo.Element} el The container element.
26623 * @cfg {String|Roo.Template} tpl The template used by this View
26627 * @cfg {String} dataName the named area of the template to use as the data area
26628 * Works with domtemplates roo-name="name"
26632 * @cfg {String} selectedClass The css class to add to selected nodes
26634 selectedClass : "x-view-selected",
26636 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26641 * @cfg {String} text to display on mask (default Loading)
26645 * @cfg {Boolean} multiSelect Allow multiple selection
26647 multiSelect : false,
26649 * @cfg {Boolean} singleSelect Allow single selection
26651 singleSelect: false,
26654 * @cfg {Boolean} toggleSelect - selecting
26656 toggleSelect : false,
26659 * @cfg {Boolean} tickable - selecting
26664 * Returns the element this view is bound to.
26665 * @return {Roo.Element}
26667 getEl : function(){
26668 return this.wrapEl;
26674 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26676 refresh : function(){
26677 //Roo.log('refresh');
26680 // if we are using something like 'domtemplate', then
26681 // the what gets used is:
26682 // t.applySubtemplate(NAME, data, wrapping data..)
26683 // the outer template then get' applied with
26684 // the store 'extra data'
26685 // and the body get's added to the
26686 // roo-name="data" node?
26687 // <span class='roo-tpl-{name}'></span> ?????
26691 this.clearSelections();
26692 this.el.update("");
26694 var records = this.store.getRange();
26695 if(records.length < 1) {
26697 // is this valid?? = should it render a template??
26699 this.el.update(this.emptyText);
26703 if (this.dataName) {
26704 this.el.update(t.apply(this.store.meta)); //????
26705 el = this.el.child('.roo-tpl-' + this.dataName);
26708 for(var i = 0, len = records.length; i < len; i++){
26709 var data = this.prepareData(records[i].data, i, records[i]);
26710 this.fireEvent("preparedata", this, data, i, records[i]);
26712 var d = Roo.apply({}, data);
26715 Roo.apply(d, {'roo-id' : Roo.id()});
26719 Roo.each(this.parent.item, function(item){
26720 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26723 Roo.apply(d, {'roo-data-checked' : 'checked'});
26727 html[html.length] = Roo.util.Format.trim(
26729 t.applySubtemplate(this.dataName, d, this.store.meta) :
26736 el.update(html.join(""));
26737 this.nodes = el.dom.childNodes;
26738 this.updateIndexes(0);
26743 * Function to override to reformat the data that is sent to
26744 * the template for each node.
26745 * DEPRICATED - use the preparedata event handler.
26746 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26747 * a JSON object for an UpdateManager bound view).
26749 prepareData : function(data, index, record)
26751 this.fireEvent("preparedata", this, data, index, record);
26755 onUpdate : function(ds, record){
26756 // Roo.log('on update');
26757 this.clearSelections();
26758 var index = this.store.indexOf(record);
26759 var n = this.nodes[index];
26760 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26761 n.parentNode.removeChild(n);
26762 this.updateIndexes(index, index);
26768 onAdd : function(ds, records, index)
26770 //Roo.log(['on Add', ds, records, index] );
26771 this.clearSelections();
26772 if(this.nodes.length == 0){
26776 var n = this.nodes[index];
26777 for(var i = 0, len = records.length; i < len; i++){
26778 var d = this.prepareData(records[i].data, i, records[i]);
26780 this.tpl.insertBefore(n, d);
26783 this.tpl.append(this.el, d);
26786 this.updateIndexes(index);
26789 onRemove : function(ds, record, index){
26790 // Roo.log('onRemove');
26791 this.clearSelections();
26792 var el = this.dataName ?
26793 this.el.child('.roo-tpl-' + this.dataName) :
26796 el.dom.removeChild(this.nodes[index]);
26797 this.updateIndexes(index);
26801 * Refresh an individual node.
26802 * @param {Number} index
26804 refreshNode : function(index){
26805 this.onUpdate(this.store, this.store.getAt(index));
26808 updateIndexes : function(startIndex, endIndex){
26809 var ns = this.nodes;
26810 startIndex = startIndex || 0;
26811 endIndex = endIndex || ns.length - 1;
26812 for(var i = startIndex; i <= endIndex; i++){
26813 ns[i].nodeIndex = i;
26818 * Changes the data store this view uses and refresh the view.
26819 * @param {Store} store
26821 setStore : function(store, initial){
26822 if(!initial && this.store){
26823 this.store.un("datachanged", this.refresh);
26824 this.store.un("add", this.onAdd);
26825 this.store.un("remove", this.onRemove);
26826 this.store.un("update", this.onUpdate);
26827 this.store.un("clear", this.refresh);
26828 this.store.un("beforeload", this.onBeforeLoad);
26829 this.store.un("load", this.onLoad);
26830 this.store.un("loadexception", this.onLoad);
26834 store.on("datachanged", this.refresh, this);
26835 store.on("add", this.onAdd, this);
26836 store.on("remove", this.onRemove, this);
26837 store.on("update", this.onUpdate, this);
26838 store.on("clear", this.refresh, this);
26839 store.on("beforeload", this.onBeforeLoad, this);
26840 store.on("load", this.onLoad, this);
26841 store.on("loadexception", this.onLoad, this);
26849 * onbeforeLoad - masks the loading area.
26852 onBeforeLoad : function(store,opts)
26854 //Roo.log('onBeforeLoad');
26856 this.el.update("");
26858 this.el.mask(this.mask ? this.mask : "Loading" );
26860 onLoad : function ()
26867 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26868 * @param {HTMLElement} node
26869 * @return {HTMLElement} The template node
26871 findItemFromChild : function(node){
26872 var el = this.dataName ?
26873 this.el.child('.roo-tpl-' + this.dataName,true) :
26876 if(!node || node.parentNode == el){
26879 var p = node.parentNode;
26880 while(p && p != el){
26881 if(p.parentNode == el){
26890 onClick : function(e){
26891 var item = this.findItemFromChild(e.getTarget());
26893 var index = this.indexOf(item);
26894 if(this.onItemClick(item, index, e) !== false){
26895 this.fireEvent("click", this, index, item, e);
26898 this.clearSelections();
26903 onContextMenu : function(e){
26904 var item = this.findItemFromChild(e.getTarget());
26906 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26911 onDblClick : function(e){
26912 var item = this.findItemFromChild(e.getTarget());
26914 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26918 onItemClick : function(item, index, e)
26920 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26923 if (this.toggleSelect) {
26924 var m = this.isSelected(item) ? 'unselect' : 'select';
26927 _t[m](item, true, false);
26930 if(this.multiSelect || this.singleSelect){
26931 if(this.multiSelect && e.shiftKey && this.lastSelection){
26932 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26934 this.select(item, this.multiSelect && e.ctrlKey);
26935 this.lastSelection = item;
26938 if(!this.tickable){
26939 e.preventDefault();
26947 * Get the number of selected nodes.
26950 getSelectionCount : function(){
26951 return this.selections.length;
26955 * Get the currently selected nodes.
26956 * @return {Array} An array of HTMLElements
26958 getSelectedNodes : function(){
26959 return this.selections;
26963 * Get the indexes of the selected nodes.
26966 getSelectedIndexes : function(){
26967 var indexes = [], s = this.selections;
26968 for(var i = 0, len = s.length; i < len; i++){
26969 indexes.push(s[i].nodeIndex);
26975 * Clear all selections
26976 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26978 clearSelections : function(suppressEvent){
26979 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26980 this.cmp.elements = this.selections;
26981 this.cmp.removeClass(this.selectedClass);
26982 this.selections = [];
26983 if(!suppressEvent){
26984 this.fireEvent("selectionchange", this, this.selections);
26990 * Returns true if the passed node is selected
26991 * @param {HTMLElement/Number} node The node or node index
26992 * @return {Boolean}
26994 isSelected : function(node){
26995 var s = this.selections;
26999 node = this.getNode(node);
27000 return s.indexOf(node) !== -1;
27005 * @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
27006 * @param {Boolean} keepExisting (optional) true to keep existing selections
27007 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27009 select : function(nodeInfo, keepExisting, suppressEvent){
27010 if(nodeInfo instanceof Array){
27012 this.clearSelections(true);
27014 for(var i = 0, len = nodeInfo.length; i < len; i++){
27015 this.select(nodeInfo[i], true, true);
27019 var node = this.getNode(nodeInfo);
27020 if(!node || this.isSelected(node)){
27021 return; // already selected.
27024 this.clearSelections(true);
27027 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27028 Roo.fly(node).addClass(this.selectedClass);
27029 this.selections.push(node);
27030 if(!suppressEvent){
27031 this.fireEvent("selectionchange", this, this.selections);
27039 * @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
27040 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27041 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27043 unselect : function(nodeInfo, keepExisting, suppressEvent)
27045 if(nodeInfo instanceof Array){
27046 Roo.each(this.selections, function(s) {
27047 this.unselect(s, nodeInfo);
27051 var node = this.getNode(nodeInfo);
27052 if(!node || !this.isSelected(node)){
27053 //Roo.log("not selected");
27054 return; // not selected.
27058 Roo.each(this.selections, function(s) {
27060 Roo.fly(node).removeClass(this.selectedClass);
27067 this.selections= ns;
27068 this.fireEvent("selectionchange", this, this.selections);
27072 * Gets a template node.
27073 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27074 * @return {HTMLElement} The node or null if it wasn't found
27076 getNode : function(nodeInfo){
27077 if(typeof nodeInfo == "string"){
27078 return document.getElementById(nodeInfo);
27079 }else if(typeof nodeInfo == "number"){
27080 return this.nodes[nodeInfo];
27086 * Gets a range template nodes.
27087 * @param {Number} startIndex
27088 * @param {Number} endIndex
27089 * @return {Array} An array of nodes
27091 getNodes : function(start, end){
27092 var ns = this.nodes;
27093 start = start || 0;
27094 end = typeof end == "undefined" ? ns.length - 1 : end;
27097 for(var i = start; i <= end; i++){
27101 for(var i = start; i >= end; i--){
27109 * Finds the index of the passed node
27110 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27111 * @return {Number} The index of the node or -1
27113 indexOf : function(node){
27114 node = this.getNode(node);
27115 if(typeof node.nodeIndex == "number"){
27116 return node.nodeIndex;
27118 var ns = this.nodes;
27119 for(var i = 0, len = ns.length; i < len; i++){
27129 * Ext JS Library 1.1.1
27130 * Copyright(c) 2006-2007, Ext JS, LLC.
27132 * Originally Released Under LGPL - original licence link has changed is not relivant.
27135 * <script type="text/javascript">
27139 * @class Roo.JsonView
27140 * @extends Roo.View
27141 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27143 var view = new Roo.JsonView({
27144 container: "my-element",
27145 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27150 // listen for node click?
27151 view.on("click", function(vw, index, node, e){
27152 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27155 // direct load of JSON data
27156 view.load("foobar.php");
27158 // Example from my blog list
27159 var tpl = new Roo.Template(
27160 '<div class="entry">' +
27161 '<a class="entry-title" href="{link}">{title}</a>' +
27162 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27163 "</div><hr />"
27166 var moreView = new Roo.JsonView({
27167 container : "entry-list",
27171 moreView.on("beforerender", this.sortEntries, this);
27173 url: "/blog/get-posts.php",
27174 params: "allposts=true",
27175 text: "Loading Blog Entries..."
27179 * Note: old code is supported with arguments : (container, template, config)
27183 * Create a new JsonView
27185 * @param {Object} config The config object
27188 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27191 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27193 var um = this.el.getUpdateManager();
27194 um.setRenderer(this);
27195 um.on("update", this.onLoad, this);
27196 um.on("failure", this.onLoadException, this);
27199 * @event beforerender
27200 * Fires before rendering of the downloaded JSON data.
27201 * @param {Roo.JsonView} this
27202 * @param {Object} data The JSON data loaded
27206 * Fires when data is loaded.
27207 * @param {Roo.JsonView} this
27208 * @param {Object} data The JSON data loaded
27209 * @param {Object} response The raw Connect response object
27212 * @event loadexception
27213 * Fires when loading fails.
27214 * @param {Roo.JsonView} this
27215 * @param {Object} response The raw Connect response object
27218 'beforerender' : true,
27220 'loadexception' : true
27223 Roo.extend(Roo.JsonView, Roo.View, {
27225 * @type {String} The root property in the loaded JSON object that contains the data
27230 * Refreshes the view.
27232 refresh : function(){
27233 this.clearSelections();
27234 this.el.update("");
27236 var o = this.jsonData;
27237 if(o && o.length > 0){
27238 for(var i = 0, len = o.length; i < len; i++){
27239 var data = this.prepareData(o[i], i, o);
27240 html[html.length] = this.tpl.apply(data);
27243 html.push(this.emptyText);
27245 this.el.update(html.join(""));
27246 this.nodes = this.el.dom.childNodes;
27247 this.updateIndexes(0);
27251 * 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.
27252 * @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:
27255 url: "your-url.php",
27256 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27257 callback: yourFunction,
27258 scope: yourObject, //(optional scope)
27261 text: "Loading...",
27266 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27267 * 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.
27268 * @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}
27269 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27270 * @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.
27273 var um = this.el.getUpdateManager();
27274 um.update.apply(um, arguments);
27277 // note - render is a standard framework call...
27278 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27279 render : function(el, response){
27281 this.clearSelections();
27282 this.el.update("");
27285 if (response != '') {
27286 o = Roo.util.JSON.decode(response.responseText);
27289 o = o[this.jsonRoot];
27295 * The current JSON data or null
27298 this.beforeRender();
27303 * Get the number of records in the current JSON dataset
27306 getCount : function(){
27307 return this.jsonData ? this.jsonData.length : 0;
27311 * Returns the JSON object for the specified node(s)
27312 * @param {HTMLElement/Array} node The node or an array of nodes
27313 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27314 * you get the JSON object for the node
27316 getNodeData : function(node){
27317 if(node instanceof Array){
27319 for(var i = 0, len = node.length; i < len; i++){
27320 data.push(this.getNodeData(node[i]));
27324 return this.jsonData[this.indexOf(node)] || null;
27327 beforeRender : function(){
27328 this.snapshot = this.jsonData;
27330 this.sort.apply(this, this.sortInfo);
27332 this.fireEvent("beforerender", this, this.jsonData);
27335 onLoad : function(el, o){
27336 this.fireEvent("load", this, this.jsonData, o);
27339 onLoadException : function(el, o){
27340 this.fireEvent("loadexception", this, o);
27344 * Filter the data by a specific property.
27345 * @param {String} property A property on your JSON objects
27346 * @param {String/RegExp} value Either string that the property values
27347 * should start with, or a RegExp to test against the property
27349 filter : function(property, value){
27352 var ss = this.snapshot;
27353 if(typeof value == "string"){
27354 var vlen = value.length;
27356 this.clearFilter();
27359 value = value.toLowerCase();
27360 for(var i = 0, len = ss.length; i < len; i++){
27362 if(o[property].substr(0, vlen).toLowerCase() == value){
27366 } else if(value.exec){ // regex?
27367 for(var i = 0, len = ss.length; i < len; i++){
27369 if(value.test(o[property])){
27376 this.jsonData = data;
27382 * Filter by a function. The passed function will be called with each
27383 * object in the current dataset. If the function returns true the value is kept,
27384 * otherwise it is filtered.
27385 * @param {Function} fn
27386 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27388 filterBy : function(fn, scope){
27391 var ss = this.snapshot;
27392 for(var i = 0, len = ss.length; i < len; i++){
27394 if(fn.call(scope || this, o)){
27398 this.jsonData = data;
27404 * Clears the current filter.
27406 clearFilter : function(){
27407 if(this.snapshot && this.jsonData != this.snapshot){
27408 this.jsonData = this.snapshot;
27415 * Sorts the data for this view and refreshes it.
27416 * @param {String} property A property on your JSON objects to sort on
27417 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27418 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27420 sort : function(property, dir, sortType){
27421 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27424 var dsc = dir && dir.toLowerCase() == "desc";
27425 var f = function(o1, o2){
27426 var v1 = sortType ? sortType(o1[p]) : o1[p];
27427 var v2 = sortType ? sortType(o2[p]) : o2[p];
27430 return dsc ? +1 : -1;
27431 } else if(v1 > v2){
27432 return dsc ? -1 : +1;
27437 this.jsonData.sort(f);
27439 if(this.jsonData != this.snapshot){
27440 this.snapshot.sort(f);
27446 * Ext JS Library 1.1.1
27447 * Copyright(c) 2006-2007, Ext JS, LLC.
27449 * Originally Released Under LGPL - original licence link has changed is not relivant.
27452 * <script type="text/javascript">
27457 * @class Roo.ColorPalette
27458 * @extends Roo.Component
27459 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27460 * Here's an example of typical usage:
27462 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27463 cp.render('my-div');
27465 cp.on('select', function(palette, selColor){
27466 // do something with selColor
27470 * Create a new ColorPalette
27471 * @param {Object} config The config object
27473 Roo.ColorPalette = function(config){
27474 Roo.ColorPalette.superclass.constructor.call(this, config);
27478 * Fires when a color is selected
27479 * @param {ColorPalette} this
27480 * @param {String} color The 6-digit color hex code (without the # symbol)
27486 this.on("select", this.handler, this.scope, true);
27489 Roo.extend(Roo.ColorPalette, Roo.Component, {
27491 * @cfg {String} itemCls
27492 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27494 itemCls : "x-color-palette",
27496 * @cfg {String} value
27497 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27498 * the hex codes are case-sensitive.
27501 clickEvent:'click',
27503 ctype: "Roo.ColorPalette",
27506 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27508 allowReselect : false,
27511 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27512 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27513 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27514 * of colors with the width setting until the box is symmetrical.</p>
27515 * <p>You can override individual colors if needed:</p>
27517 var cp = new Roo.ColorPalette();
27518 cp.colors[0] = "FF0000"; // change the first box to red
27521 Or you can provide a custom array of your own for complete control:
27523 var cp = new Roo.ColorPalette();
27524 cp.colors = ["000000", "993300", "333300"];
27529 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27530 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27531 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27532 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27533 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27537 onRender : function(container, position){
27538 var t = new Roo.MasterTemplate(
27539 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27541 var c = this.colors;
27542 for(var i = 0, len = c.length; i < len; i++){
27545 var el = document.createElement("div");
27546 el.className = this.itemCls;
27548 container.dom.insertBefore(el, position);
27549 this.el = Roo.get(el);
27550 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27551 if(this.clickEvent != 'click'){
27552 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27557 afterRender : function(){
27558 Roo.ColorPalette.superclass.afterRender.call(this);
27560 var s = this.value;
27567 handleClick : function(e, t){
27568 e.preventDefault();
27569 if(!this.disabled){
27570 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27571 this.select(c.toUpperCase());
27576 * Selects the specified color in the palette (fires the select event)
27577 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27579 select : function(color){
27580 color = color.replace("#", "");
27581 if(color != this.value || this.allowReselect){
27584 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27586 el.child("a.color-"+color).addClass("x-color-palette-sel");
27587 this.value = color;
27588 this.fireEvent("select", this, color);
27593 * Ext JS Library 1.1.1
27594 * Copyright(c) 2006-2007, Ext JS, LLC.
27596 * Originally Released Under LGPL - original licence link has changed is not relivant.
27599 * <script type="text/javascript">
27603 * @class Roo.DatePicker
27604 * @extends Roo.Component
27605 * Simple date picker class.
27607 * Create a new DatePicker
27608 * @param {Object} config The config object
27610 Roo.DatePicker = function(config){
27611 Roo.DatePicker.superclass.constructor.call(this, config);
27613 this.value = config && config.value ?
27614 config.value.clearTime() : new Date().clearTime();
27619 * Fires when a date is selected
27620 * @param {DatePicker} this
27621 * @param {Date} date The selected date
27625 * @event monthchange
27626 * Fires when the displayed month changes
27627 * @param {DatePicker} this
27628 * @param {Date} date The selected month
27630 'monthchange': true
27634 this.on("select", this.handler, this.scope || this);
27636 // build the disabledDatesRE
27637 if(!this.disabledDatesRE && this.disabledDates){
27638 var dd = this.disabledDates;
27640 for(var i = 0; i < dd.length; i++){
27642 if(i != dd.length-1) {
27646 this.disabledDatesRE = new RegExp(re + ")");
27650 Roo.extend(Roo.DatePicker, Roo.Component, {
27652 * @cfg {String} todayText
27653 * The text to display on the button that selects the current date (defaults to "Today")
27655 todayText : "Today",
27657 * @cfg {String} okText
27658 * The text to display on the ok button
27660 okText : " OK ", //   to give the user extra clicking room
27662 * @cfg {String} cancelText
27663 * The text to display on the cancel button
27665 cancelText : "Cancel",
27667 * @cfg {String} todayTip
27668 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27670 todayTip : "{0} (Spacebar)",
27672 * @cfg {Date} minDate
27673 * Minimum allowable date (JavaScript date object, defaults to null)
27677 * @cfg {Date} maxDate
27678 * Maximum allowable date (JavaScript date object, defaults to null)
27682 * @cfg {String} minText
27683 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27685 minText : "This date is before the minimum date",
27687 * @cfg {String} maxText
27688 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27690 maxText : "This date is after the maximum date",
27692 * @cfg {String} format
27693 * The default date format string which can be overriden for localization support. The format must be
27694 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27698 * @cfg {Array} disabledDays
27699 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27701 disabledDays : null,
27703 * @cfg {String} disabledDaysText
27704 * The tooltip to display when the date falls on a disabled day (defaults to "")
27706 disabledDaysText : "",
27708 * @cfg {RegExp} disabledDatesRE
27709 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27711 disabledDatesRE : null,
27713 * @cfg {String} disabledDatesText
27714 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27716 disabledDatesText : "",
27718 * @cfg {Boolean} constrainToViewport
27719 * True to constrain the date picker to the viewport (defaults to true)
27721 constrainToViewport : true,
27723 * @cfg {Array} monthNames
27724 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27726 monthNames : Date.monthNames,
27728 * @cfg {Array} dayNames
27729 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27731 dayNames : Date.dayNames,
27733 * @cfg {String} nextText
27734 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27736 nextText: 'Next Month (Control+Right)',
27738 * @cfg {String} prevText
27739 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27741 prevText: 'Previous Month (Control+Left)',
27743 * @cfg {String} monthYearText
27744 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27746 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27748 * @cfg {Number} startDay
27749 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27753 * @cfg {Bool} showClear
27754 * Show a clear button (usefull for date form elements that can be blank.)
27760 * Sets the value of the date field
27761 * @param {Date} value The date to set
27763 setValue : function(value){
27764 var old = this.value;
27766 if (typeof(value) == 'string') {
27768 value = Date.parseDate(value, this.format);
27771 value = new Date();
27774 this.value = value.clearTime(true);
27776 this.update(this.value);
27781 * Gets the current selected value of the date field
27782 * @return {Date} The selected date
27784 getValue : function(){
27789 focus : function(){
27791 this.update(this.activeDate);
27796 onRender : function(container, position){
27799 '<table cellspacing="0">',
27800 '<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>',
27801 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27802 var dn = this.dayNames;
27803 for(var i = 0; i < 7; i++){
27804 var d = this.startDay+i;
27808 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27810 m[m.length] = "</tr></thead><tbody><tr>";
27811 for(var i = 0; i < 42; i++) {
27812 if(i % 7 == 0 && i != 0){
27813 m[m.length] = "</tr><tr>";
27815 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27817 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27818 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27820 var el = document.createElement("div");
27821 el.className = "x-date-picker";
27822 el.innerHTML = m.join("");
27824 container.dom.insertBefore(el, position);
27826 this.el = Roo.get(el);
27827 this.eventEl = Roo.get(el.firstChild);
27829 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27830 handler: this.showPrevMonth,
27832 preventDefault:true,
27836 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27837 handler: this.showNextMonth,
27839 preventDefault:true,
27843 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27845 this.monthPicker = this.el.down('div.x-date-mp');
27846 this.monthPicker.enableDisplayMode('block');
27848 var kn = new Roo.KeyNav(this.eventEl, {
27849 "left" : function(e){
27851 this.showPrevMonth() :
27852 this.update(this.activeDate.add("d", -1));
27855 "right" : function(e){
27857 this.showNextMonth() :
27858 this.update(this.activeDate.add("d", 1));
27861 "up" : function(e){
27863 this.showNextYear() :
27864 this.update(this.activeDate.add("d", -7));
27867 "down" : function(e){
27869 this.showPrevYear() :
27870 this.update(this.activeDate.add("d", 7));
27873 "pageUp" : function(e){
27874 this.showNextMonth();
27877 "pageDown" : function(e){
27878 this.showPrevMonth();
27881 "enter" : function(e){
27882 e.stopPropagation();
27889 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27891 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27893 this.el.unselectable();
27895 this.cells = this.el.select("table.x-date-inner tbody td");
27896 this.textNodes = this.el.query("table.x-date-inner tbody span");
27898 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27900 tooltip: this.monthYearText
27903 this.mbtn.on('click', this.showMonthPicker, this);
27904 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27907 var today = (new Date()).dateFormat(this.format);
27909 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27910 if (this.showClear) {
27911 baseTb.add( new Roo.Toolbar.Fill());
27914 text: String.format(this.todayText, today),
27915 tooltip: String.format(this.todayTip, today),
27916 handler: this.selectToday,
27920 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27923 if (this.showClear) {
27925 baseTb.add( new Roo.Toolbar.Fill());
27928 cls: 'x-btn-icon x-btn-clear',
27929 handler: function() {
27931 this.fireEvent("select", this, '');
27941 this.update(this.value);
27944 createMonthPicker : function(){
27945 if(!this.monthPicker.dom.firstChild){
27946 var buf = ['<table border="0" cellspacing="0">'];
27947 for(var i = 0; i < 6; i++){
27949 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27950 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27952 '<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>' :
27953 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27957 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27959 '</button><button type="button" class="x-date-mp-cancel">',
27961 '</button></td></tr>',
27964 this.monthPicker.update(buf.join(''));
27965 this.monthPicker.on('click', this.onMonthClick, this);
27966 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27968 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27969 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27971 this.mpMonths.each(function(m, a, i){
27974 m.dom.xmonth = 5 + Math.round(i * .5);
27976 m.dom.xmonth = Math.round((i-1) * .5);
27982 showMonthPicker : function(){
27983 this.createMonthPicker();
27984 var size = this.el.getSize();
27985 this.monthPicker.setSize(size);
27986 this.monthPicker.child('table').setSize(size);
27988 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27989 this.updateMPMonth(this.mpSelMonth);
27990 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27991 this.updateMPYear(this.mpSelYear);
27993 this.monthPicker.slideIn('t', {duration:.2});
27996 updateMPYear : function(y){
27998 var ys = this.mpYears.elements;
27999 for(var i = 1; i <= 10; i++){
28000 var td = ys[i-1], y2;
28002 y2 = y + Math.round(i * .5);
28003 td.firstChild.innerHTML = y2;
28006 y2 = y - (5-Math.round(i * .5));
28007 td.firstChild.innerHTML = y2;
28010 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28014 updateMPMonth : function(sm){
28015 this.mpMonths.each(function(m, a, i){
28016 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28020 selectMPMonth: function(m){
28024 onMonthClick : function(e, t){
28026 var el = new Roo.Element(t), pn;
28027 if(el.is('button.x-date-mp-cancel')){
28028 this.hideMonthPicker();
28030 else if(el.is('button.x-date-mp-ok')){
28031 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28032 this.hideMonthPicker();
28034 else if(pn = el.up('td.x-date-mp-month', 2)){
28035 this.mpMonths.removeClass('x-date-mp-sel');
28036 pn.addClass('x-date-mp-sel');
28037 this.mpSelMonth = pn.dom.xmonth;
28039 else if(pn = el.up('td.x-date-mp-year', 2)){
28040 this.mpYears.removeClass('x-date-mp-sel');
28041 pn.addClass('x-date-mp-sel');
28042 this.mpSelYear = pn.dom.xyear;
28044 else if(el.is('a.x-date-mp-prev')){
28045 this.updateMPYear(this.mpyear-10);
28047 else if(el.is('a.x-date-mp-next')){
28048 this.updateMPYear(this.mpyear+10);
28052 onMonthDblClick : function(e, t){
28054 var el = new Roo.Element(t), pn;
28055 if(pn = el.up('td.x-date-mp-month', 2)){
28056 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28057 this.hideMonthPicker();
28059 else if(pn = el.up('td.x-date-mp-year', 2)){
28060 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28061 this.hideMonthPicker();
28065 hideMonthPicker : function(disableAnim){
28066 if(this.monthPicker){
28067 if(disableAnim === true){
28068 this.monthPicker.hide();
28070 this.monthPicker.slideOut('t', {duration:.2});
28076 showPrevMonth : function(e){
28077 this.update(this.activeDate.add("mo", -1));
28081 showNextMonth : function(e){
28082 this.update(this.activeDate.add("mo", 1));
28086 showPrevYear : function(){
28087 this.update(this.activeDate.add("y", -1));
28091 showNextYear : function(){
28092 this.update(this.activeDate.add("y", 1));
28096 handleMouseWheel : function(e){
28097 var delta = e.getWheelDelta();
28099 this.showPrevMonth();
28101 } else if(delta < 0){
28102 this.showNextMonth();
28108 handleDateClick : function(e, t){
28110 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28111 this.setValue(new Date(t.dateValue));
28112 this.fireEvent("select", this, this.value);
28117 selectToday : function(){
28118 this.setValue(new Date().clearTime());
28119 this.fireEvent("select", this, this.value);
28123 update : function(date)
28125 var vd = this.activeDate;
28126 this.activeDate = date;
28128 var t = date.getTime();
28129 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28130 this.cells.removeClass("x-date-selected");
28131 this.cells.each(function(c){
28132 if(c.dom.firstChild.dateValue == t){
28133 c.addClass("x-date-selected");
28134 setTimeout(function(){
28135 try{c.dom.firstChild.focus();}catch(e){}
28144 var days = date.getDaysInMonth();
28145 var firstOfMonth = date.getFirstDateOfMonth();
28146 var startingPos = firstOfMonth.getDay()-this.startDay;
28148 if(startingPos <= this.startDay){
28152 var pm = date.add("mo", -1);
28153 var prevStart = pm.getDaysInMonth()-startingPos;
28155 var cells = this.cells.elements;
28156 var textEls = this.textNodes;
28157 days += startingPos;
28159 // convert everything to numbers so it's fast
28160 var day = 86400000;
28161 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28162 var today = new Date().clearTime().getTime();
28163 var sel = date.clearTime().getTime();
28164 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28165 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28166 var ddMatch = this.disabledDatesRE;
28167 var ddText = this.disabledDatesText;
28168 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28169 var ddaysText = this.disabledDaysText;
28170 var format = this.format;
28172 var setCellClass = function(cal, cell){
28174 var t = d.getTime();
28175 cell.firstChild.dateValue = t;
28177 cell.className += " x-date-today";
28178 cell.title = cal.todayText;
28181 cell.className += " x-date-selected";
28182 setTimeout(function(){
28183 try{cell.firstChild.focus();}catch(e){}
28188 cell.className = " x-date-disabled";
28189 cell.title = cal.minText;
28193 cell.className = " x-date-disabled";
28194 cell.title = cal.maxText;
28198 if(ddays.indexOf(d.getDay()) != -1){
28199 cell.title = ddaysText;
28200 cell.className = " x-date-disabled";
28203 if(ddMatch && format){
28204 var fvalue = d.dateFormat(format);
28205 if(ddMatch.test(fvalue)){
28206 cell.title = ddText.replace("%0", fvalue);
28207 cell.className = " x-date-disabled";
28213 for(; i < startingPos; i++) {
28214 textEls[i].innerHTML = (++prevStart);
28215 d.setDate(d.getDate()+1);
28216 cells[i].className = "x-date-prevday";
28217 setCellClass(this, cells[i]);
28219 for(; i < days; i++){
28220 intDay = i - startingPos + 1;
28221 textEls[i].innerHTML = (intDay);
28222 d.setDate(d.getDate()+1);
28223 cells[i].className = "x-date-active";
28224 setCellClass(this, cells[i]);
28227 for(; i < 42; i++) {
28228 textEls[i].innerHTML = (++extraDays);
28229 d.setDate(d.getDate()+1);
28230 cells[i].className = "x-date-nextday";
28231 setCellClass(this, cells[i]);
28234 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28235 this.fireEvent('monthchange', this, date);
28237 if(!this.internalRender){
28238 var main = this.el.dom.firstChild;
28239 var w = main.offsetWidth;
28240 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28241 Roo.fly(main).setWidth(w);
28242 this.internalRender = true;
28243 // opera does not respect the auto grow header center column
28244 // then, after it gets a width opera refuses to recalculate
28245 // without a second pass
28246 if(Roo.isOpera && !this.secondPass){
28247 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28248 this.secondPass = true;
28249 this.update.defer(10, this, [date]);
28257 * Ext JS Library 1.1.1
28258 * Copyright(c) 2006-2007, Ext JS, LLC.
28260 * Originally Released Under LGPL - original licence link has changed is not relivant.
28263 * <script type="text/javascript">
28266 * @class Roo.TabPanel
28267 * @extends Roo.util.Observable
28268 * A lightweight tab container.
28272 // basic tabs 1, built from existing content
28273 var tabs = new Roo.TabPanel("tabs1");
28274 tabs.addTab("script", "View Script");
28275 tabs.addTab("markup", "View Markup");
28276 tabs.activate("script");
28278 // more advanced tabs, built from javascript
28279 var jtabs = new Roo.TabPanel("jtabs");
28280 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28282 // set up the UpdateManager
28283 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28284 var updater = tab2.getUpdateManager();
28285 updater.setDefaultUrl("ajax1.htm");
28286 tab2.on('activate', updater.refresh, updater, true);
28288 // Use setUrl for Ajax loading
28289 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28290 tab3.setUrl("ajax2.htm", null, true);
28293 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28296 jtabs.activate("jtabs-1");
28299 * Create a new TabPanel.
28300 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28301 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28303 Roo.TabPanel = function(container, config){
28305 * The container element for this TabPanel.
28306 * @type Roo.Element
28308 this.el = Roo.get(container, true);
28310 if(typeof config == "boolean"){
28311 this.tabPosition = config ? "bottom" : "top";
28313 Roo.apply(this, config);
28316 if(this.tabPosition == "bottom"){
28317 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28318 this.el.addClass("x-tabs-bottom");
28320 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28321 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28322 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28324 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28326 if(this.tabPosition != "bottom"){
28327 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28328 * @type Roo.Element
28330 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28331 this.el.addClass("x-tabs-top");
28335 this.bodyEl.setStyle("position", "relative");
28337 this.active = null;
28338 this.activateDelegate = this.activate.createDelegate(this);
28343 * Fires when the active tab changes
28344 * @param {Roo.TabPanel} this
28345 * @param {Roo.TabPanelItem} activePanel The new active tab
28349 * @event beforetabchange
28350 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28351 * @param {Roo.TabPanel} this
28352 * @param {Object} e Set cancel to true on this object to cancel the tab change
28353 * @param {Roo.TabPanelItem} tab The tab being changed to
28355 "beforetabchange" : true
28358 Roo.EventManager.onWindowResize(this.onResize, this);
28359 this.cpad = this.el.getPadding("lr");
28360 this.hiddenCount = 0;
28363 // toolbar on the tabbar support...
28364 if (this.toolbar) {
28365 var tcfg = this.toolbar;
28366 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28367 this.toolbar = new Roo.Toolbar(tcfg);
28368 if (Roo.isSafari) {
28369 var tbl = tcfg.container.child('table', true);
28370 tbl.setAttribute('width', '100%');
28377 Roo.TabPanel.superclass.constructor.call(this);
28380 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28382 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28384 tabPosition : "top",
28386 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28388 currentTabWidth : 0,
28390 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28394 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28398 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28400 preferredTabWidth : 175,
28402 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28404 resizeTabs : false,
28406 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28408 monitorResize : true,
28410 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28415 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28416 * @param {String} id The id of the div to use <b>or create</b>
28417 * @param {String} text The text for the tab
28418 * @param {String} content (optional) Content to put in the TabPanelItem body
28419 * @param {Boolean} closable (optional) True to create a close icon on the tab
28420 * @return {Roo.TabPanelItem} The created TabPanelItem
28422 addTab : function(id, text, content, closable){
28423 var item = new Roo.TabPanelItem(this, id, text, closable);
28424 this.addTabItem(item);
28426 item.setContent(content);
28432 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28433 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28434 * @return {Roo.TabPanelItem}
28436 getTab : function(id){
28437 return this.items[id];
28441 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28442 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28444 hideTab : function(id){
28445 var t = this.items[id];
28448 this.hiddenCount++;
28449 this.autoSizeTabs();
28454 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28455 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28457 unhideTab : function(id){
28458 var t = this.items[id];
28460 t.setHidden(false);
28461 this.hiddenCount--;
28462 this.autoSizeTabs();
28467 * Adds an existing {@link Roo.TabPanelItem}.
28468 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28470 addTabItem : function(item){
28471 this.items[item.id] = item;
28472 this.items.push(item);
28473 if(this.resizeTabs){
28474 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28475 this.autoSizeTabs();
28482 * Removes a {@link Roo.TabPanelItem}.
28483 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28485 removeTab : function(id){
28486 var items = this.items;
28487 var tab = items[id];
28488 if(!tab) { return; }
28489 var index = items.indexOf(tab);
28490 if(this.active == tab && items.length > 1){
28491 var newTab = this.getNextAvailable(index);
28496 this.stripEl.dom.removeChild(tab.pnode.dom);
28497 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28498 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28500 items.splice(index, 1);
28501 delete this.items[tab.id];
28502 tab.fireEvent("close", tab);
28503 tab.purgeListeners();
28504 this.autoSizeTabs();
28507 getNextAvailable : function(start){
28508 var items = this.items;
28510 // look for a next tab that will slide over to
28511 // replace the one being removed
28512 while(index < items.length){
28513 var item = items[++index];
28514 if(item && !item.isHidden()){
28518 // if one isn't found select the previous tab (on the left)
28521 var item = items[--index];
28522 if(item && !item.isHidden()){
28530 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28531 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28533 disableTab : function(id){
28534 var tab = this.items[id];
28535 if(tab && this.active != tab){
28541 * Enables a {@link Roo.TabPanelItem} that is disabled.
28542 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28544 enableTab : function(id){
28545 var tab = this.items[id];
28550 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28551 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28552 * @return {Roo.TabPanelItem} The TabPanelItem.
28554 activate : function(id){
28555 var tab = this.items[id];
28559 if(tab == this.active || tab.disabled){
28563 this.fireEvent("beforetabchange", this, e, tab);
28564 if(e.cancel !== true && !tab.disabled){
28566 this.active.hide();
28568 this.active = this.items[id];
28569 this.active.show();
28570 this.fireEvent("tabchange", this, this.active);
28576 * Gets the active {@link Roo.TabPanelItem}.
28577 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28579 getActiveTab : function(){
28580 return this.active;
28584 * Updates the tab body element to fit the height of the container element
28585 * for overflow scrolling
28586 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28588 syncHeight : function(targetHeight){
28589 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28590 var bm = this.bodyEl.getMargins();
28591 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28592 this.bodyEl.setHeight(newHeight);
28596 onResize : function(){
28597 if(this.monitorResize){
28598 this.autoSizeTabs();
28603 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28605 beginUpdate : function(){
28606 this.updating = true;
28610 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28612 endUpdate : function(){
28613 this.updating = false;
28614 this.autoSizeTabs();
28618 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28620 autoSizeTabs : function(){
28621 var count = this.items.length;
28622 var vcount = count - this.hiddenCount;
28623 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28626 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28627 var availWidth = Math.floor(w / vcount);
28628 var b = this.stripBody;
28629 if(b.getWidth() > w){
28630 var tabs = this.items;
28631 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28632 if(availWidth < this.minTabWidth){
28633 /*if(!this.sleft){ // incomplete scrolling code
28634 this.createScrollButtons();
28637 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28640 if(this.currentTabWidth < this.preferredTabWidth){
28641 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28647 * Returns the number of tabs in this TabPanel.
28650 getCount : function(){
28651 return this.items.length;
28655 * Resizes all the tabs to the passed width
28656 * @param {Number} The new width
28658 setTabWidth : function(width){
28659 this.currentTabWidth = width;
28660 for(var i = 0, len = this.items.length; i < len; i++) {
28661 if(!this.items[i].isHidden()) {
28662 this.items[i].setWidth(width);
28668 * Destroys this TabPanel
28669 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28671 destroy : function(removeEl){
28672 Roo.EventManager.removeResizeListener(this.onResize, this);
28673 for(var i = 0, len = this.items.length; i < len; i++){
28674 this.items[i].purgeListeners();
28676 if(removeEl === true){
28677 this.el.update("");
28684 * @class Roo.TabPanelItem
28685 * @extends Roo.util.Observable
28686 * Represents an individual item (tab plus body) in a TabPanel.
28687 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28688 * @param {String} id The id of this TabPanelItem
28689 * @param {String} text The text for the tab of this TabPanelItem
28690 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28692 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28694 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28695 * @type Roo.TabPanel
28697 this.tabPanel = tabPanel;
28699 * The id for this TabPanelItem
28704 this.disabled = false;
28708 this.loaded = false;
28709 this.closable = closable;
28712 * The body element for this TabPanelItem.
28713 * @type Roo.Element
28715 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28716 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28717 this.bodyEl.setStyle("display", "block");
28718 this.bodyEl.setStyle("zoom", "1");
28721 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28723 this.el = Roo.get(els.el, true);
28724 this.inner = Roo.get(els.inner, true);
28725 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28726 this.pnode = Roo.get(els.el.parentNode, true);
28727 this.el.on("mousedown", this.onTabMouseDown, this);
28728 this.el.on("click", this.onTabClick, this);
28731 var c = Roo.get(els.close, true);
28732 c.dom.title = this.closeText;
28733 c.addClassOnOver("close-over");
28734 c.on("click", this.closeClick, this);
28740 * Fires when this tab becomes the active tab.
28741 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28742 * @param {Roo.TabPanelItem} this
28746 * @event beforeclose
28747 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28748 * @param {Roo.TabPanelItem} this
28749 * @param {Object} e Set cancel to true on this object to cancel the close.
28751 "beforeclose": true,
28754 * Fires when this tab is closed.
28755 * @param {Roo.TabPanelItem} this
28759 * @event deactivate
28760 * Fires when this tab is no longer the active tab.
28761 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28762 * @param {Roo.TabPanelItem} this
28764 "deactivate" : true
28766 this.hidden = false;
28768 Roo.TabPanelItem.superclass.constructor.call(this);
28771 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28772 purgeListeners : function(){
28773 Roo.util.Observable.prototype.purgeListeners.call(this);
28774 this.el.removeAllListeners();
28777 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28780 this.pnode.addClass("on");
28783 this.tabPanel.stripWrap.repaint();
28785 this.fireEvent("activate", this.tabPanel, this);
28789 * Returns true if this tab is the active tab.
28790 * @return {Boolean}
28792 isActive : function(){
28793 return this.tabPanel.getActiveTab() == this;
28797 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28800 this.pnode.removeClass("on");
28802 this.fireEvent("deactivate", this.tabPanel, this);
28805 hideAction : function(){
28806 this.bodyEl.hide();
28807 this.bodyEl.setStyle("position", "absolute");
28808 this.bodyEl.setLeft("-20000px");
28809 this.bodyEl.setTop("-20000px");
28812 showAction : function(){
28813 this.bodyEl.setStyle("position", "relative");
28814 this.bodyEl.setTop("");
28815 this.bodyEl.setLeft("");
28816 this.bodyEl.show();
28820 * Set the tooltip for the tab.
28821 * @param {String} tooltip The tab's tooltip
28823 setTooltip : function(text){
28824 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28825 this.textEl.dom.qtip = text;
28826 this.textEl.dom.removeAttribute('title');
28828 this.textEl.dom.title = text;
28832 onTabClick : function(e){
28833 e.preventDefault();
28834 this.tabPanel.activate(this.id);
28837 onTabMouseDown : function(e){
28838 e.preventDefault();
28839 this.tabPanel.activate(this.id);
28842 getWidth : function(){
28843 return this.inner.getWidth();
28846 setWidth : function(width){
28847 var iwidth = width - this.pnode.getPadding("lr");
28848 this.inner.setWidth(iwidth);
28849 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28850 this.pnode.setWidth(width);
28854 * Show or hide the tab
28855 * @param {Boolean} hidden True to hide or false to show.
28857 setHidden : function(hidden){
28858 this.hidden = hidden;
28859 this.pnode.setStyle("display", hidden ? "none" : "");
28863 * Returns true if this tab is "hidden"
28864 * @return {Boolean}
28866 isHidden : function(){
28867 return this.hidden;
28871 * Returns the text for this tab
28874 getText : function(){
28878 autoSize : function(){
28879 //this.el.beginMeasure();
28880 this.textEl.setWidth(1);
28882 * #2804 [new] Tabs in Roojs
28883 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28885 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28886 //this.el.endMeasure();
28890 * Sets the text for the tab (Note: this also sets the tooltip text)
28891 * @param {String} text The tab's text and tooltip
28893 setText : function(text){
28895 this.textEl.update(text);
28896 this.setTooltip(text);
28897 if(!this.tabPanel.resizeTabs){
28902 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28904 activate : function(){
28905 this.tabPanel.activate(this.id);
28909 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28911 disable : function(){
28912 if(this.tabPanel.active != this){
28913 this.disabled = true;
28914 this.pnode.addClass("disabled");
28919 * Enables this TabPanelItem if it was previously disabled.
28921 enable : function(){
28922 this.disabled = false;
28923 this.pnode.removeClass("disabled");
28927 * Sets the content for this TabPanelItem.
28928 * @param {String} content The content
28929 * @param {Boolean} loadScripts true to look for and load scripts
28931 setContent : function(content, loadScripts){
28932 this.bodyEl.update(content, loadScripts);
28936 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28937 * @return {Roo.UpdateManager} The UpdateManager
28939 getUpdateManager : function(){
28940 return this.bodyEl.getUpdateManager();
28944 * Set a URL to be used to load the content for this TabPanelItem.
28945 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28946 * @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)
28947 * @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)
28948 * @return {Roo.UpdateManager} The UpdateManager
28950 setUrl : function(url, params, loadOnce){
28951 if(this.refreshDelegate){
28952 this.un('activate', this.refreshDelegate);
28954 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28955 this.on("activate", this.refreshDelegate);
28956 return this.bodyEl.getUpdateManager();
28960 _handleRefresh : function(url, params, loadOnce){
28961 if(!loadOnce || !this.loaded){
28962 var updater = this.bodyEl.getUpdateManager();
28963 updater.update(url, params, this._setLoaded.createDelegate(this));
28968 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28969 * Will fail silently if the setUrl method has not been called.
28970 * This does not activate the panel, just updates its content.
28972 refresh : function(){
28973 if(this.refreshDelegate){
28974 this.loaded = false;
28975 this.refreshDelegate();
28980 _setLoaded : function(){
28981 this.loaded = true;
28985 closeClick : function(e){
28988 this.fireEvent("beforeclose", this, o);
28989 if(o.cancel !== true){
28990 this.tabPanel.removeTab(this.id);
28994 * The text displayed in the tooltip for the close icon.
28997 closeText : "Close this tab"
29001 Roo.TabPanel.prototype.createStrip = function(container){
29002 var strip = document.createElement("div");
29003 strip.className = "x-tabs-wrap";
29004 container.appendChild(strip);
29008 Roo.TabPanel.prototype.createStripList = function(strip){
29009 // div wrapper for retard IE
29010 // returns the "tr" element.
29011 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29012 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29013 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29014 return strip.firstChild.firstChild.firstChild.firstChild;
29017 Roo.TabPanel.prototype.createBody = function(container){
29018 var body = document.createElement("div");
29019 Roo.id(body, "tab-body");
29020 Roo.fly(body).addClass("x-tabs-body");
29021 container.appendChild(body);
29025 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29026 var body = Roo.getDom(id);
29028 body = document.createElement("div");
29031 Roo.fly(body).addClass("x-tabs-item-body");
29032 bodyEl.insertBefore(body, bodyEl.firstChild);
29036 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29037 var td = document.createElement("td");
29038 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29039 //stripEl.appendChild(td);
29041 td.className = "x-tabs-closable";
29042 if(!this.closeTpl){
29043 this.closeTpl = new Roo.Template(
29044 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29045 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29046 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29049 var el = this.closeTpl.overwrite(td, {"text": text});
29050 var close = el.getElementsByTagName("div")[0];
29051 var inner = el.getElementsByTagName("em")[0];
29052 return {"el": el, "close": close, "inner": inner};
29055 this.tabTpl = new Roo.Template(
29056 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29057 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29060 var el = this.tabTpl.overwrite(td, {"text": text});
29061 var inner = el.getElementsByTagName("em")[0];
29062 return {"el": el, "inner": inner};
29066 * Ext JS Library 1.1.1
29067 * Copyright(c) 2006-2007, Ext JS, LLC.
29069 * Originally Released Under LGPL - original licence link has changed is not relivant.
29072 * <script type="text/javascript">
29076 * @class Roo.Button
29077 * @extends Roo.util.Observable
29078 * Simple Button class
29079 * @cfg {String} text The button text
29080 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29081 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29082 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29083 * @cfg {Object} scope The scope of the handler
29084 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29085 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29086 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29087 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29088 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29089 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29090 applies if enableToggle = true)
29091 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29092 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29093 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29095 * Create a new button
29096 * @param {Object} config The config object
29098 Roo.Button = function(renderTo, config)
29102 renderTo = config.renderTo || false;
29105 Roo.apply(this, config);
29109 * Fires when this button is clicked
29110 * @param {Button} this
29111 * @param {EventObject} e The click event
29116 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29117 * @param {Button} this
29118 * @param {Boolean} pressed
29123 * Fires when the mouse hovers over the button
29124 * @param {Button} this
29125 * @param {Event} e The event object
29127 'mouseover' : true,
29130 * Fires when the mouse exits the button
29131 * @param {Button} this
29132 * @param {Event} e The event object
29137 * Fires when the button is rendered
29138 * @param {Button} this
29143 this.menu = Roo.menu.MenuMgr.get(this.menu);
29145 // register listeners first!! - so render can be captured..
29146 Roo.util.Observable.call(this);
29148 this.render(renderTo);
29154 Roo.extend(Roo.Button, Roo.util.Observable, {
29160 * Read-only. True if this button is hidden
29165 * Read-only. True if this button is disabled
29170 * Read-only. True if this button is pressed (only if enableToggle = true)
29176 * @cfg {Number} tabIndex
29177 * The DOM tabIndex for this button (defaults to undefined)
29179 tabIndex : undefined,
29182 * @cfg {Boolean} enableToggle
29183 * True to enable pressed/not pressed toggling (defaults to false)
29185 enableToggle: false,
29187 * @cfg {Mixed} menu
29188 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29192 * @cfg {String} menuAlign
29193 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29195 menuAlign : "tl-bl?",
29198 * @cfg {String} iconCls
29199 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29201 iconCls : undefined,
29203 * @cfg {String} type
29204 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29209 menuClassTarget: 'tr',
29212 * @cfg {String} clickEvent
29213 * The type of event to map to the button's event handler (defaults to 'click')
29215 clickEvent : 'click',
29218 * @cfg {Boolean} handleMouseEvents
29219 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29221 handleMouseEvents : true,
29224 * @cfg {String} tooltipType
29225 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29227 tooltipType : 'qtip',
29230 * @cfg {String} cls
29231 * A CSS class to apply to the button's main element.
29235 * @cfg {Roo.Template} template (Optional)
29236 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29237 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29238 * require code modifications if required elements (e.g. a button) aren't present.
29242 render : function(renderTo){
29244 if(this.hideParent){
29245 this.parentEl = Roo.get(renderTo);
29247 if(!this.dhconfig){
29248 if(!this.template){
29249 if(!Roo.Button.buttonTemplate){
29250 // hideous table template
29251 Roo.Button.buttonTemplate = new Roo.Template(
29252 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29253 '<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>',
29254 "</tr></tbody></table>");
29256 this.template = Roo.Button.buttonTemplate;
29258 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29259 var btnEl = btn.child("button:first");
29260 btnEl.on('focus', this.onFocus, this);
29261 btnEl.on('blur', this.onBlur, this);
29263 btn.addClass(this.cls);
29266 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29269 btnEl.addClass(this.iconCls);
29271 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29274 if(this.tabIndex !== undefined){
29275 btnEl.dom.tabIndex = this.tabIndex;
29278 if(typeof this.tooltip == 'object'){
29279 Roo.QuickTips.tips(Roo.apply({
29283 btnEl.dom[this.tooltipType] = this.tooltip;
29287 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29291 this.el.dom.id = this.el.id = this.id;
29294 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29295 this.menu.on("show", this.onMenuShow, this);
29296 this.menu.on("hide", this.onMenuHide, this);
29298 btn.addClass("x-btn");
29299 if(Roo.isIE && !Roo.isIE7){
29300 this.autoWidth.defer(1, this);
29304 if(this.handleMouseEvents){
29305 btn.on("mouseover", this.onMouseOver, this);
29306 btn.on("mouseout", this.onMouseOut, this);
29307 btn.on("mousedown", this.onMouseDown, this);
29309 btn.on(this.clickEvent, this.onClick, this);
29310 //btn.on("mouseup", this.onMouseUp, this);
29317 Roo.ButtonToggleMgr.register(this);
29319 this.el.addClass("x-btn-pressed");
29322 var repeater = new Roo.util.ClickRepeater(btn,
29323 typeof this.repeat == "object" ? this.repeat : {}
29325 repeater.on("click", this.onClick, this);
29328 this.fireEvent('render', this);
29332 * Returns the button's underlying element
29333 * @return {Roo.Element} The element
29335 getEl : function(){
29340 * Destroys this Button and removes any listeners.
29342 destroy : function(){
29343 Roo.ButtonToggleMgr.unregister(this);
29344 this.el.removeAllListeners();
29345 this.purgeListeners();
29350 autoWidth : function(){
29352 this.el.setWidth("auto");
29353 if(Roo.isIE7 && Roo.isStrict){
29354 var ib = this.el.child('button');
29355 if(ib && ib.getWidth() > 20){
29357 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29362 this.el.beginMeasure();
29364 if(this.el.getWidth() < this.minWidth){
29365 this.el.setWidth(this.minWidth);
29368 this.el.endMeasure();
29375 * Assigns this button's click handler
29376 * @param {Function} handler The function to call when the button is clicked
29377 * @param {Object} scope (optional) Scope for the function passed in
29379 setHandler : function(handler, scope){
29380 this.handler = handler;
29381 this.scope = scope;
29385 * Sets this button's text
29386 * @param {String} text The button text
29388 setText : function(text){
29391 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29397 * Gets the text for this button
29398 * @return {String} The button text
29400 getText : function(){
29408 this.hidden = false;
29410 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29418 this.hidden = true;
29420 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29425 * Convenience function for boolean show/hide
29426 * @param {Boolean} visible True to show, false to hide
29428 setVisible: function(visible){
29437 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29438 * @param {Boolean} state (optional) Force a particular state
29440 toggle : function(state){
29441 state = state === undefined ? !this.pressed : state;
29442 if(state != this.pressed){
29444 this.el.addClass("x-btn-pressed");
29445 this.pressed = true;
29446 this.fireEvent("toggle", this, true);
29448 this.el.removeClass("x-btn-pressed");
29449 this.pressed = false;
29450 this.fireEvent("toggle", this, false);
29452 if(this.toggleHandler){
29453 this.toggleHandler.call(this.scope || this, this, state);
29461 focus : function(){
29462 this.el.child('button:first').focus();
29466 * Disable this button
29468 disable : function(){
29470 this.el.addClass("x-btn-disabled");
29472 this.disabled = true;
29476 * Enable this button
29478 enable : function(){
29480 this.el.removeClass("x-btn-disabled");
29482 this.disabled = false;
29486 * Convenience function for boolean enable/disable
29487 * @param {Boolean} enabled True to enable, false to disable
29489 setDisabled : function(v){
29490 this[v !== true ? "enable" : "disable"]();
29494 onClick : function(e)
29497 e.preventDefault();
29502 if(!this.disabled){
29503 if(this.enableToggle){
29506 if(this.menu && !this.menu.isVisible()){
29507 this.menu.show(this.el, this.menuAlign);
29509 this.fireEvent("click", this, e);
29511 this.el.removeClass("x-btn-over");
29512 this.handler.call(this.scope || this, this, e);
29517 onMouseOver : function(e){
29518 if(!this.disabled){
29519 this.el.addClass("x-btn-over");
29520 this.fireEvent('mouseover', this, e);
29524 onMouseOut : function(e){
29525 if(!e.within(this.el, true)){
29526 this.el.removeClass("x-btn-over");
29527 this.fireEvent('mouseout', this, e);
29531 onFocus : function(e){
29532 if(!this.disabled){
29533 this.el.addClass("x-btn-focus");
29537 onBlur : function(e){
29538 this.el.removeClass("x-btn-focus");
29541 onMouseDown : function(e){
29542 if(!this.disabled && e.button == 0){
29543 this.el.addClass("x-btn-click");
29544 Roo.get(document).on('mouseup', this.onMouseUp, this);
29548 onMouseUp : function(e){
29550 this.el.removeClass("x-btn-click");
29551 Roo.get(document).un('mouseup', this.onMouseUp, this);
29555 onMenuShow : function(e){
29556 this.el.addClass("x-btn-menu-active");
29559 onMenuHide : function(e){
29560 this.el.removeClass("x-btn-menu-active");
29564 // Private utility class used by Button
29565 Roo.ButtonToggleMgr = function(){
29568 function toggleGroup(btn, state){
29570 var g = groups[btn.toggleGroup];
29571 for(var i = 0, l = g.length; i < l; i++){
29573 g[i].toggle(false);
29580 register : function(btn){
29581 if(!btn.toggleGroup){
29584 var g = groups[btn.toggleGroup];
29586 g = groups[btn.toggleGroup] = [];
29589 btn.on("toggle", toggleGroup);
29592 unregister : function(btn){
29593 if(!btn.toggleGroup){
29596 var g = groups[btn.toggleGroup];
29599 btn.un("toggle", toggleGroup);
29605 * Ext JS Library 1.1.1
29606 * Copyright(c) 2006-2007, Ext JS, LLC.
29608 * Originally Released Under LGPL - original licence link has changed is not relivant.
29611 * <script type="text/javascript">
29615 * @class Roo.SplitButton
29616 * @extends Roo.Button
29617 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29618 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29619 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29620 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29621 * @cfg {String} arrowTooltip The title attribute of the arrow
29623 * Create a new menu button
29624 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29625 * @param {Object} config The config object
29627 Roo.SplitButton = function(renderTo, config){
29628 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29630 * @event arrowclick
29631 * Fires when this button's arrow is clicked
29632 * @param {SplitButton} this
29633 * @param {EventObject} e The click event
29635 this.addEvents({"arrowclick":true});
29638 Roo.extend(Roo.SplitButton, Roo.Button, {
29639 render : function(renderTo){
29640 // this is one sweet looking template!
29641 var tpl = new Roo.Template(
29642 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29643 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29644 '<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>',
29645 "</tbody></table></td><td>",
29646 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29647 '<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>',
29648 "</tbody></table></td></tr></table>"
29650 var btn = tpl.append(renderTo, [this.text, this.type], true);
29651 var btnEl = btn.child("button");
29653 btn.addClass(this.cls);
29656 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29659 btnEl.addClass(this.iconCls);
29661 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29665 if(this.handleMouseEvents){
29666 btn.on("mouseover", this.onMouseOver, this);
29667 btn.on("mouseout", this.onMouseOut, this);
29668 btn.on("mousedown", this.onMouseDown, this);
29669 btn.on("mouseup", this.onMouseUp, this);
29671 btn.on(this.clickEvent, this.onClick, this);
29673 if(typeof this.tooltip == 'object'){
29674 Roo.QuickTips.tips(Roo.apply({
29678 btnEl.dom[this.tooltipType] = this.tooltip;
29681 if(this.arrowTooltip){
29682 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29691 this.el.addClass("x-btn-pressed");
29693 if(Roo.isIE && !Roo.isIE7){
29694 this.autoWidth.defer(1, this);
29699 this.menu.on("show", this.onMenuShow, this);
29700 this.menu.on("hide", this.onMenuHide, this);
29702 this.fireEvent('render', this);
29706 autoWidth : function(){
29708 var tbl = this.el.child("table:first");
29709 var tbl2 = this.el.child("table:last");
29710 this.el.setWidth("auto");
29711 tbl.setWidth("auto");
29712 if(Roo.isIE7 && Roo.isStrict){
29713 var ib = this.el.child('button:first');
29714 if(ib && ib.getWidth() > 20){
29716 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29721 this.el.beginMeasure();
29723 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29724 tbl.setWidth(this.minWidth-tbl2.getWidth());
29727 this.el.endMeasure();
29730 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29734 * Sets this button's click handler
29735 * @param {Function} handler The function to call when the button is clicked
29736 * @param {Object} scope (optional) Scope for the function passed above
29738 setHandler : function(handler, scope){
29739 this.handler = handler;
29740 this.scope = scope;
29744 * Sets this button's arrow click handler
29745 * @param {Function} handler The function to call when the arrow is clicked
29746 * @param {Object} scope (optional) Scope for the function passed above
29748 setArrowHandler : function(handler, scope){
29749 this.arrowHandler = handler;
29750 this.scope = scope;
29756 focus : function(){
29758 this.el.child("button:first").focus();
29763 onClick : function(e){
29764 e.preventDefault();
29765 if(!this.disabled){
29766 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29767 if(this.menu && !this.menu.isVisible()){
29768 this.menu.show(this.el, this.menuAlign);
29770 this.fireEvent("arrowclick", this, e);
29771 if(this.arrowHandler){
29772 this.arrowHandler.call(this.scope || this, this, e);
29775 this.fireEvent("click", this, e);
29777 this.handler.call(this.scope || this, this, e);
29783 onMouseDown : function(e){
29784 if(!this.disabled){
29785 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29789 onMouseUp : function(e){
29790 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29795 // backwards compat
29796 Roo.MenuButton = Roo.SplitButton;/*
29798 * Ext JS Library 1.1.1
29799 * Copyright(c) 2006-2007, Ext JS, LLC.
29801 * Originally Released Under LGPL - original licence link has changed is not relivant.
29804 * <script type="text/javascript">
29808 * @class Roo.Toolbar
29809 * Basic Toolbar class.
29811 * Creates a new Toolbar
29812 * @param {Object} container The config object
29814 Roo.Toolbar = function(container, buttons, config)
29816 /// old consturctor format still supported..
29817 if(container instanceof Array){ // omit the container for later rendering
29818 buttons = container;
29822 if (typeof(container) == 'object' && container.xtype) {
29823 config = container;
29824 container = config.container;
29825 buttons = config.buttons || []; // not really - use items!!
29828 if (config && config.items) {
29829 xitems = config.items;
29830 delete config.items;
29832 Roo.apply(this, config);
29833 this.buttons = buttons;
29836 this.render(container);
29838 this.xitems = xitems;
29839 Roo.each(xitems, function(b) {
29845 Roo.Toolbar.prototype = {
29847 * @cfg {Array} items
29848 * array of button configs or elements to add (will be converted to a MixedCollection)
29852 * @cfg {String/HTMLElement/Element} container
29853 * The id or element that will contain the toolbar
29856 render : function(ct){
29857 this.el = Roo.get(ct);
29859 this.el.addClass(this.cls);
29861 // using a table allows for vertical alignment
29862 // 100% width is needed by Safari...
29863 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29864 this.tr = this.el.child("tr", true);
29866 this.items = new Roo.util.MixedCollection(false, function(o){
29867 return o.id || ("item" + (++autoId));
29870 this.add.apply(this, this.buttons);
29871 delete this.buttons;
29876 * Adds element(s) to the toolbar -- this function takes a variable number of
29877 * arguments of mixed type and adds them to the toolbar.
29878 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29880 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29881 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29882 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29883 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29884 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29885 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29886 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29887 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29888 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29890 * @param {Mixed} arg2
29891 * @param {Mixed} etc.
29894 var a = arguments, l = a.length;
29895 for(var i = 0; i < l; i++){
29900 _add : function(el) {
29903 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29906 if (el.applyTo){ // some kind of form field
29907 return this.addField(el);
29909 if (el.render){ // some kind of Toolbar.Item
29910 return this.addItem(el);
29912 if (typeof el == "string"){ // string
29913 if(el == "separator" || el == "-"){
29914 return this.addSeparator();
29917 return this.addSpacer();
29920 return this.addFill();
29922 return this.addText(el);
29925 if(el.tagName){ // element
29926 return this.addElement(el);
29928 if(typeof el == "object"){ // must be button config?
29929 return this.addButton(el);
29931 // and now what?!?!
29937 * Add an Xtype element
29938 * @param {Object} xtype Xtype Object
29939 * @return {Object} created Object
29941 addxtype : function(e){
29942 return this.add(e);
29946 * Returns the Element for this toolbar.
29947 * @return {Roo.Element}
29949 getEl : function(){
29955 * @return {Roo.Toolbar.Item} The separator item
29957 addSeparator : function(){
29958 return this.addItem(new Roo.Toolbar.Separator());
29962 * Adds a spacer element
29963 * @return {Roo.Toolbar.Spacer} The spacer item
29965 addSpacer : function(){
29966 return this.addItem(new Roo.Toolbar.Spacer());
29970 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29971 * @return {Roo.Toolbar.Fill} The fill item
29973 addFill : function(){
29974 return this.addItem(new Roo.Toolbar.Fill());
29978 * Adds any standard HTML element to the toolbar
29979 * @param {String/HTMLElement/Element} el The element or id of the element to add
29980 * @return {Roo.Toolbar.Item} The element's item
29982 addElement : function(el){
29983 return this.addItem(new Roo.Toolbar.Item(el));
29986 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29987 * @type Roo.util.MixedCollection
29992 * Adds any Toolbar.Item or subclass
29993 * @param {Roo.Toolbar.Item} item
29994 * @return {Roo.Toolbar.Item} The item
29996 addItem : function(item){
29997 var td = this.nextBlock();
29999 this.items.add(item);
30004 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30005 * @param {Object/Array} config A button config or array of configs
30006 * @return {Roo.Toolbar.Button/Array}
30008 addButton : function(config){
30009 if(config instanceof Array){
30011 for(var i = 0, len = config.length; i < len; i++) {
30012 buttons.push(this.addButton(config[i]));
30017 if(!(config instanceof Roo.Toolbar.Button)){
30019 new Roo.Toolbar.SplitButton(config) :
30020 new Roo.Toolbar.Button(config);
30022 var td = this.nextBlock();
30029 * Adds text to the toolbar
30030 * @param {String} text The text to add
30031 * @return {Roo.Toolbar.Item} The element's item
30033 addText : function(text){
30034 return this.addItem(new Roo.Toolbar.TextItem(text));
30038 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30039 * @param {Number} index The index where the item is to be inserted
30040 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30041 * @return {Roo.Toolbar.Button/Item}
30043 insertButton : function(index, item){
30044 if(item instanceof Array){
30046 for(var i = 0, len = item.length; i < len; i++) {
30047 buttons.push(this.insertButton(index + i, item[i]));
30051 if (!(item instanceof Roo.Toolbar.Button)){
30052 item = new Roo.Toolbar.Button(item);
30054 var td = document.createElement("td");
30055 this.tr.insertBefore(td, this.tr.childNodes[index]);
30057 this.items.insert(index, item);
30062 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30063 * @param {Object} config
30064 * @return {Roo.Toolbar.Item} The element's item
30066 addDom : function(config, returnEl){
30067 var td = this.nextBlock();
30068 Roo.DomHelper.overwrite(td, config);
30069 var ti = new Roo.Toolbar.Item(td.firstChild);
30071 this.items.add(ti);
30076 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30077 * @type Roo.util.MixedCollection
30082 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30083 * Note: the field should not have been rendered yet. For a field that has already been
30084 * rendered, use {@link #addElement}.
30085 * @param {Roo.form.Field} field
30086 * @return {Roo.ToolbarItem}
30090 addField : function(field) {
30091 if (!this.fields) {
30093 this.fields = new Roo.util.MixedCollection(false, function(o){
30094 return o.id || ("item" + (++autoId));
30099 var td = this.nextBlock();
30101 var ti = new Roo.Toolbar.Item(td.firstChild);
30103 this.items.add(ti);
30104 this.fields.add(field);
30115 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30116 this.el.child('div').hide();
30124 this.el.child('div').show();
30128 nextBlock : function(){
30129 var td = document.createElement("td");
30130 this.tr.appendChild(td);
30135 destroy : function(){
30136 if(this.items){ // rendered?
30137 Roo.destroy.apply(Roo, this.items.items);
30139 if(this.fields){ // rendered?
30140 Roo.destroy.apply(Roo, this.fields.items);
30142 Roo.Element.uncache(this.el, this.tr);
30147 * @class Roo.Toolbar.Item
30148 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30150 * Creates a new Item
30151 * @param {HTMLElement} el
30153 Roo.Toolbar.Item = function(el){
30155 if (typeof (el.xtype) != 'undefined') {
30160 this.el = Roo.getDom(el);
30161 this.id = Roo.id(this.el);
30162 this.hidden = false;
30167 * Fires when the button is rendered
30168 * @param {Button} this
30172 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30174 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30175 //Roo.Toolbar.Item.prototype = {
30178 * Get this item's HTML Element
30179 * @return {HTMLElement}
30181 getEl : function(){
30186 render : function(td){
30189 td.appendChild(this.el);
30191 this.fireEvent('render', this);
30195 * Removes and destroys this item.
30197 destroy : function(){
30198 this.td.parentNode.removeChild(this.td);
30205 this.hidden = false;
30206 this.td.style.display = "";
30213 this.hidden = true;
30214 this.td.style.display = "none";
30218 * Convenience function for boolean show/hide.
30219 * @param {Boolean} visible true to show/false to hide
30221 setVisible: function(visible){
30230 * Try to focus this item.
30232 focus : function(){
30233 Roo.fly(this.el).focus();
30237 * Disables this item.
30239 disable : function(){
30240 Roo.fly(this.td).addClass("x-item-disabled");
30241 this.disabled = true;
30242 this.el.disabled = true;
30246 * Enables this item.
30248 enable : function(){
30249 Roo.fly(this.td).removeClass("x-item-disabled");
30250 this.disabled = false;
30251 this.el.disabled = false;
30257 * @class Roo.Toolbar.Separator
30258 * @extends Roo.Toolbar.Item
30259 * A simple toolbar separator class
30261 * Creates a new Separator
30263 Roo.Toolbar.Separator = function(cfg){
30265 var s = document.createElement("span");
30266 s.className = "ytb-sep";
30271 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30273 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30274 enable:Roo.emptyFn,
30275 disable:Roo.emptyFn,
30280 * @class Roo.Toolbar.Spacer
30281 * @extends Roo.Toolbar.Item
30282 * A simple element that adds extra horizontal space to a toolbar.
30284 * Creates a new Spacer
30286 Roo.Toolbar.Spacer = function(cfg){
30287 var s = document.createElement("div");
30288 s.className = "ytb-spacer";
30292 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30294 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30295 enable:Roo.emptyFn,
30296 disable:Roo.emptyFn,
30301 * @class Roo.Toolbar.Fill
30302 * @extends Roo.Toolbar.Spacer
30303 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30305 * Creates a new Spacer
30307 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30309 render : function(td){
30310 td.style.width = '100%';
30311 Roo.Toolbar.Fill.superclass.render.call(this, td);
30316 * @class Roo.Toolbar.TextItem
30317 * @extends Roo.Toolbar.Item
30318 * A simple class that renders text directly into a toolbar.
30320 * Creates a new TextItem
30321 * @param {String} text
30323 Roo.Toolbar.TextItem = function(cfg){
30324 var text = cfg || "";
30325 if (typeof(cfg) == 'object') {
30326 text = cfg.text || "";
30330 var s = document.createElement("span");
30331 s.className = "ytb-text";
30332 s.innerHTML = text;
30337 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30339 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30342 enable:Roo.emptyFn,
30343 disable:Roo.emptyFn,
30348 * @class Roo.Toolbar.Button
30349 * @extends Roo.Button
30350 * A button that renders into a toolbar.
30352 * Creates a new Button
30353 * @param {Object} config A standard {@link Roo.Button} config object
30355 Roo.Toolbar.Button = function(config){
30356 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30358 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30359 render : function(td){
30361 Roo.Toolbar.Button.superclass.render.call(this, td);
30365 * Removes and destroys this button
30367 destroy : function(){
30368 Roo.Toolbar.Button.superclass.destroy.call(this);
30369 this.td.parentNode.removeChild(this.td);
30373 * Shows this button
30376 this.hidden = false;
30377 this.td.style.display = "";
30381 * Hides this button
30384 this.hidden = true;
30385 this.td.style.display = "none";
30389 * Disables this item
30391 disable : function(){
30392 Roo.fly(this.td).addClass("x-item-disabled");
30393 this.disabled = true;
30397 * Enables this item
30399 enable : function(){
30400 Roo.fly(this.td).removeClass("x-item-disabled");
30401 this.disabled = false;
30404 // backwards compat
30405 Roo.ToolbarButton = Roo.Toolbar.Button;
30408 * @class Roo.Toolbar.SplitButton
30409 * @extends Roo.SplitButton
30410 * A menu button that renders into a toolbar.
30412 * Creates a new SplitButton
30413 * @param {Object} config A standard {@link Roo.SplitButton} config object
30415 Roo.Toolbar.SplitButton = function(config){
30416 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30418 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30419 render : function(td){
30421 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30425 * Removes and destroys this button
30427 destroy : function(){
30428 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30429 this.td.parentNode.removeChild(this.td);
30433 * Shows this button
30436 this.hidden = false;
30437 this.td.style.display = "";
30441 * Hides this button
30444 this.hidden = true;
30445 this.td.style.display = "none";
30449 // backwards compat
30450 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30452 * Ext JS Library 1.1.1
30453 * Copyright(c) 2006-2007, Ext JS, LLC.
30455 * Originally Released Under LGPL - original licence link has changed is not relivant.
30458 * <script type="text/javascript">
30462 * @class Roo.PagingToolbar
30463 * @extends Roo.Toolbar
30464 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30466 * Create a new PagingToolbar
30467 * @param {Object} config The config object
30469 Roo.PagingToolbar = function(el, ds, config)
30471 // old args format still supported... - xtype is prefered..
30472 if (typeof(el) == 'object' && el.xtype) {
30473 // created from xtype...
30475 ds = el.dataSource;
30476 el = config.container;
30479 if (config.items) {
30480 items = config.items;
30484 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30487 this.renderButtons(this.el);
30490 // supprot items array.
30492 Roo.each(items, function(e) {
30493 this.add(Roo.factory(e));
30498 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30500 * @cfg {Roo.data.Store} dataSource
30501 * The underlying data store providing the paged data
30504 * @cfg {String/HTMLElement/Element} container
30505 * container The id or element that will contain the toolbar
30508 * @cfg {Boolean} displayInfo
30509 * True to display the displayMsg (defaults to false)
30512 * @cfg {Number} pageSize
30513 * The number of records to display per page (defaults to 20)
30517 * @cfg {String} displayMsg
30518 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30520 displayMsg : 'Displaying {0} - {1} of {2}',
30522 * @cfg {String} emptyMsg
30523 * The message to display when no records are found (defaults to "No data to display")
30525 emptyMsg : 'No data to display',
30527 * Customizable piece of the default paging text (defaults to "Page")
30530 beforePageText : "Page",
30532 * Customizable piece of the default paging text (defaults to "of %0")
30535 afterPageText : "of {0}",
30537 * Customizable piece of the default paging text (defaults to "First Page")
30540 firstText : "First Page",
30542 * Customizable piece of the default paging text (defaults to "Previous Page")
30545 prevText : "Previous Page",
30547 * Customizable piece of the default paging text (defaults to "Next Page")
30550 nextText : "Next Page",
30552 * Customizable piece of the default paging text (defaults to "Last Page")
30555 lastText : "Last Page",
30557 * Customizable piece of the default paging text (defaults to "Refresh")
30560 refreshText : "Refresh",
30563 renderButtons : function(el){
30564 Roo.PagingToolbar.superclass.render.call(this, el);
30565 this.first = this.addButton({
30566 tooltip: this.firstText,
30567 cls: "x-btn-icon x-grid-page-first",
30569 handler: this.onClick.createDelegate(this, ["first"])
30571 this.prev = this.addButton({
30572 tooltip: this.prevText,
30573 cls: "x-btn-icon x-grid-page-prev",
30575 handler: this.onClick.createDelegate(this, ["prev"])
30577 //this.addSeparator();
30578 this.add(this.beforePageText);
30579 this.field = Roo.get(this.addDom({
30584 cls: "x-grid-page-number"
30586 this.field.on("keydown", this.onPagingKeydown, this);
30587 this.field.on("focus", function(){this.dom.select();});
30588 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30589 this.field.setHeight(18);
30590 //this.addSeparator();
30591 this.next = this.addButton({
30592 tooltip: this.nextText,
30593 cls: "x-btn-icon x-grid-page-next",
30595 handler: this.onClick.createDelegate(this, ["next"])
30597 this.last = this.addButton({
30598 tooltip: this.lastText,
30599 cls: "x-btn-icon x-grid-page-last",
30601 handler: this.onClick.createDelegate(this, ["last"])
30603 //this.addSeparator();
30604 this.loading = this.addButton({
30605 tooltip: this.refreshText,
30606 cls: "x-btn-icon x-grid-loading",
30607 handler: this.onClick.createDelegate(this, ["refresh"])
30610 if(this.displayInfo){
30611 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30616 updateInfo : function(){
30617 if(this.displayEl){
30618 var count = this.ds.getCount();
30619 var msg = count == 0 ?
30623 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30625 this.displayEl.update(msg);
30630 onLoad : function(ds, r, o){
30631 this.cursor = o.params ? o.params.start : 0;
30632 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30634 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30635 this.field.dom.value = ap;
30636 this.first.setDisabled(ap == 1);
30637 this.prev.setDisabled(ap == 1);
30638 this.next.setDisabled(ap == ps);
30639 this.last.setDisabled(ap == ps);
30640 this.loading.enable();
30645 getPageData : function(){
30646 var total = this.ds.getTotalCount();
30649 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30650 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30655 onLoadError : function(){
30656 this.loading.enable();
30660 onPagingKeydown : function(e){
30661 var k = e.getKey();
30662 var d = this.getPageData();
30664 var v = this.field.dom.value, pageNum;
30665 if(!v || isNaN(pageNum = parseInt(v, 10))){
30666 this.field.dom.value = d.activePage;
30669 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30670 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30673 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))
30675 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30676 this.field.dom.value = pageNum;
30677 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30680 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30682 var v = this.field.dom.value, pageNum;
30683 var increment = (e.shiftKey) ? 10 : 1;
30684 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30687 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30688 this.field.dom.value = d.activePage;
30691 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30693 this.field.dom.value = parseInt(v, 10) + increment;
30694 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30695 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30702 beforeLoad : function(){
30704 this.loading.disable();
30709 onClick : function(which){
30713 ds.load({params:{start: 0, limit: this.pageSize}});
30716 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30719 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30722 var total = ds.getTotalCount();
30723 var extra = total % this.pageSize;
30724 var lastStart = extra ? (total - extra) : total-this.pageSize;
30725 ds.load({params:{start: lastStart, limit: this.pageSize}});
30728 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30734 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30735 * @param {Roo.data.Store} store The data store to unbind
30737 unbind : function(ds){
30738 ds.un("beforeload", this.beforeLoad, this);
30739 ds.un("load", this.onLoad, this);
30740 ds.un("loadexception", this.onLoadError, this);
30741 ds.un("remove", this.updateInfo, this);
30742 ds.un("add", this.updateInfo, this);
30743 this.ds = undefined;
30747 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30748 * @param {Roo.data.Store} store The data store to bind
30750 bind : function(ds){
30751 ds.on("beforeload", this.beforeLoad, this);
30752 ds.on("load", this.onLoad, this);
30753 ds.on("loadexception", this.onLoadError, this);
30754 ds.on("remove", this.updateInfo, this);
30755 ds.on("add", this.updateInfo, this);
30760 * Ext JS Library 1.1.1
30761 * Copyright(c) 2006-2007, Ext JS, LLC.
30763 * Originally Released Under LGPL - original licence link has changed is not relivant.
30766 * <script type="text/javascript">
30770 * @class Roo.Resizable
30771 * @extends Roo.util.Observable
30772 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30773 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30774 * 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
30775 * the element will be wrapped for you automatically.</p>
30776 * <p>Here is the list of valid resize handles:</p>
30779 ------ -------------------
30788 'hd' horizontal drag
30791 * <p>Here's an example showing the creation of a typical Resizable:</p>
30793 var resizer = new Roo.Resizable("element-id", {
30801 resizer.on("resize", myHandler);
30803 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30804 * resizer.east.setDisplayed(false);</p>
30805 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30806 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30807 * resize operation's new size (defaults to [0, 0])
30808 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30809 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30810 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30811 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30812 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30813 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30814 * @cfg {Number} width The width of the element in pixels (defaults to null)
30815 * @cfg {Number} height The height of the element in pixels (defaults to null)
30816 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30817 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30818 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30819 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30820 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30821 * in favor of the handles config option (defaults to false)
30822 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30823 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30824 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30825 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30826 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30827 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30828 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30829 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30830 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30831 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30832 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30834 * Create a new resizable component
30835 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30836 * @param {Object} config configuration options
30838 Roo.Resizable = function(el, config)
30840 this.el = Roo.get(el);
30842 if(config && config.wrap){
30843 config.resizeChild = this.el;
30844 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30845 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30846 this.el.setStyle("overflow", "hidden");
30847 this.el.setPositioning(config.resizeChild.getPositioning());
30848 config.resizeChild.clearPositioning();
30849 if(!config.width || !config.height){
30850 var csize = config.resizeChild.getSize();
30851 this.el.setSize(csize.width, csize.height);
30853 if(config.pinned && !config.adjustments){
30854 config.adjustments = "auto";
30858 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30859 this.proxy.unselectable();
30860 this.proxy.enableDisplayMode('block');
30862 Roo.apply(this, config);
30865 this.disableTrackOver = true;
30866 this.el.addClass("x-resizable-pinned");
30868 // if the element isn't positioned, make it relative
30869 var position = this.el.getStyle("position");
30870 if(position != "absolute" && position != "fixed"){
30871 this.el.setStyle("position", "relative");
30873 if(!this.handles){ // no handles passed, must be legacy style
30874 this.handles = 's,e,se';
30875 if(this.multiDirectional){
30876 this.handles += ',n,w';
30879 if(this.handles == "all"){
30880 this.handles = "n s e w ne nw se sw";
30882 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30883 var ps = Roo.Resizable.positions;
30884 for(var i = 0, len = hs.length; i < len; i++){
30885 if(hs[i] && ps[hs[i]]){
30886 var pos = ps[hs[i]];
30887 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30891 this.corner = this.southeast;
30893 // updateBox = the box can move..
30894 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30895 this.updateBox = true;
30898 this.activeHandle = null;
30900 if(this.resizeChild){
30901 if(typeof this.resizeChild == "boolean"){
30902 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30904 this.resizeChild = Roo.get(this.resizeChild, true);
30908 if(this.adjustments == "auto"){
30909 var rc = this.resizeChild;
30910 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30911 if(rc && (hw || hn)){
30912 rc.position("relative");
30913 rc.setLeft(hw ? hw.el.getWidth() : 0);
30914 rc.setTop(hn ? hn.el.getHeight() : 0);
30916 this.adjustments = [
30917 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30918 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30922 if(this.draggable){
30923 this.dd = this.dynamic ?
30924 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30925 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30931 * @event beforeresize
30932 * Fired before resize is allowed. Set enabled to false to cancel resize.
30933 * @param {Roo.Resizable} this
30934 * @param {Roo.EventObject} e The mousedown event
30936 "beforeresize" : true,
30939 * Fired a resizing.
30940 * @param {Roo.Resizable} this
30941 * @param {Number} x The new x position
30942 * @param {Number} y The new y position
30943 * @param {Number} w The new w width
30944 * @param {Number} h The new h hight
30945 * @param {Roo.EventObject} e The mouseup event
30950 * Fired after a resize.
30951 * @param {Roo.Resizable} this
30952 * @param {Number} width The new width
30953 * @param {Number} height The new height
30954 * @param {Roo.EventObject} e The mouseup event
30959 if(this.width !== null && this.height !== null){
30960 this.resizeTo(this.width, this.height);
30962 this.updateChildSize();
30965 this.el.dom.style.zoom = 1;
30967 Roo.Resizable.superclass.constructor.call(this);
30970 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30971 resizeChild : false,
30972 adjustments : [0, 0],
30982 multiDirectional : false,
30983 disableTrackOver : false,
30984 easing : 'easeOutStrong',
30985 widthIncrement : 0,
30986 heightIncrement : 0,
30990 preserveRatio : false,
30991 transparent: false,
30997 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30999 constrainTo: undefined,
31001 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31003 resizeRegion: undefined,
31007 * Perform a manual resize
31008 * @param {Number} width
31009 * @param {Number} height
31011 resizeTo : function(width, height){
31012 this.el.setSize(width, height);
31013 this.updateChildSize();
31014 this.fireEvent("resize", this, width, height, null);
31018 startSizing : function(e, handle){
31019 this.fireEvent("beforeresize", this, e);
31020 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31023 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31024 this.overlay.unselectable();
31025 this.overlay.enableDisplayMode("block");
31026 this.overlay.on("mousemove", this.onMouseMove, this);
31027 this.overlay.on("mouseup", this.onMouseUp, this);
31029 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31031 this.resizing = true;
31032 this.startBox = this.el.getBox();
31033 this.startPoint = e.getXY();
31034 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31035 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31037 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31038 this.overlay.show();
31040 if(this.constrainTo) {
31041 var ct = Roo.get(this.constrainTo);
31042 this.resizeRegion = ct.getRegion().adjust(
31043 ct.getFrameWidth('t'),
31044 ct.getFrameWidth('l'),
31045 -ct.getFrameWidth('b'),
31046 -ct.getFrameWidth('r')
31050 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31052 this.proxy.setBox(this.startBox);
31054 this.proxy.setStyle('visibility', 'visible');
31060 onMouseDown : function(handle, e){
31063 this.activeHandle = handle;
31064 this.startSizing(e, handle);
31069 onMouseUp : function(e){
31070 var size = this.resizeElement();
31071 this.resizing = false;
31073 this.overlay.hide();
31075 this.fireEvent("resize", this, size.width, size.height, e);
31079 updateChildSize : function(){
31081 if(this.resizeChild){
31083 var child = this.resizeChild;
31084 var adj = this.adjustments;
31085 if(el.dom.offsetWidth){
31086 var b = el.getSize(true);
31087 child.setSize(b.width+adj[0], b.height+adj[1]);
31089 // Second call here for IE
31090 // The first call enables instant resizing and
31091 // the second call corrects scroll bars if they
31094 setTimeout(function(){
31095 if(el.dom.offsetWidth){
31096 var b = el.getSize(true);
31097 child.setSize(b.width+adj[0], b.height+adj[1]);
31105 snap : function(value, inc, min){
31106 if(!inc || !value) {
31109 var newValue = value;
31110 var m = value % inc;
31113 newValue = value + (inc-m);
31115 newValue = value - m;
31118 return Math.max(min, newValue);
31122 resizeElement : function(){
31123 var box = this.proxy.getBox();
31124 if(this.updateBox){
31125 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31127 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31129 this.updateChildSize();
31137 constrain : function(v, diff, m, mx){
31140 }else if(v - diff > mx){
31147 onMouseMove : function(e){
31150 try{// try catch so if something goes wrong the user doesn't get hung
31152 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31156 //var curXY = this.startPoint;
31157 var curSize = this.curSize || this.startBox;
31158 var x = this.startBox.x, y = this.startBox.y;
31159 var ox = x, oy = y;
31160 var w = curSize.width, h = curSize.height;
31161 var ow = w, oh = h;
31162 var mw = this.minWidth, mh = this.minHeight;
31163 var mxw = this.maxWidth, mxh = this.maxHeight;
31164 var wi = this.widthIncrement;
31165 var hi = this.heightIncrement;
31167 var eventXY = e.getXY();
31168 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31169 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31171 var pos = this.activeHandle.position;
31176 w = Math.min(Math.max(mw, w), mxw);
31181 h = Math.min(Math.max(mh, h), mxh);
31186 w = Math.min(Math.max(mw, w), mxw);
31187 h = Math.min(Math.max(mh, h), mxh);
31190 diffY = this.constrain(h, diffY, mh, mxh);
31197 var adiffX = Math.abs(diffX);
31198 var sub = (adiffX % wi); // how much
31199 if (sub > (wi/2)) { // far enough to snap
31200 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31202 // remove difference..
31203 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31207 x = Math.max(this.minX, x);
31210 diffX = this.constrain(w, diffX, mw, mxw);
31216 w = Math.min(Math.max(mw, w), mxw);
31217 diffY = this.constrain(h, diffY, mh, mxh);
31222 diffX = this.constrain(w, diffX, mw, mxw);
31223 diffY = this.constrain(h, diffY, mh, mxh);
31230 diffX = this.constrain(w, diffX, mw, mxw);
31232 h = Math.min(Math.max(mh, h), mxh);
31238 var sw = this.snap(w, wi, mw);
31239 var sh = this.snap(h, hi, mh);
31240 if(sw != w || sh != h){
31263 if(this.preserveRatio){
31268 h = Math.min(Math.max(mh, h), mxh);
31273 w = Math.min(Math.max(mw, w), mxw);
31278 w = Math.min(Math.max(mw, w), mxw);
31284 w = Math.min(Math.max(mw, w), mxw);
31290 h = Math.min(Math.max(mh, h), mxh);
31298 h = Math.min(Math.max(mh, h), mxh);
31308 h = Math.min(Math.max(mh, h), mxh);
31316 if (pos == 'hdrag') {
31319 this.proxy.setBounds(x, y, w, h);
31321 this.resizeElement();
31325 this.fireEvent("resizing", this, x, y, w, h, e);
31329 handleOver : function(){
31331 this.el.addClass("x-resizable-over");
31336 handleOut : function(){
31337 if(!this.resizing){
31338 this.el.removeClass("x-resizable-over");
31343 * Returns the element this component is bound to.
31344 * @return {Roo.Element}
31346 getEl : function(){
31351 * Returns the resizeChild element (or null).
31352 * @return {Roo.Element}
31354 getResizeChild : function(){
31355 return this.resizeChild;
31357 groupHandler : function()
31362 * Destroys this resizable. If the element was wrapped and
31363 * removeEl is not true then the element remains.
31364 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31366 destroy : function(removeEl){
31367 this.proxy.remove();
31369 this.overlay.removeAllListeners();
31370 this.overlay.remove();
31372 var ps = Roo.Resizable.positions;
31374 if(typeof ps[k] != "function" && this[ps[k]]){
31375 var h = this[ps[k]];
31376 h.el.removeAllListeners();
31381 this.el.update("");
31388 // hash to map config positions to true positions
31389 Roo.Resizable.positions = {
31390 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31395 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31397 // only initialize the template if resizable is used
31398 var tpl = Roo.DomHelper.createTemplate(
31399 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31402 Roo.Resizable.Handle.prototype.tpl = tpl;
31404 this.position = pos;
31406 // show north drag fro topdra
31407 var handlepos = pos == 'hdrag' ? 'north' : pos;
31409 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31410 if (pos == 'hdrag') {
31411 this.el.setStyle('cursor', 'pointer');
31413 this.el.unselectable();
31415 this.el.setOpacity(0);
31417 this.el.on("mousedown", this.onMouseDown, this);
31418 if(!disableTrackOver){
31419 this.el.on("mouseover", this.onMouseOver, this);
31420 this.el.on("mouseout", this.onMouseOut, this);
31425 Roo.Resizable.Handle.prototype = {
31426 afterResize : function(rz){
31431 onMouseDown : function(e){
31432 this.rz.onMouseDown(this, e);
31435 onMouseOver : function(e){
31436 this.rz.handleOver(this, e);
31439 onMouseOut : function(e){
31440 this.rz.handleOut(this, e);
31444 * Ext JS Library 1.1.1
31445 * Copyright(c) 2006-2007, Ext JS, LLC.
31447 * Originally Released Under LGPL - original licence link has changed is not relivant.
31450 * <script type="text/javascript">
31454 * @class Roo.Editor
31455 * @extends Roo.Component
31456 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31458 * Create a new Editor
31459 * @param {Roo.form.Field} field The Field object (or descendant)
31460 * @param {Object} config The config object
31462 Roo.Editor = function(field, config){
31463 Roo.Editor.superclass.constructor.call(this, config);
31464 this.field = field;
31467 * @event beforestartedit
31468 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31469 * false from the handler of this event.
31470 * @param {Editor} this
31471 * @param {Roo.Element} boundEl The underlying element bound to this editor
31472 * @param {Mixed} value The field value being set
31474 "beforestartedit" : true,
31477 * Fires when this editor is displayed
31478 * @param {Roo.Element} boundEl The underlying element bound to this editor
31479 * @param {Mixed} value The starting field value
31481 "startedit" : true,
31483 * @event beforecomplete
31484 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31485 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31486 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31487 * event will not fire since no edit actually occurred.
31488 * @param {Editor} this
31489 * @param {Mixed} value The current field value
31490 * @param {Mixed} startValue The original field value
31492 "beforecomplete" : true,
31495 * Fires after editing is complete and any changed value has been written to the underlying field.
31496 * @param {Editor} this
31497 * @param {Mixed} value The current field value
31498 * @param {Mixed} startValue The original field value
31502 * @event specialkey
31503 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31504 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31505 * @param {Roo.form.Field} this
31506 * @param {Roo.EventObject} e The event object
31508 "specialkey" : true
31512 Roo.extend(Roo.Editor, Roo.Component, {
31514 * @cfg {Boolean/String} autosize
31515 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31516 * or "height" to adopt the height only (defaults to false)
31519 * @cfg {Boolean} revertInvalid
31520 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31521 * validation fails (defaults to true)
31524 * @cfg {Boolean} ignoreNoChange
31525 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31526 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31527 * will never be ignored.
31530 * @cfg {Boolean} hideEl
31531 * False to keep the bound element visible while the editor is displayed (defaults to true)
31534 * @cfg {Mixed} value
31535 * The data value of the underlying field (defaults to "")
31539 * @cfg {String} alignment
31540 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31544 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31545 * for bottom-right shadow (defaults to "frame")
31549 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31553 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31555 completeOnEnter : false,
31557 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31559 cancelOnEsc : false,
31561 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31566 onRender : function(ct, position){
31567 this.el = new Roo.Layer({
31568 shadow: this.shadow,
31574 constrain: this.constrain
31576 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31577 if(this.field.msgTarget != 'title'){
31578 this.field.msgTarget = 'qtip';
31580 this.field.render(this.el);
31582 this.field.el.dom.setAttribute('autocomplete', 'off');
31584 this.field.on("specialkey", this.onSpecialKey, this);
31585 if(this.swallowKeys){
31586 this.field.el.swallowEvent(['keydown','keypress']);
31589 this.field.on("blur", this.onBlur, this);
31590 if(this.field.grow){
31591 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31595 onSpecialKey : function(field, e)
31597 //Roo.log('editor onSpecialKey');
31598 if(this.completeOnEnter && e.getKey() == e.ENTER){
31600 this.completeEdit();
31603 // do not fire special key otherwise it might hide close the editor...
31604 if(e.getKey() == e.ENTER){
31607 if(this.cancelOnEsc && e.getKey() == e.ESC){
31611 this.fireEvent('specialkey', field, e);
31616 * Starts the editing process and shows the editor.
31617 * @param {String/HTMLElement/Element} el The element to edit
31618 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31619 * to the innerHTML of el.
31621 startEdit : function(el, value){
31623 this.completeEdit();
31625 this.boundEl = Roo.get(el);
31626 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31627 if(!this.rendered){
31628 this.render(this.parentEl || document.body);
31630 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31633 this.startValue = v;
31634 this.field.setValue(v);
31636 var sz = this.boundEl.getSize();
31637 switch(this.autoSize){
31639 this.setSize(sz.width, "");
31642 this.setSize("", sz.height);
31645 this.setSize(sz.width, sz.height);
31648 this.el.alignTo(this.boundEl, this.alignment);
31649 this.editing = true;
31651 Roo.QuickTips.disable();
31657 * Sets the height and width of this editor.
31658 * @param {Number} width The new width
31659 * @param {Number} height The new height
31661 setSize : function(w, h){
31662 this.field.setSize(w, h);
31669 * Realigns the editor to the bound field based on the current alignment config value.
31671 realign : function(){
31672 this.el.alignTo(this.boundEl, this.alignment);
31676 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31677 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31679 completeEdit : function(remainVisible){
31683 var v = this.getValue();
31684 if(this.revertInvalid !== false && !this.field.isValid()){
31685 v = this.startValue;
31686 this.cancelEdit(true);
31688 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31689 this.editing = false;
31693 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31694 this.editing = false;
31695 if(this.updateEl && this.boundEl){
31696 this.boundEl.update(v);
31698 if(remainVisible !== true){
31701 this.fireEvent("complete", this, v, this.startValue);
31706 onShow : function(){
31708 if(this.hideEl !== false){
31709 this.boundEl.hide();
31712 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31713 this.fixIEFocus = true;
31714 this.deferredFocus.defer(50, this);
31716 this.field.focus();
31718 this.fireEvent("startedit", this.boundEl, this.startValue);
31721 deferredFocus : function(){
31723 this.field.focus();
31728 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31729 * reverted to the original starting value.
31730 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31731 * cancel (defaults to false)
31733 cancelEdit : function(remainVisible){
31735 this.setValue(this.startValue);
31736 if(remainVisible !== true){
31743 onBlur : function(){
31744 if(this.allowBlur !== true && this.editing){
31745 this.completeEdit();
31750 onHide : function(){
31752 this.completeEdit();
31756 if(this.field.collapse){
31757 this.field.collapse();
31760 if(this.hideEl !== false){
31761 this.boundEl.show();
31764 Roo.QuickTips.enable();
31769 * Sets the data value of the editor
31770 * @param {Mixed} value Any valid value supported by the underlying field
31772 setValue : function(v){
31773 this.field.setValue(v);
31777 * Gets the data value of the editor
31778 * @return {Mixed} The data value
31780 getValue : function(){
31781 return this.field.getValue();
31785 * Ext JS Library 1.1.1
31786 * Copyright(c) 2006-2007, Ext JS, LLC.
31788 * Originally Released Under LGPL - original licence link has changed is not relivant.
31791 * <script type="text/javascript">
31795 * @class Roo.BasicDialog
31796 * @extends Roo.util.Observable
31797 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31799 var dlg = new Roo.BasicDialog("my-dlg", {
31808 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31809 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31810 dlg.addButton('Cancel', dlg.hide, dlg);
31813 <b>A Dialog should always be a direct child of the body element.</b>
31814 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31815 * @cfg {String} title Default text to display in the title bar (defaults to null)
31816 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31817 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31818 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31819 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31820 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31821 * (defaults to null with no animation)
31822 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31823 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31824 * property for valid values (defaults to 'all')
31825 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31826 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31827 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31828 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31829 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31830 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31831 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31832 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31833 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31834 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31835 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31836 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31837 * draggable = true (defaults to false)
31838 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31839 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31840 * shadow (defaults to false)
31841 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31842 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31843 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31844 * @cfg {Array} buttons Array of buttons
31845 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31847 * Create a new BasicDialog.
31848 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31849 * @param {Object} config Configuration options
31851 Roo.BasicDialog = function(el, config){
31852 this.el = Roo.get(el);
31853 var dh = Roo.DomHelper;
31854 if(!this.el && config && config.autoCreate){
31855 if(typeof config.autoCreate == "object"){
31856 if(!config.autoCreate.id){
31857 config.autoCreate.id = el;
31859 this.el = dh.append(document.body,
31860 config.autoCreate, true);
31862 this.el = dh.append(document.body,
31863 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31867 el.setDisplayed(true);
31868 el.hide = this.hideAction;
31870 el.addClass("x-dlg");
31872 Roo.apply(this, config);
31874 this.proxy = el.createProxy("x-dlg-proxy");
31875 this.proxy.hide = this.hideAction;
31876 this.proxy.setOpacity(.5);
31880 el.setWidth(config.width);
31883 el.setHeight(config.height);
31885 this.size = el.getSize();
31886 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31887 this.xy = [config.x,config.y];
31889 this.xy = el.getCenterXY(true);
31891 /** The header element @type Roo.Element */
31892 this.header = el.child("> .x-dlg-hd");
31893 /** The body element @type Roo.Element */
31894 this.body = el.child("> .x-dlg-bd");
31895 /** The footer element @type Roo.Element */
31896 this.footer = el.child("> .x-dlg-ft");
31899 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31902 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31905 this.header.unselectable();
31907 this.header.update(this.title);
31909 // this element allows the dialog to be focused for keyboard event
31910 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31911 this.focusEl.swallowEvent("click", true);
31913 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31915 // wrap the body and footer for special rendering
31916 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31918 this.bwrap.dom.appendChild(this.footer.dom);
31921 this.bg = this.el.createChild({
31922 tag: "div", cls:"x-dlg-bg",
31923 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31925 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31928 if(this.autoScroll !== false && !this.autoTabs){
31929 this.body.setStyle("overflow", "auto");
31932 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31934 if(this.closable !== false){
31935 this.el.addClass("x-dlg-closable");
31936 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31937 this.close.on("click", this.closeClick, this);
31938 this.close.addClassOnOver("x-dlg-close-over");
31940 if(this.collapsible !== false){
31941 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31942 this.collapseBtn.on("click", this.collapseClick, this);
31943 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31944 this.header.on("dblclick", this.collapseClick, this);
31946 if(this.resizable !== false){
31947 this.el.addClass("x-dlg-resizable");
31948 this.resizer = new Roo.Resizable(el, {
31949 minWidth: this.minWidth || 80,
31950 minHeight:this.minHeight || 80,
31951 handles: this.resizeHandles || "all",
31954 this.resizer.on("beforeresize", this.beforeResize, this);
31955 this.resizer.on("resize", this.onResize, this);
31957 if(this.draggable !== false){
31958 el.addClass("x-dlg-draggable");
31959 if (!this.proxyDrag) {
31960 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31963 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31965 dd.setHandleElId(this.header.id);
31966 dd.endDrag = this.endMove.createDelegate(this);
31967 dd.startDrag = this.startMove.createDelegate(this);
31968 dd.onDrag = this.onDrag.createDelegate(this);
31973 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31974 this.mask.enableDisplayMode("block");
31976 this.el.addClass("x-dlg-modal");
31979 this.shadow = new Roo.Shadow({
31980 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31981 offset : this.shadowOffset
31984 this.shadowOffset = 0;
31986 if(Roo.useShims && this.shim !== false){
31987 this.shim = this.el.createShim();
31988 this.shim.hide = this.hideAction;
31996 if (this.buttons) {
31997 var bts= this.buttons;
31999 Roo.each(bts, function(b) {
32008 * Fires when a key is pressed
32009 * @param {Roo.BasicDialog} this
32010 * @param {Roo.EventObject} e
32015 * Fires when this dialog is moved by the user.
32016 * @param {Roo.BasicDialog} this
32017 * @param {Number} x The new page X
32018 * @param {Number} y The new page Y
32023 * Fires when this dialog is resized by the user.
32024 * @param {Roo.BasicDialog} this
32025 * @param {Number} width The new width
32026 * @param {Number} height The new height
32030 * @event beforehide
32031 * Fires before this dialog is hidden.
32032 * @param {Roo.BasicDialog} this
32034 "beforehide" : true,
32037 * Fires when this dialog is hidden.
32038 * @param {Roo.BasicDialog} this
32042 * @event beforeshow
32043 * Fires before this dialog is shown.
32044 * @param {Roo.BasicDialog} this
32046 "beforeshow" : true,
32049 * Fires when this dialog is shown.
32050 * @param {Roo.BasicDialog} this
32054 el.on("keydown", this.onKeyDown, this);
32055 el.on("mousedown", this.toFront, this);
32056 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32058 Roo.DialogManager.register(this);
32059 Roo.BasicDialog.superclass.constructor.call(this);
32062 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32063 shadowOffset: Roo.isIE ? 6 : 5,
32066 minButtonWidth: 75,
32067 defaultButton: null,
32068 buttonAlign: "right",
32073 * Sets the dialog title text
32074 * @param {String} text The title text to display
32075 * @return {Roo.BasicDialog} this
32077 setTitle : function(text){
32078 this.header.update(text);
32083 closeClick : function(){
32088 collapseClick : function(){
32089 this[this.collapsed ? "expand" : "collapse"]();
32093 * Collapses the dialog to its minimized state (only the title bar is visible).
32094 * Equivalent to the user clicking the collapse dialog button.
32096 collapse : function(){
32097 if(!this.collapsed){
32098 this.collapsed = true;
32099 this.el.addClass("x-dlg-collapsed");
32100 this.restoreHeight = this.el.getHeight();
32101 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32106 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32107 * clicking the expand dialog button.
32109 expand : function(){
32110 if(this.collapsed){
32111 this.collapsed = false;
32112 this.el.removeClass("x-dlg-collapsed");
32113 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32118 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32119 * @return {Roo.TabPanel} The tabs component
32121 initTabs : function(){
32122 var tabs = this.getTabs();
32123 while(tabs.getTab(0)){
32126 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32128 tabs.addTab(Roo.id(dom), dom.title);
32136 beforeResize : function(){
32137 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32141 onResize : function(){
32142 this.refreshSize();
32143 this.syncBodyHeight();
32144 this.adjustAssets();
32146 this.fireEvent("resize", this, this.size.width, this.size.height);
32150 onKeyDown : function(e){
32151 if(this.isVisible()){
32152 this.fireEvent("keydown", this, e);
32157 * Resizes the dialog.
32158 * @param {Number} width
32159 * @param {Number} height
32160 * @return {Roo.BasicDialog} this
32162 resizeTo : function(width, height){
32163 this.el.setSize(width, height);
32164 this.size = {width: width, height: height};
32165 this.syncBodyHeight();
32166 if(this.fixedcenter){
32169 if(this.isVisible()){
32170 this.constrainXY();
32171 this.adjustAssets();
32173 this.fireEvent("resize", this, width, height);
32179 * Resizes the dialog to fit the specified content size.
32180 * @param {Number} width
32181 * @param {Number} height
32182 * @return {Roo.BasicDialog} this
32184 setContentSize : function(w, h){
32185 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32186 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32187 //if(!this.el.isBorderBox()){
32188 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32189 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32192 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32193 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32195 this.resizeTo(w, h);
32200 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32201 * executed in response to a particular key being pressed while the dialog is active.
32202 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32203 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32204 * @param {Function} fn The function to call
32205 * @param {Object} scope (optional) The scope of the function
32206 * @return {Roo.BasicDialog} this
32208 addKeyListener : function(key, fn, scope){
32209 var keyCode, shift, ctrl, alt;
32210 if(typeof key == "object" && !(key instanceof Array)){
32211 keyCode = key["key"];
32212 shift = key["shift"];
32213 ctrl = key["ctrl"];
32218 var handler = function(dlg, e){
32219 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32220 var k = e.getKey();
32221 if(keyCode instanceof Array){
32222 for(var i = 0, len = keyCode.length; i < len; i++){
32223 if(keyCode[i] == k){
32224 fn.call(scope || window, dlg, k, e);
32230 fn.call(scope || window, dlg, k, e);
32235 this.on("keydown", handler);
32240 * Returns the TabPanel component (creates it if it doesn't exist).
32241 * Note: If you wish to simply check for the existence of tabs without creating them,
32242 * check for a null 'tabs' property.
32243 * @return {Roo.TabPanel} The tabs component
32245 getTabs : function(){
32247 this.el.addClass("x-dlg-auto-tabs");
32248 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32249 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32255 * Adds a button to the footer section of the dialog.
32256 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32257 * object or a valid Roo.DomHelper element config
32258 * @param {Function} handler The function called when the button is clicked
32259 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32260 * @return {Roo.Button} The new button
32262 addButton : function(config, handler, scope){
32263 var dh = Roo.DomHelper;
32265 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32267 if(!this.btnContainer){
32268 var tb = this.footer.createChild({
32270 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32271 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32273 this.btnContainer = tb.firstChild.firstChild.firstChild;
32278 minWidth: this.minButtonWidth,
32281 if(typeof config == "string"){
32282 bconfig.text = config;
32285 bconfig.dhconfig = config;
32287 Roo.apply(bconfig, config);
32291 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32292 bconfig.position = Math.max(0, bconfig.position);
32293 fc = this.btnContainer.childNodes[bconfig.position];
32296 var btn = new Roo.Button(
32298 this.btnContainer.insertBefore(document.createElement("td"),fc)
32299 : this.btnContainer.appendChild(document.createElement("td")),
32300 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32303 this.syncBodyHeight();
32306 * Array of all the buttons that have been added to this dialog via addButton
32311 this.buttons.push(btn);
32316 * Sets the default button to be focused when the dialog is displayed.
32317 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32318 * @return {Roo.BasicDialog} this
32320 setDefaultButton : function(btn){
32321 this.defaultButton = btn;
32326 getHeaderFooterHeight : function(safe){
32329 height += this.header.getHeight();
32332 var fm = this.footer.getMargins();
32333 height += (this.footer.getHeight()+fm.top+fm.bottom);
32335 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32336 height += this.centerBg.getPadding("tb");
32341 syncBodyHeight : function()
32343 var bd = this.body, // the text
32344 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32346 var height = this.size.height - this.getHeaderFooterHeight(false);
32347 bd.setHeight(height-bd.getMargins("tb"));
32348 var hh = this.header.getHeight();
32349 var h = this.size.height-hh;
32352 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32353 bw.setHeight(h-cb.getPadding("tb"));
32355 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32356 bd.setWidth(bw.getWidth(true));
32358 this.tabs.syncHeight();
32360 this.tabs.el.repaint();
32366 * Restores the previous state of the dialog if Roo.state is configured.
32367 * @return {Roo.BasicDialog} this
32369 restoreState : function(){
32370 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32371 if(box && box.width){
32372 this.xy = [box.x, box.y];
32373 this.resizeTo(box.width, box.height);
32379 beforeShow : function(){
32381 if(this.fixedcenter){
32382 this.xy = this.el.getCenterXY(true);
32385 Roo.get(document.body).addClass("x-body-masked");
32386 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32389 this.constrainXY();
32393 animShow : function(){
32394 var b = Roo.get(this.animateTarget).getBox();
32395 this.proxy.setSize(b.width, b.height);
32396 this.proxy.setLocation(b.x, b.y);
32398 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32399 true, .35, this.showEl.createDelegate(this));
32403 * Shows the dialog.
32404 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32405 * @return {Roo.BasicDialog} this
32407 show : function(animateTarget){
32408 if (this.fireEvent("beforeshow", this) === false){
32411 if(this.syncHeightBeforeShow){
32412 this.syncBodyHeight();
32413 }else if(this.firstShow){
32414 this.firstShow = false;
32415 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32417 this.animateTarget = animateTarget || this.animateTarget;
32418 if(!this.el.isVisible()){
32420 if(this.animateTarget && Roo.get(this.animateTarget)){
32430 showEl : function(){
32432 this.el.setXY(this.xy);
32434 this.adjustAssets(true);
32437 // IE peekaboo bug - fix found by Dave Fenwick
32441 this.fireEvent("show", this);
32445 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32446 * dialog itself will receive focus.
32448 focus : function(){
32449 if(this.defaultButton){
32450 this.defaultButton.focus();
32452 this.focusEl.focus();
32457 constrainXY : function(){
32458 if(this.constraintoviewport !== false){
32459 if(!this.viewSize){
32460 if(this.container){
32461 var s = this.container.getSize();
32462 this.viewSize = [s.width, s.height];
32464 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32467 var s = Roo.get(this.container||document).getScroll();
32469 var x = this.xy[0], y = this.xy[1];
32470 var w = this.size.width, h = this.size.height;
32471 var vw = this.viewSize[0], vh = this.viewSize[1];
32472 // only move it if it needs it
32474 // first validate right/bottom
32475 if(x + w > vw+s.left){
32479 if(y + h > vh+s.top){
32483 // then make sure top/left isn't negative
32495 if(this.isVisible()){
32496 this.el.setLocation(x, y);
32497 this.adjustAssets();
32504 onDrag : function(){
32505 if(!this.proxyDrag){
32506 this.xy = this.el.getXY();
32507 this.adjustAssets();
32512 adjustAssets : function(doShow){
32513 var x = this.xy[0], y = this.xy[1];
32514 var w = this.size.width, h = this.size.height;
32515 if(doShow === true){
32517 this.shadow.show(this.el);
32523 if(this.shadow && this.shadow.isVisible()){
32524 this.shadow.show(this.el);
32526 if(this.shim && this.shim.isVisible()){
32527 this.shim.setBounds(x, y, w, h);
32532 adjustViewport : function(w, h){
32534 w = Roo.lib.Dom.getViewWidth();
32535 h = Roo.lib.Dom.getViewHeight();
32538 this.viewSize = [w, h];
32539 if(this.modal && this.mask.isVisible()){
32540 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32541 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32543 if(this.isVisible()){
32544 this.constrainXY();
32549 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32550 * shadow, proxy, mask, etc.) Also removes all event listeners.
32551 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32553 destroy : function(removeEl){
32554 if(this.isVisible()){
32555 this.animateTarget = null;
32558 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32560 this.tabs.destroy(removeEl);
32573 for(var i = 0, len = this.buttons.length; i < len; i++){
32574 this.buttons[i].destroy();
32577 this.el.removeAllListeners();
32578 if(removeEl === true){
32579 this.el.update("");
32582 Roo.DialogManager.unregister(this);
32586 startMove : function(){
32587 if(this.proxyDrag){
32590 if(this.constraintoviewport !== false){
32591 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32596 endMove : function(){
32597 if(!this.proxyDrag){
32598 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32600 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32603 this.refreshSize();
32604 this.adjustAssets();
32606 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32610 * Brings this dialog to the front of any other visible dialogs
32611 * @return {Roo.BasicDialog} this
32613 toFront : function(){
32614 Roo.DialogManager.bringToFront(this);
32619 * Sends this dialog to the back (under) of any other visible dialogs
32620 * @return {Roo.BasicDialog} this
32622 toBack : function(){
32623 Roo.DialogManager.sendToBack(this);
32628 * Centers this dialog in the viewport
32629 * @return {Roo.BasicDialog} this
32631 center : function(){
32632 var xy = this.el.getCenterXY(true);
32633 this.moveTo(xy[0], xy[1]);
32638 * Moves the dialog's top-left corner to the specified point
32639 * @param {Number} x
32640 * @param {Number} y
32641 * @return {Roo.BasicDialog} this
32643 moveTo : function(x, y){
32645 if(this.isVisible()){
32646 this.el.setXY(this.xy);
32647 this.adjustAssets();
32653 * Aligns the dialog to the specified element
32654 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32655 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32656 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32657 * @return {Roo.BasicDialog} this
32659 alignTo : function(element, position, offsets){
32660 this.xy = this.el.getAlignToXY(element, position, offsets);
32661 if(this.isVisible()){
32662 this.el.setXY(this.xy);
32663 this.adjustAssets();
32669 * Anchors an element to another element and realigns it when the window is resized.
32670 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32671 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32672 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32673 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32674 * is a number, it is used as the buffer delay (defaults to 50ms).
32675 * @return {Roo.BasicDialog} this
32677 anchorTo : function(el, alignment, offsets, monitorScroll){
32678 var action = function(){
32679 this.alignTo(el, alignment, offsets);
32681 Roo.EventManager.onWindowResize(action, this);
32682 var tm = typeof monitorScroll;
32683 if(tm != 'undefined'){
32684 Roo.EventManager.on(window, 'scroll', action, this,
32685 {buffer: tm == 'number' ? monitorScroll : 50});
32692 * Returns true if the dialog is visible
32693 * @return {Boolean}
32695 isVisible : function(){
32696 return this.el.isVisible();
32700 animHide : function(callback){
32701 var b = Roo.get(this.animateTarget).getBox();
32703 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32705 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32706 this.hideEl.createDelegate(this, [callback]));
32710 * Hides the dialog.
32711 * @param {Function} callback (optional) Function to call when the dialog is hidden
32712 * @return {Roo.BasicDialog} this
32714 hide : function(callback){
32715 if (this.fireEvent("beforehide", this) === false){
32719 this.shadow.hide();
32724 // sometimes animateTarget seems to get set.. causing problems...
32725 // this just double checks..
32726 if(this.animateTarget && Roo.get(this.animateTarget)) {
32727 this.animHide(callback);
32730 this.hideEl(callback);
32736 hideEl : function(callback){
32740 Roo.get(document.body).removeClass("x-body-masked");
32742 this.fireEvent("hide", this);
32743 if(typeof callback == "function"){
32749 hideAction : function(){
32750 this.setLeft("-10000px");
32751 this.setTop("-10000px");
32752 this.setStyle("visibility", "hidden");
32756 refreshSize : function(){
32757 this.size = this.el.getSize();
32758 this.xy = this.el.getXY();
32759 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32763 // z-index is managed by the DialogManager and may be overwritten at any time
32764 setZIndex : function(index){
32766 this.mask.setStyle("z-index", index);
32769 this.shim.setStyle("z-index", ++index);
32772 this.shadow.setZIndex(++index);
32774 this.el.setStyle("z-index", ++index);
32776 this.proxy.setStyle("z-index", ++index);
32779 this.resizer.proxy.setStyle("z-index", ++index);
32782 this.lastZIndex = index;
32786 * Returns the element for this dialog
32787 * @return {Roo.Element} The underlying dialog Element
32789 getEl : function(){
32795 * @class Roo.DialogManager
32796 * Provides global access to BasicDialogs that have been created and
32797 * support for z-indexing (layering) multiple open dialogs.
32799 Roo.DialogManager = function(){
32801 var accessList = [];
32805 var sortDialogs = function(d1, d2){
32806 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32810 var orderDialogs = function(){
32811 accessList.sort(sortDialogs);
32812 var seed = Roo.DialogManager.zseed;
32813 for(var i = 0, len = accessList.length; i < len; i++){
32814 var dlg = accessList[i];
32816 dlg.setZIndex(seed + (i*10));
32823 * The starting z-index for BasicDialogs (defaults to 9000)
32824 * @type Number The z-index value
32829 register : function(dlg){
32830 list[dlg.id] = dlg;
32831 accessList.push(dlg);
32835 unregister : function(dlg){
32836 delete list[dlg.id];
32839 if(!accessList.indexOf){
32840 for( i = 0, len = accessList.length; i < len; i++){
32841 if(accessList[i] == dlg){
32842 accessList.splice(i, 1);
32847 i = accessList.indexOf(dlg);
32849 accessList.splice(i, 1);
32855 * Gets a registered dialog by id
32856 * @param {String/Object} id The id of the dialog or a dialog
32857 * @return {Roo.BasicDialog} this
32859 get : function(id){
32860 return typeof id == "object" ? id : list[id];
32864 * Brings the specified dialog to the front
32865 * @param {String/Object} dlg The id of the dialog or a dialog
32866 * @return {Roo.BasicDialog} this
32868 bringToFront : function(dlg){
32869 dlg = this.get(dlg);
32872 dlg._lastAccess = new Date().getTime();
32879 * Sends the specified dialog to the back
32880 * @param {String/Object} dlg The id of the dialog or a dialog
32881 * @return {Roo.BasicDialog} this
32883 sendToBack : function(dlg){
32884 dlg = this.get(dlg);
32885 dlg._lastAccess = -(new Date().getTime());
32891 * Hides all dialogs
32893 hideAll : function(){
32894 for(var id in list){
32895 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32904 * @class Roo.LayoutDialog
32905 * @extends Roo.BasicDialog
32906 * Dialog which provides adjustments for working with a layout in a Dialog.
32907 * Add your necessary layout config options to the dialog's config.<br>
32908 * Example usage (including a nested layout):
32911 dialog = new Roo.LayoutDialog("download-dlg", {
32920 // layout config merges with the dialog config
32922 tabPosition: "top",
32923 alwaysShowTabs: true
32926 dialog.addKeyListener(27, dialog.hide, dialog);
32927 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32928 dialog.addButton("Build It!", this.getDownload, this);
32930 // we can even add nested layouts
32931 var innerLayout = new Roo.BorderLayout("dl-inner", {
32941 innerLayout.beginUpdate();
32942 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32943 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32944 innerLayout.endUpdate(true);
32946 var layout = dialog.getLayout();
32947 layout.beginUpdate();
32948 layout.add("center", new Roo.ContentPanel("standard-panel",
32949 {title: "Download the Source", fitToFrame:true}));
32950 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32951 {title: "Build your own roo.js"}));
32952 layout.getRegion("center").showPanel(sp);
32953 layout.endUpdate();
32957 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32958 * @param {Object} config configuration options
32960 Roo.LayoutDialog = function(el, cfg){
32963 if (typeof(cfg) == 'undefined') {
32964 config = Roo.apply({}, el);
32965 // not sure why we use documentElement here.. - it should always be body.
32966 // IE7 borks horribly if we use documentElement.
32967 // webkit also does not like documentElement - it creates a body element...
32968 el = Roo.get( document.body || document.documentElement ).createChild();
32969 //config.autoCreate = true;
32973 config.autoTabs = false;
32974 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32975 this.body.setStyle({overflow:"hidden", position:"relative"});
32976 this.layout = new Roo.BorderLayout(this.body.dom, config);
32977 this.layout.monitorWindowResize = false;
32978 this.el.addClass("x-dlg-auto-layout");
32979 // fix case when center region overwrites center function
32980 this.center = Roo.BasicDialog.prototype.center;
32981 this.on("show", this.layout.layout, this.layout, true);
32982 if (config.items) {
32983 var xitems = config.items;
32984 delete config.items;
32985 Roo.each(xitems, this.addxtype, this);
32990 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32992 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32995 endUpdate : function(){
32996 this.layout.endUpdate();
33000 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33003 beginUpdate : function(){
33004 this.layout.beginUpdate();
33008 * Get the BorderLayout for this dialog
33009 * @return {Roo.BorderLayout}
33011 getLayout : function(){
33012 return this.layout;
33015 showEl : function(){
33016 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33018 this.layout.layout();
33023 // Use the syncHeightBeforeShow config option to control this automatically
33024 syncBodyHeight : function(){
33025 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33026 if(this.layout){this.layout.layout();}
33030 * Add an xtype element (actually adds to the layout.)
33031 * @return {Object} xdata xtype object data.
33034 addxtype : function(c) {
33035 return this.layout.addxtype(c);
33039 * Ext JS Library 1.1.1
33040 * Copyright(c) 2006-2007, Ext JS, LLC.
33042 * Originally Released Under LGPL - original licence link has changed is not relivant.
33045 * <script type="text/javascript">
33049 * @class Roo.MessageBox
33050 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33054 Roo.Msg.alert('Status', 'Changes saved successfully.');
33056 // Prompt for user data:
33057 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33059 // process text value...
33063 // Show a dialog using config options:
33065 title:'Save Changes?',
33066 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33067 buttons: Roo.Msg.YESNOCANCEL,
33074 Roo.MessageBox = function(){
33075 var dlg, opt, mask, waitTimer;
33076 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33077 var buttons, activeTextEl, bwidth;
33080 var handleButton = function(button){
33082 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33086 var handleHide = function(){
33087 if(opt && opt.cls){
33088 dlg.el.removeClass(opt.cls);
33091 Roo.TaskMgr.stop(waitTimer);
33097 var updateButtons = function(b){
33100 buttons["ok"].hide();
33101 buttons["cancel"].hide();
33102 buttons["yes"].hide();
33103 buttons["no"].hide();
33104 dlg.footer.dom.style.display = 'none';
33107 dlg.footer.dom.style.display = '';
33108 for(var k in buttons){
33109 if(typeof buttons[k] != "function"){
33112 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33113 width += buttons[k].el.getWidth()+15;
33123 var handleEsc = function(d, k, e){
33124 if(opt && opt.closable !== false){
33134 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33135 * @return {Roo.BasicDialog} The BasicDialog element
33137 getDialog : function(){
33139 dlg = new Roo.BasicDialog("x-msg-box", {
33144 constraintoviewport:false,
33146 collapsible : false,
33149 width:400, height:100,
33150 buttonAlign:"center",
33151 closeClick : function(){
33152 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33153 handleButton("no");
33155 handleButton("cancel");
33159 dlg.on("hide", handleHide);
33161 dlg.addKeyListener(27, handleEsc);
33163 var bt = this.buttonText;
33164 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33165 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33166 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33167 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33168 bodyEl = dlg.body.createChild({
33170 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>'
33172 msgEl = bodyEl.dom.firstChild;
33173 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33174 textboxEl.enableDisplayMode();
33175 textboxEl.addKeyListener([10,13], function(){
33176 if(dlg.isVisible() && opt && opt.buttons){
33177 if(opt.buttons.ok){
33178 handleButton("ok");
33179 }else if(opt.buttons.yes){
33180 handleButton("yes");
33184 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33185 textareaEl.enableDisplayMode();
33186 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33187 progressEl.enableDisplayMode();
33188 var pf = progressEl.dom.firstChild;
33190 pp = Roo.get(pf.firstChild);
33191 pp.setHeight(pf.offsetHeight);
33199 * Updates the message box body text
33200 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33201 * the XHTML-compliant non-breaking space character '&#160;')
33202 * @return {Roo.MessageBox} This message box
33204 updateText : function(text){
33205 if(!dlg.isVisible() && !opt.width){
33206 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33208 msgEl.innerHTML = text || ' ';
33210 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33211 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33213 Math.min(opt.width || cw , this.maxWidth),
33214 Math.max(opt.minWidth || this.minWidth, bwidth)
33217 activeTextEl.setWidth(w);
33219 if(dlg.isVisible()){
33220 dlg.fixedcenter = false;
33222 // to big, make it scroll. = But as usual stupid IE does not support
33225 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33226 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33227 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33229 bodyEl.dom.style.height = '';
33230 bodyEl.dom.style.overflowY = '';
33233 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33235 bodyEl.dom.style.overflowX = '';
33238 dlg.setContentSize(w, bodyEl.getHeight());
33239 if(dlg.isVisible()){
33240 dlg.fixedcenter = true;
33246 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33247 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33248 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33249 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33250 * @return {Roo.MessageBox} This message box
33252 updateProgress : function(value, text){
33254 this.updateText(text);
33256 if (pp) { // weird bug on my firefox - for some reason this is not defined
33257 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33263 * Returns true if the message box is currently displayed
33264 * @return {Boolean} True if the message box is visible, else false
33266 isVisible : function(){
33267 return dlg && dlg.isVisible();
33271 * Hides the message box if it is displayed
33274 if(this.isVisible()){
33280 * Displays a new message box, or reinitializes an existing message box, based on the config options
33281 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33282 * The following config object properties are supported:
33284 Property Type Description
33285 ---------- --------------- ------------------------------------------------------------------------------------
33286 animEl String/Element An id or Element from which the message box should animate as it opens and
33287 closes (defaults to undefined)
33288 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33289 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33290 closable Boolean False to hide the top-right close button (defaults to true). Note that
33291 progress and wait dialogs will ignore this property and always hide the
33292 close button as they can only be closed programmatically.
33293 cls String A custom CSS class to apply to the message box element
33294 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33295 displayed (defaults to 75)
33296 fn Function A callback function to execute after closing the dialog. The arguments to the
33297 function will be btn (the name of the button that was clicked, if applicable,
33298 e.g. "ok"), and text (the value of the active text field, if applicable).
33299 Progress and wait dialogs will ignore this option since they do not respond to
33300 user actions and can only be closed programmatically, so any required function
33301 should be called by the same code after it closes the dialog.
33302 icon String A CSS class that provides a background image to be used as an icon for
33303 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33304 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33305 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33306 modal Boolean False to allow user interaction with the page while the message box is
33307 displayed (defaults to true)
33308 msg String A string that will replace the existing message box body text (defaults
33309 to the XHTML-compliant non-breaking space character ' ')
33310 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33311 progress Boolean True to display a progress bar (defaults to false)
33312 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33313 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33314 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33315 title String The title text
33316 value String The string value to set into the active textbox element if displayed
33317 wait Boolean True to display a progress bar (defaults to false)
33318 width Number The width of the dialog in pixels
33325 msg: 'Please enter your address:',
33327 buttons: Roo.MessageBox.OKCANCEL,
33330 animEl: 'addAddressBtn'
33333 * @param {Object} config Configuration options
33334 * @return {Roo.MessageBox} This message box
33336 show : function(options)
33339 // this causes nightmares if you show one dialog after another
33340 // especially on callbacks..
33342 if(this.isVisible()){
33345 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33346 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33347 Roo.log("New Dialog Message:" + options.msg )
33348 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33349 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33352 var d = this.getDialog();
33354 d.setTitle(opt.title || " ");
33355 d.close.setDisplayed(opt.closable !== false);
33356 activeTextEl = textboxEl;
33357 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33362 textareaEl.setHeight(typeof opt.multiline == "number" ?
33363 opt.multiline : this.defaultTextHeight);
33364 activeTextEl = textareaEl;
33373 progressEl.setDisplayed(opt.progress === true);
33374 this.updateProgress(0);
33375 activeTextEl.dom.value = opt.value || "";
33377 dlg.setDefaultButton(activeTextEl);
33379 var bs = opt.buttons;
33382 db = buttons["ok"];
33383 }else if(bs && bs.yes){
33384 db = buttons["yes"];
33386 dlg.setDefaultButton(db);
33388 bwidth = updateButtons(opt.buttons);
33389 this.updateText(opt.msg);
33391 d.el.addClass(opt.cls);
33393 d.proxyDrag = opt.proxyDrag === true;
33394 d.modal = opt.modal !== false;
33395 d.mask = opt.modal !== false ? mask : false;
33396 if(!d.isVisible()){
33397 // force it to the end of the z-index stack so it gets a cursor in FF
33398 document.body.appendChild(dlg.el.dom);
33399 d.animateTarget = null;
33400 d.show(options.animEl);
33406 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33407 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33408 * and closing the message box when the process is complete.
33409 * @param {String} title The title bar text
33410 * @param {String} msg The message box body text
33411 * @return {Roo.MessageBox} This message box
33413 progress : function(title, msg){
33420 minWidth: this.minProgressWidth,
33427 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33428 * If a callback function is passed it will be called after the user clicks the button, and the
33429 * id of the button that was clicked will be passed as the only parameter to the callback
33430 * (could also be the top-right close button).
33431 * @param {String} title The title bar text
33432 * @param {String} msg The message box body text
33433 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33434 * @param {Object} scope (optional) The scope of the callback function
33435 * @return {Roo.MessageBox} This message box
33437 alert : function(title, msg, fn, scope){
33450 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33451 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33452 * You are responsible for closing the message box when the process is complete.
33453 * @param {String} msg The message box body text
33454 * @param {String} title (optional) The title bar text
33455 * @return {Roo.MessageBox} This message box
33457 wait : function(msg, title){
33468 waitTimer = Roo.TaskMgr.start({
33470 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33478 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33479 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33480 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33481 * @param {String} title The title bar text
33482 * @param {String} msg The message box body text
33483 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33484 * @param {Object} scope (optional) The scope of the callback function
33485 * @return {Roo.MessageBox} This message box
33487 confirm : function(title, msg, fn, scope){
33491 buttons: this.YESNO,
33500 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33501 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33502 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33503 * (could also be the top-right close button) and the text that was entered will be passed as the two
33504 * parameters to the callback.
33505 * @param {String} title The title bar text
33506 * @param {String} msg The message box body text
33507 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33508 * @param {Object} scope (optional) The scope of the callback function
33509 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33510 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33511 * @return {Roo.MessageBox} This message box
33513 prompt : function(title, msg, fn, scope, multiline){
33517 buttons: this.OKCANCEL,
33522 multiline: multiline,
33529 * Button config that displays a single OK button
33534 * Button config that displays Yes and No buttons
33537 YESNO : {yes:true, no:true},
33539 * Button config that displays OK and Cancel buttons
33542 OKCANCEL : {ok:true, cancel:true},
33544 * Button config that displays Yes, No and Cancel buttons
33547 YESNOCANCEL : {yes:true, no:true, cancel:true},
33550 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33553 defaultTextHeight : 75,
33555 * The maximum width in pixels of the message box (defaults to 600)
33560 * The minimum width in pixels of the message box (defaults to 100)
33565 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33566 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33569 minProgressWidth : 250,
33571 * An object containing the default button text strings that can be overriden for localized language support.
33572 * Supported properties are: ok, cancel, yes and no.
33573 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33586 * Shorthand for {@link Roo.MessageBox}
33588 Roo.Msg = Roo.MessageBox;/*
33590 * Ext JS Library 1.1.1
33591 * Copyright(c) 2006-2007, Ext JS, LLC.
33593 * Originally Released Under LGPL - original licence link has changed is not relivant.
33596 * <script type="text/javascript">
33599 * @class Roo.QuickTips
33600 * Provides attractive and customizable tooltips for any element.
33603 Roo.QuickTips = function(){
33604 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33605 var ce, bd, xy, dd;
33606 var visible = false, disabled = true, inited = false;
33607 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33609 var onOver = function(e){
33613 var t = e.getTarget();
33614 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33617 if(ce && t == ce.el){
33618 clearTimeout(hideProc);
33621 if(t && tagEls[t.id]){
33622 tagEls[t.id].el = t;
33623 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33626 var ttp, et = Roo.fly(t);
33627 var ns = cfg.namespace;
33628 if(tm.interceptTitles && t.title){
33631 t.removeAttribute("title");
33632 e.preventDefault();
33634 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33637 showProc = show.defer(tm.showDelay, tm, [{
33639 text: ttp.replace(/\\n/g,'<br/>'),
33640 width: et.getAttributeNS(ns, cfg.width),
33641 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33642 title: et.getAttributeNS(ns, cfg.title),
33643 cls: et.getAttributeNS(ns, cfg.cls)
33648 var onOut = function(e){
33649 clearTimeout(showProc);
33650 var t = e.getTarget();
33651 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33652 hideProc = setTimeout(hide, tm.hideDelay);
33656 var onMove = function(e){
33662 if(tm.trackMouse && ce){
33667 var onDown = function(e){
33668 clearTimeout(showProc);
33669 clearTimeout(hideProc);
33671 if(tm.hideOnClick){
33674 tm.enable.defer(100, tm);
33679 var getPad = function(){
33680 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33683 var show = function(o){
33687 clearTimeout(dismissProc);
33689 if(removeCls){ // in case manually hidden
33690 el.removeClass(removeCls);
33694 el.addClass(ce.cls);
33695 removeCls = ce.cls;
33698 tipTitle.update(ce.title);
33701 tipTitle.update('');
33704 el.dom.style.width = tm.maxWidth+'px';
33705 //tipBody.dom.style.width = '';
33706 tipBodyText.update(o.text);
33707 var p = getPad(), w = ce.width;
33709 var td = tipBodyText.dom;
33710 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33711 if(aw > tm.maxWidth){
33713 }else if(aw < tm.minWidth){
33719 //tipBody.setWidth(w);
33720 el.setWidth(parseInt(w, 10) + p);
33721 if(ce.autoHide === false){
33722 close.setDisplayed(true);
33727 close.setDisplayed(false);
33733 el.avoidY = xy[1]-18;
33738 el.setStyle("visibility", "visible");
33739 el.fadeIn({callback: afterShow});
33745 var afterShow = function(){
33749 if(tm.autoDismiss && ce.autoHide !== false){
33750 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33755 var hide = function(noanim){
33756 clearTimeout(dismissProc);
33757 clearTimeout(hideProc);
33759 if(el.isVisible()){
33761 if(noanim !== true && tm.animate){
33762 el.fadeOut({callback: afterHide});
33769 var afterHide = function(){
33772 el.removeClass(removeCls);
33779 * @cfg {Number} minWidth
33780 * The minimum width of the quick tip (defaults to 40)
33784 * @cfg {Number} maxWidth
33785 * The maximum width of the quick tip (defaults to 300)
33789 * @cfg {Boolean} interceptTitles
33790 * True to automatically use the element's DOM title value if available (defaults to false)
33792 interceptTitles : false,
33794 * @cfg {Boolean} trackMouse
33795 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33797 trackMouse : false,
33799 * @cfg {Boolean} hideOnClick
33800 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33802 hideOnClick : true,
33804 * @cfg {Number} showDelay
33805 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33809 * @cfg {Number} hideDelay
33810 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33814 * @cfg {Boolean} autoHide
33815 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33816 * Used in conjunction with hideDelay.
33821 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33822 * (defaults to true). Used in conjunction with autoDismissDelay.
33824 autoDismiss : true,
33827 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33829 autoDismissDelay : 5000,
33831 * @cfg {Boolean} animate
33832 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33837 * @cfg {String} title
33838 * Title text to display (defaults to ''). This can be any valid HTML markup.
33842 * @cfg {String} text
33843 * Body text to display (defaults to ''). This can be any valid HTML markup.
33847 * @cfg {String} cls
33848 * A CSS class to apply to the base quick tip element (defaults to '').
33852 * @cfg {Number} width
33853 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33854 * minWidth or maxWidth.
33859 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33860 * or display QuickTips in a page.
33863 tm = Roo.QuickTips;
33864 cfg = tm.tagConfig;
33866 if(!Roo.isReady){ // allow calling of init() before onReady
33867 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33870 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33871 el.fxDefaults = {stopFx: true};
33872 // maximum custom styling
33873 //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>');
33874 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>');
33875 tipTitle = el.child('h3');
33876 tipTitle.enableDisplayMode("block");
33877 tipBody = el.child('div.x-tip-bd');
33878 tipBodyText = el.child('div.x-tip-bd-inner');
33879 //bdLeft = el.child('div.x-tip-bd-left');
33880 //bdRight = el.child('div.x-tip-bd-right');
33881 close = el.child('div.x-tip-close');
33882 close.enableDisplayMode("block");
33883 close.on("click", hide);
33884 var d = Roo.get(document);
33885 d.on("mousedown", onDown);
33886 d.on("mouseover", onOver);
33887 d.on("mouseout", onOut);
33888 d.on("mousemove", onMove);
33889 esc = d.addKeyListener(27, hide);
33892 dd = el.initDD("default", null, {
33893 onDrag : function(){
33897 dd.setHandleElId(tipTitle.id);
33906 * Configures a new quick tip instance and assigns it to a target element. The following config options
33909 Property Type Description
33910 ---------- --------------------- ------------------------------------------------------------------------
33911 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33913 * @param {Object} config The config object
33915 register : function(config){
33916 var cs = config instanceof Array ? config : arguments;
33917 for(var i = 0, len = cs.length; i < len; i++) {
33919 var target = c.target;
33921 if(target instanceof Array){
33922 for(var j = 0, jlen = target.length; j < jlen; j++){
33923 tagEls[target[j]] = c;
33926 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33933 * Removes this quick tip from its element and destroys it.
33934 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33936 unregister : function(el){
33937 delete tagEls[Roo.id(el)];
33941 * Enable this quick tip.
33943 enable : function(){
33944 if(inited && disabled){
33946 if(locks.length < 1){
33953 * Disable this quick tip.
33955 disable : function(){
33957 clearTimeout(showProc);
33958 clearTimeout(hideProc);
33959 clearTimeout(dismissProc);
33967 * Returns true if the quick tip is enabled, else false.
33969 isEnabled : function(){
33975 namespace : "roo", // was ext?? this may break..
33976 alt_namespace : "ext",
33977 attribute : "qtip",
33987 // backwards compat
33988 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33990 * Ext JS Library 1.1.1
33991 * Copyright(c) 2006-2007, Ext JS, LLC.
33993 * Originally Released Under LGPL - original licence link has changed is not relivant.
33996 * <script type="text/javascript">
34001 * @class Roo.tree.TreePanel
34002 * @extends Roo.data.Tree
34004 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34005 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34006 * @cfg {Boolean} enableDD true to enable drag and drop
34007 * @cfg {Boolean} enableDrag true to enable just drag
34008 * @cfg {Boolean} enableDrop true to enable just drop
34009 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34010 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34011 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34012 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34013 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34014 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34015 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34016 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34017 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34018 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34019 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34020 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34021 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34022 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34023 * @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>
34024 * @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>
34027 * @param {String/HTMLElement/Element} el The container element
34028 * @param {Object} config
34030 Roo.tree.TreePanel = function(el, config){
34032 var loader = false;
34034 root = config.root;
34035 delete config.root;
34037 if (config.loader) {
34038 loader = config.loader;
34039 delete config.loader;
34042 Roo.apply(this, config);
34043 Roo.tree.TreePanel.superclass.constructor.call(this);
34044 this.el = Roo.get(el);
34045 this.el.addClass('x-tree');
34046 //console.log(root);
34048 this.setRootNode( Roo.factory(root, Roo.tree));
34051 this.loader = Roo.factory(loader, Roo.tree);
34054 * Read-only. The id of the container element becomes this TreePanel's id.
34056 this.id = this.el.id;
34059 * @event beforeload
34060 * Fires before a node is loaded, return false to cancel
34061 * @param {Node} node The node being loaded
34063 "beforeload" : true,
34066 * Fires when a node is loaded
34067 * @param {Node} node The node that was loaded
34071 * @event textchange
34072 * Fires when the text for a node is changed
34073 * @param {Node} node The node
34074 * @param {String} text The new text
34075 * @param {String} oldText The old text
34077 "textchange" : true,
34079 * @event beforeexpand
34080 * Fires before a node is expanded, return false to cancel.
34081 * @param {Node} node The node
34082 * @param {Boolean} deep
34083 * @param {Boolean} anim
34085 "beforeexpand" : true,
34087 * @event beforecollapse
34088 * Fires before a node is collapsed, return false to cancel.
34089 * @param {Node} node The node
34090 * @param {Boolean} deep
34091 * @param {Boolean} anim
34093 "beforecollapse" : true,
34096 * Fires when a node is expanded
34097 * @param {Node} node The node
34101 * @event disabledchange
34102 * Fires when the disabled status of a node changes
34103 * @param {Node} node The node
34104 * @param {Boolean} disabled
34106 "disabledchange" : true,
34109 * Fires when a node is collapsed
34110 * @param {Node} node The node
34114 * @event beforeclick
34115 * Fires before click processing on a node. Return false to cancel the default action.
34116 * @param {Node} node The node
34117 * @param {Roo.EventObject} e The event object
34119 "beforeclick":true,
34121 * @event checkchange
34122 * Fires when a node with a checkbox's checked property changes
34123 * @param {Node} this This node
34124 * @param {Boolean} checked
34126 "checkchange":true,
34129 * Fires when a node is clicked
34130 * @param {Node} node The node
34131 * @param {Roo.EventObject} e The event object
34136 * Fires when a node is double clicked
34137 * @param {Node} node The node
34138 * @param {Roo.EventObject} e The event object
34142 * @event contextmenu
34143 * Fires when a node is right clicked
34144 * @param {Node} node The node
34145 * @param {Roo.EventObject} e The event object
34147 "contextmenu":true,
34149 * @event beforechildrenrendered
34150 * Fires right before the child nodes for a node are rendered
34151 * @param {Node} node The node
34153 "beforechildrenrendered":true,
34156 * Fires when a node starts being dragged
34157 * @param {Roo.tree.TreePanel} this
34158 * @param {Roo.tree.TreeNode} node
34159 * @param {event} e The raw browser event
34161 "startdrag" : true,
34164 * Fires when a drag operation is complete
34165 * @param {Roo.tree.TreePanel} this
34166 * @param {Roo.tree.TreeNode} node
34167 * @param {event} e The raw browser event
34172 * Fires when a dragged node is dropped on a valid DD target
34173 * @param {Roo.tree.TreePanel} this
34174 * @param {Roo.tree.TreeNode} node
34175 * @param {DD} dd The dd it was dropped on
34176 * @param {event} e The raw browser event
34180 * @event beforenodedrop
34181 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34182 * passed to handlers has the following properties:<br />
34183 * <ul style="padding:5px;padding-left:16px;">
34184 * <li>tree - The TreePanel</li>
34185 * <li>target - The node being targeted for the drop</li>
34186 * <li>data - The drag data from the drag source</li>
34187 * <li>point - The point of the drop - append, above or below</li>
34188 * <li>source - The drag source</li>
34189 * <li>rawEvent - Raw mouse event</li>
34190 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34191 * to be inserted by setting them on this object.</li>
34192 * <li>cancel - Set this to true to cancel the drop.</li>
34194 * @param {Object} dropEvent
34196 "beforenodedrop" : true,
34199 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34200 * passed to handlers has the following properties:<br />
34201 * <ul style="padding:5px;padding-left:16px;">
34202 * <li>tree - The TreePanel</li>
34203 * <li>target - The node being targeted for the drop</li>
34204 * <li>data - The drag data from the drag source</li>
34205 * <li>point - The point of the drop - append, above or below</li>
34206 * <li>source - The drag source</li>
34207 * <li>rawEvent - Raw mouse event</li>
34208 * <li>dropNode - Dropped node(s).</li>
34210 * @param {Object} dropEvent
34214 * @event nodedragover
34215 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34216 * passed to handlers has the following properties:<br />
34217 * <ul style="padding:5px;padding-left:16px;">
34218 * <li>tree - The TreePanel</li>
34219 * <li>target - The node being targeted for the drop</li>
34220 * <li>data - The drag data from the drag source</li>
34221 * <li>point - The point of the drop - append, above or below</li>
34222 * <li>source - The drag source</li>
34223 * <li>rawEvent - Raw mouse event</li>
34224 * <li>dropNode - Drop node(s) provided by the source.</li>
34225 * <li>cancel - Set this to true to signal drop not allowed.</li>
34227 * @param {Object} dragOverEvent
34229 "nodedragover" : true
34232 if(this.singleExpand){
34233 this.on("beforeexpand", this.restrictExpand, this);
34236 this.editor.tree = this;
34237 this.editor = Roo.factory(this.editor, Roo.tree);
34240 if (this.selModel) {
34241 this.selModel = Roo.factory(this.selModel, Roo.tree);
34245 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34246 rootVisible : true,
34247 animate: Roo.enableFx,
34250 hlDrop : Roo.enableFx,
34254 rendererTip: false,
34256 restrictExpand : function(node){
34257 var p = node.parentNode;
34259 if(p.expandedChild && p.expandedChild.parentNode == p){
34260 p.expandedChild.collapse();
34262 p.expandedChild = node;
34266 // private override
34267 setRootNode : function(node){
34268 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34269 if(!this.rootVisible){
34270 node.ui = new Roo.tree.RootTreeNodeUI(node);
34276 * Returns the container element for this TreePanel
34278 getEl : function(){
34283 * Returns the default TreeLoader for this TreePanel
34285 getLoader : function(){
34286 return this.loader;
34292 expandAll : function(){
34293 this.root.expand(true);
34297 * Collapse all nodes
34299 collapseAll : function(){
34300 this.root.collapse(true);
34304 * Returns the selection model used by this TreePanel
34306 getSelectionModel : function(){
34307 if(!this.selModel){
34308 this.selModel = new Roo.tree.DefaultSelectionModel();
34310 return this.selModel;
34314 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34315 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34316 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34319 getChecked : function(a, startNode){
34320 startNode = startNode || this.root;
34322 var f = function(){
34323 if(this.attributes.checked){
34324 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34327 startNode.cascade(f);
34332 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34333 * @param {String} path
34334 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34335 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34336 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34338 expandPath : function(path, attr, callback){
34339 attr = attr || "id";
34340 var keys = path.split(this.pathSeparator);
34341 var curNode = this.root;
34342 if(curNode.attributes[attr] != keys[1]){ // invalid root
34344 callback(false, null);
34349 var f = function(){
34350 if(++index == keys.length){
34352 callback(true, curNode);
34356 var c = curNode.findChild(attr, keys[index]);
34359 callback(false, curNode);
34364 c.expand(false, false, f);
34366 curNode.expand(false, false, f);
34370 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34371 * @param {String} path
34372 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34373 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34374 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34376 selectPath : function(path, attr, callback){
34377 attr = attr || "id";
34378 var keys = path.split(this.pathSeparator);
34379 var v = keys.pop();
34380 if(keys.length > 0){
34381 var f = function(success, node){
34382 if(success && node){
34383 var n = node.findChild(attr, v);
34389 }else if(callback){
34390 callback(false, n);
34394 callback(false, n);
34398 this.expandPath(keys.join(this.pathSeparator), attr, f);
34400 this.root.select();
34402 callback(true, this.root);
34407 getTreeEl : function(){
34412 * Trigger rendering of this TreePanel
34414 render : function(){
34415 if (this.innerCt) {
34416 return this; // stop it rendering more than once!!
34419 this.innerCt = this.el.createChild({tag:"ul",
34420 cls:"x-tree-root-ct " +
34421 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34423 if(this.containerScroll){
34424 Roo.dd.ScrollManager.register(this.el);
34426 if((this.enableDD || this.enableDrop) && !this.dropZone){
34428 * The dropZone used by this tree if drop is enabled
34429 * @type Roo.tree.TreeDropZone
34431 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34432 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34435 if((this.enableDD || this.enableDrag) && !this.dragZone){
34437 * The dragZone used by this tree if drag is enabled
34438 * @type Roo.tree.TreeDragZone
34440 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34441 ddGroup: this.ddGroup || "TreeDD",
34442 scroll: this.ddScroll
34445 this.getSelectionModel().init(this);
34447 Roo.log("ROOT not set in tree");
34450 this.root.render();
34451 if(!this.rootVisible){
34452 this.root.renderChildren();
34458 * Ext JS Library 1.1.1
34459 * Copyright(c) 2006-2007, Ext JS, LLC.
34461 * Originally Released Under LGPL - original licence link has changed is not relivant.
34464 * <script type="text/javascript">
34469 * @class Roo.tree.DefaultSelectionModel
34470 * @extends Roo.util.Observable
34471 * The default single selection for a TreePanel.
34472 * @param {Object} cfg Configuration
34474 Roo.tree.DefaultSelectionModel = function(cfg){
34475 this.selNode = null;
34481 * @event selectionchange
34482 * Fires when the selected node changes
34483 * @param {DefaultSelectionModel} this
34484 * @param {TreeNode} node the new selection
34486 "selectionchange" : true,
34489 * @event beforeselect
34490 * Fires before the selected node changes, return false to cancel the change
34491 * @param {DefaultSelectionModel} this
34492 * @param {TreeNode} node the new selection
34493 * @param {TreeNode} node the old selection
34495 "beforeselect" : true
34498 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34501 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34502 init : function(tree){
34504 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34505 tree.on("click", this.onNodeClick, this);
34508 onNodeClick : function(node, e){
34509 if (e.ctrlKey && this.selNode == node) {
34510 this.unselect(node);
34518 * @param {TreeNode} node The node to select
34519 * @return {TreeNode} The selected node
34521 select : function(node){
34522 var last = this.selNode;
34523 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34525 last.ui.onSelectedChange(false);
34527 this.selNode = node;
34528 node.ui.onSelectedChange(true);
34529 this.fireEvent("selectionchange", this, node, last);
34536 * @param {TreeNode} node The node to unselect
34538 unselect : function(node){
34539 if(this.selNode == node){
34540 this.clearSelections();
34545 * Clear all selections
34547 clearSelections : function(){
34548 var n = this.selNode;
34550 n.ui.onSelectedChange(false);
34551 this.selNode = null;
34552 this.fireEvent("selectionchange", this, null);
34558 * Get the selected node
34559 * @return {TreeNode} The selected node
34561 getSelectedNode : function(){
34562 return this.selNode;
34566 * Returns true if the node is selected
34567 * @param {TreeNode} node The node to check
34568 * @return {Boolean}
34570 isSelected : function(node){
34571 return this.selNode == node;
34575 * Selects the node above the selected node in the tree, intelligently walking the nodes
34576 * @return TreeNode The new selection
34578 selectPrevious : function(){
34579 var s = this.selNode || this.lastSelNode;
34583 var ps = s.previousSibling;
34585 if(!ps.isExpanded() || ps.childNodes.length < 1){
34586 return this.select(ps);
34588 var lc = ps.lastChild;
34589 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34592 return this.select(lc);
34594 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34595 return this.select(s.parentNode);
34601 * Selects the node above the selected node in the tree, intelligently walking the nodes
34602 * @return TreeNode The new selection
34604 selectNext : function(){
34605 var s = this.selNode || this.lastSelNode;
34609 if(s.firstChild && s.isExpanded()){
34610 return this.select(s.firstChild);
34611 }else if(s.nextSibling){
34612 return this.select(s.nextSibling);
34613 }else if(s.parentNode){
34615 s.parentNode.bubble(function(){
34616 if(this.nextSibling){
34617 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34626 onKeyDown : function(e){
34627 var s = this.selNode || this.lastSelNode;
34628 // undesirable, but required
34633 var k = e.getKey();
34641 this.selectPrevious();
34644 e.preventDefault();
34645 if(s.hasChildNodes()){
34646 if(!s.isExpanded()){
34648 }else if(s.firstChild){
34649 this.select(s.firstChild, e);
34654 e.preventDefault();
34655 if(s.hasChildNodes() && s.isExpanded()){
34657 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34658 this.select(s.parentNode, e);
34666 * @class Roo.tree.MultiSelectionModel
34667 * @extends Roo.util.Observable
34668 * Multi selection for a TreePanel.
34669 * @param {Object} cfg Configuration
34671 Roo.tree.MultiSelectionModel = function(){
34672 this.selNodes = [];
34676 * @event selectionchange
34677 * Fires when the selected nodes change
34678 * @param {MultiSelectionModel} this
34679 * @param {Array} nodes Array of the selected nodes
34681 "selectionchange" : true
34683 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34687 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34688 init : function(tree){
34690 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34691 tree.on("click", this.onNodeClick, this);
34694 onNodeClick : function(node, e){
34695 this.select(node, e, e.ctrlKey);
34700 * @param {TreeNode} node The node to select
34701 * @param {EventObject} e (optional) An event associated with the selection
34702 * @param {Boolean} keepExisting True to retain existing selections
34703 * @return {TreeNode} The selected node
34705 select : function(node, e, keepExisting){
34706 if(keepExisting !== true){
34707 this.clearSelections(true);
34709 if(this.isSelected(node)){
34710 this.lastSelNode = node;
34713 this.selNodes.push(node);
34714 this.selMap[node.id] = node;
34715 this.lastSelNode = node;
34716 node.ui.onSelectedChange(true);
34717 this.fireEvent("selectionchange", this, this.selNodes);
34723 * @param {TreeNode} node The node to unselect
34725 unselect : function(node){
34726 if(this.selMap[node.id]){
34727 node.ui.onSelectedChange(false);
34728 var sn = this.selNodes;
34731 index = sn.indexOf(node);
34733 for(var i = 0, len = sn.length; i < len; i++){
34741 this.selNodes.splice(index, 1);
34743 delete this.selMap[node.id];
34744 this.fireEvent("selectionchange", this, this.selNodes);
34749 * Clear all selections
34751 clearSelections : function(suppressEvent){
34752 var sn = this.selNodes;
34754 for(var i = 0, len = sn.length; i < len; i++){
34755 sn[i].ui.onSelectedChange(false);
34757 this.selNodes = [];
34759 if(suppressEvent !== true){
34760 this.fireEvent("selectionchange", this, this.selNodes);
34766 * Returns true if the node is selected
34767 * @param {TreeNode} node The node to check
34768 * @return {Boolean}
34770 isSelected : function(node){
34771 return this.selMap[node.id] ? true : false;
34775 * Returns an array of the selected nodes
34778 getSelectedNodes : function(){
34779 return this.selNodes;
34782 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34784 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34786 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34789 * Ext JS Library 1.1.1
34790 * Copyright(c) 2006-2007, Ext JS, LLC.
34792 * Originally Released Under LGPL - original licence link has changed is not relivant.
34795 * <script type="text/javascript">
34799 * @class Roo.tree.TreeNode
34800 * @extends Roo.data.Node
34801 * @cfg {String} text The text for this node
34802 * @cfg {Boolean} expanded true to start the node expanded
34803 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34804 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34805 * @cfg {Boolean} disabled true to start the node disabled
34806 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34807 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34808 * @cfg {String} cls A css class to be added to the node
34809 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34810 * @cfg {String} href URL of the link used for the node (defaults to #)
34811 * @cfg {String} hrefTarget target frame for the link
34812 * @cfg {String} qtip An Ext QuickTip for the node
34813 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34814 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34815 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34816 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34817 * (defaults to undefined with no checkbox rendered)
34819 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34821 Roo.tree.TreeNode = function(attributes){
34822 attributes = attributes || {};
34823 if(typeof attributes == "string"){
34824 attributes = {text: attributes};
34826 this.childrenRendered = false;
34827 this.rendered = false;
34828 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34829 this.expanded = attributes.expanded === true;
34830 this.isTarget = attributes.isTarget !== false;
34831 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34832 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34835 * Read-only. The text for this node. To change it use setText().
34838 this.text = attributes.text;
34840 * True if this node is disabled.
34843 this.disabled = attributes.disabled === true;
34847 * @event textchange
34848 * Fires when the text for this node is changed
34849 * @param {Node} this This node
34850 * @param {String} text The new text
34851 * @param {String} oldText The old text
34853 "textchange" : true,
34855 * @event beforeexpand
34856 * Fires before this node is expanded, return false to cancel.
34857 * @param {Node} this This node
34858 * @param {Boolean} deep
34859 * @param {Boolean} anim
34861 "beforeexpand" : true,
34863 * @event beforecollapse
34864 * Fires before this node is collapsed, return false to cancel.
34865 * @param {Node} this This node
34866 * @param {Boolean} deep
34867 * @param {Boolean} anim
34869 "beforecollapse" : true,
34872 * Fires when this node is expanded
34873 * @param {Node} this This node
34877 * @event disabledchange
34878 * Fires when the disabled status of this node changes
34879 * @param {Node} this This node
34880 * @param {Boolean} disabled
34882 "disabledchange" : true,
34885 * Fires when this node is collapsed
34886 * @param {Node} this This node
34890 * @event beforeclick
34891 * Fires before click processing. Return false to cancel the default action.
34892 * @param {Node} this This node
34893 * @param {Roo.EventObject} e The event object
34895 "beforeclick":true,
34897 * @event checkchange
34898 * Fires when a node with a checkbox's checked property changes
34899 * @param {Node} this This node
34900 * @param {Boolean} checked
34902 "checkchange":true,
34905 * Fires when this node is clicked
34906 * @param {Node} this This node
34907 * @param {Roo.EventObject} e The event object
34912 * Fires when this node is double clicked
34913 * @param {Node} this This node
34914 * @param {Roo.EventObject} e The event object
34918 * @event contextmenu
34919 * Fires when this node is right clicked
34920 * @param {Node} this This node
34921 * @param {Roo.EventObject} e The event object
34923 "contextmenu":true,
34925 * @event beforechildrenrendered
34926 * Fires right before the child nodes for this node are rendered
34927 * @param {Node} this This node
34929 "beforechildrenrendered":true
34932 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34935 * Read-only. The UI for this node
34938 this.ui = new uiClass(this);
34940 // finally support items[]
34941 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34946 Roo.each(this.attributes.items, function(c) {
34947 this.appendChild(Roo.factory(c,Roo.Tree));
34949 delete this.attributes.items;
34954 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34955 preventHScroll: true,
34957 * Returns true if this node is expanded
34958 * @return {Boolean}
34960 isExpanded : function(){
34961 return this.expanded;
34965 * Returns the UI object for this node
34966 * @return {TreeNodeUI}
34968 getUI : function(){
34972 // private override
34973 setFirstChild : function(node){
34974 var of = this.firstChild;
34975 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34976 if(this.childrenRendered && of && node != of){
34977 of.renderIndent(true, true);
34980 this.renderIndent(true, true);
34984 // private override
34985 setLastChild : function(node){
34986 var ol = this.lastChild;
34987 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34988 if(this.childrenRendered && ol && node != ol){
34989 ol.renderIndent(true, true);
34992 this.renderIndent(true, true);
34996 // these methods are overridden to provide lazy rendering support
34997 // private override
34998 appendChild : function()
35000 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35001 if(node && this.childrenRendered){
35004 this.ui.updateExpandIcon();
35008 // private override
35009 removeChild : function(node){
35010 this.ownerTree.getSelectionModel().unselect(node);
35011 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35012 // if it's been rendered remove dom node
35013 if(this.childrenRendered){
35016 if(this.childNodes.length < 1){
35017 this.collapse(false, false);
35019 this.ui.updateExpandIcon();
35021 if(!this.firstChild) {
35022 this.childrenRendered = false;
35027 // private override
35028 insertBefore : function(node, refNode){
35029 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35030 if(newNode && refNode && this.childrenRendered){
35033 this.ui.updateExpandIcon();
35038 * Sets the text for this node
35039 * @param {String} text
35041 setText : function(text){
35042 var oldText = this.text;
35044 this.attributes.text = text;
35045 if(this.rendered){ // event without subscribing
35046 this.ui.onTextChange(this, text, oldText);
35048 this.fireEvent("textchange", this, text, oldText);
35052 * Triggers selection of this node
35054 select : function(){
35055 this.getOwnerTree().getSelectionModel().select(this);
35059 * Triggers deselection of this node
35061 unselect : function(){
35062 this.getOwnerTree().getSelectionModel().unselect(this);
35066 * Returns true if this node is selected
35067 * @return {Boolean}
35069 isSelected : function(){
35070 return this.getOwnerTree().getSelectionModel().isSelected(this);
35074 * Expand this node.
35075 * @param {Boolean} deep (optional) True to expand all children as well
35076 * @param {Boolean} anim (optional) false to cancel the default animation
35077 * @param {Function} callback (optional) A callback to be called when
35078 * expanding this node completes (does not wait for deep expand to complete).
35079 * Called with 1 parameter, this node.
35081 expand : function(deep, anim, callback){
35082 if(!this.expanded){
35083 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35086 if(!this.childrenRendered){
35087 this.renderChildren();
35089 this.expanded = true;
35090 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35091 this.ui.animExpand(function(){
35092 this.fireEvent("expand", this);
35093 if(typeof callback == "function"){
35097 this.expandChildNodes(true);
35099 }.createDelegate(this));
35103 this.fireEvent("expand", this);
35104 if(typeof callback == "function"){
35109 if(typeof callback == "function"){
35114 this.expandChildNodes(true);
35118 isHiddenRoot : function(){
35119 return this.isRoot && !this.getOwnerTree().rootVisible;
35123 * Collapse this node.
35124 * @param {Boolean} deep (optional) True to collapse all children as well
35125 * @param {Boolean} anim (optional) false to cancel the default animation
35127 collapse : function(deep, anim){
35128 if(this.expanded && !this.isHiddenRoot()){
35129 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35132 this.expanded = false;
35133 if((this.getOwnerTree().animate && anim !== false) || anim){
35134 this.ui.animCollapse(function(){
35135 this.fireEvent("collapse", this);
35137 this.collapseChildNodes(true);
35139 }.createDelegate(this));
35142 this.ui.collapse();
35143 this.fireEvent("collapse", this);
35147 var cs = this.childNodes;
35148 for(var i = 0, len = cs.length; i < len; i++) {
35149 cs[i].collapse(true, false);
35155 delayedExpand : function(delay){
35156 if(!this.expandProcId){
35157 this.expandProcId = this.expand.defer(delay, this);
35162 cancelExpand : function(){
35163 if(this.expandProcId){
35164 clearTimeout(this.expandProcId);
35166 this.expandProcId = false;
35170 * Toggles expanded/collapsed state of the node
35172 toggle : function(){
35181 * Ensures all parent nodes are expanded
35183 ensureVisible : function(callback){
35184 var tree = this.getOwnerTree();
35185 tree.expandPath(this.parentNode.getPath(), false, function(){
35186 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35187 Roo.callback(callback);
35188 }.createDelegate(this));
35192 * Expand all child nodes
35193 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35195 expandChildNodes : function(deep){
35196 var cs = this.childNodes;
35197 for(var i = 0, len = cs.length; i < len; i++) {
35198 cs[i].expand(deep);
35203 * Collapse all child nodes
35204 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35206 collapseChildNodes : function(deep){
35207 var cs = this.childNodes;
35208 for(var i = 0, len = cs.length; i < len; i++) {
35209 cs[i].collapse(deep);
35214 * Disables this node
35216 disable : function(){
35217 this.disabled = true;
35219 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35220 this.ui.onDisableChange(this, true);
35222 this.fireEvent("disabledchange", this, true);
35226 * Enables this node
35228 enable : function(){
35229 this.disabled = false;
35230 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35231 this.ui.onDisableChange(this, false);
35233 this.fireEvent("disabledchange", this, false);
35237 renderChildren : function(suppressEvent){
35238 if(suppressEvent !== false){
35239 this.fireEvent("beforechildrenrendered", this);
35241 var cs = this.childNodes;
35242 for(var i = 0, len = cs.length; i < len; i++){
35243 cs[i].render(true);
35245 this.childrenRendered = true;
35249 sort : function(fn, scope){
35250 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35251 if(this.childrenRendered){
35252 var cs = this.childNodes;
35253 for(var i = 0, len = cs.length; i < len; i++){
35254 cs[i].render(true);
35260 render : function(bulkRender){
35261 this.ui.render(bulkRender);
35262 if(!this.rendered){
35263 this.rendered = true;
35265 this.expanded = false;
35266 this.expand(false, false);
35272 renderIndent : function(deep, refresh){
35274 this.ui.childIndent = null;
35276 this.ui.renderIndent();
35277 if(deep === true && this.childrenRendered){
35278 var cs = this.childNodes;
35279 for(var i = 0, len = cs.length; i < len; i++){
35280 cs[i].renderIndent(true, refresh);
35286 * Ext JS Library 1.1.1
35287 * Copyright(c) 2006-2007, Ext JS, LLC.
35289 * Originally Released Under LGPL - original licence link has changed is not relivant.
35292 * <script type="text/javascript">
35296 * @class Roo.tree.AsyncTreeNode
35297 * @extends Roo.tree.TreeNode
35298 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35300 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35302 Roo.tree.AsyncTreeNode = function(config){
35303 this.loaded = false;
35304 this.loading = false;
35305 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35307 * @event beforeload
35308 * Fires before this node is loaded, return false to cancel
35309 * @param {Node} this This node
35311 this.addEvents({'beforeload':true, 'load': true});
35314 * Fires when this node is loaded
35315 * @param {Node} this This node
35318 * The loader used by this node (defaults to using the tree's defined loader)
35323 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35324 expand : function(deep, anim, callback){
35325 if(this.loading){ // if an async load is already running, waiting til it's done
35327 var f = function(){
35328 if(!this.loading){ // done loading
35329 clearInterval(timer);
35330 this.expand(deep, anim, callback);
35332 }.createDelegate(this);
35333 timer = setInterval(f, 200);
35337 if(this.fireEvent("beforeload", this) === false){
35340 this.loading = true;
35341 this.ui.beforeLoad(this);
35342 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35344 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35348 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35352 * Returns true if this node is currently loading
35353 * @return {Boolean}
35355 isLoading : function(){
35356 return this.loading;
35359 loadComplete : function(deep, anim, callback){
35360 this.loading = false;
35361 this.loaded = true;
35362 this.ui.afterLoad(this);
35363 this.fireEvent("load", this);
35364 this.expand(deep, anim, callback);
35368 * Returns true if this node has been loaded
35369 * @return {Boolean}
35371 isLoaded : function(){
35372 return this.loaded;
35375 hasChildNodes : function(){
35376 if(!this.isLeaf() && !this.loaded){
35379 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35384 * Trigger a reload for this node
35385 * @param {Function} callback
35387 reload : function(callback){
35388 this.collapse(false, false);
35389 while(this.firstChild){
35390 this.removeChild(this.firstChild);
35392 this.childrenRendered = false;
35393 this.loaded = false;
35394 if(this.isHiddenRoot()){
35395 this.expanded = false;
35397 this.expand(false, false, callback);
35401 * Ext JS Library 1.1.1
35402 * Copyright(c) 2006-2007, Ext JS, LLC.
35404 * Originally Released Under LGPL - original licence link has changed is not relivant.
35407 * <script type="text/javascript">
35411 * @class Roo.tree.TreeNodeUI
35413 * @param {Object} node The node to render
35414 * The TreeNode UI implementation is separate from the
35415 * tree implementation. Unless you are customizing the tree UI,
35416 * you should never have to use this directly.
35418 Roo.tree.TreeNodeUI = function(node){
35420 this.rendered = false;
35421 this.animating = false;
35422 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35425 Roo.tree.TreeNodeUI.prototype = {
35426 removeChild : function(node){
35428 this.ctNode.removeChild(node.ui.getEl());
35432 beforeLoad : function(){
35433 this.addClass("x-tree-node-loading");
35436 afterLoad : function(){
35437 this.removeClass("x-tree-node-loading");
35440 onTextChange : function(node, text, oldText){
35442 this.textNode.innerHTML = text;
35446 onDisableChange : function(node, state){
35447 this.disabled = state;
35449 this.addClass("x-tree-node-disabled");
35451 this.removeClass("x-tree-node-disabled");
35455 onSelectedChange : function(state){
35458 this.addClass("x-tree-selected");
35461 this.removeClass("x-tree-selected");
35465 onMove : function(tree, node, oldParent, newParent, index, refNode){
35466 this.childIndent = null;
35468 var targetNode = newParent.ui.getContainer();
35469 if(!targetNode){//target not rendered
35470 this.holder = document.createElement("div");
35471 this.holder.appendChild(this.wrap);
35474 var insertBefore = refNode ? refNode.ui.getEl() : null;
35476 targetNode.insertBefore(this.wrap, insertBefore);
35478 targetNode.appendChild(this.wrap);
35480 this.node.renderIndent(true);
35484 addClass : function(cls){
35486 Roo.fly(this.elNode).addClass(cls);
35490 removeClass : function(cls){
35492 Roo.fly(this.elNode).removeClass(cls);
35496 remove : function(){
35498 this.holder = document.createElement("div");
35499 this.holder.appendChild(this.wrap);
35503 fireEvent : function(){
35504 return this.node.fireEvent.apply(this.node, arguments);
35507 initEvents : function(){
35508 this.node.on("move", this.onMove, this);
35509 var E = Roo.EventManager;
35510 var a = this.anchor;
35512 var el = Roo.fly(a, '_treeui');
35514 if(Roo.isOpera){ // opera render bug ignores the CSS
35515 el.setStyle("text-decoration", "none");
35518 el.on("click", this.onClick, this);
35519 el.on("dblclick", this.onDblClick, this);
35522 Roo.EventManager.on(this.checkbox,
35523 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35526 el.on("contextmenu", this.onContextMenu, this);
35528 var icon = Roo.fly(this.iconNode);
35529 icon.on("click", this.onClick, this);
35530 icon.on("dblclick", this.onDblClick, this);
35531 icon.on("contextmenu", this.onContextMenu, this);
35532 E.on(this.ecNode, "click", this.ecClick, this, true);
35534 if(this.node.disabled){
35535 this.addClass("x-tree-node-disabled");
35537 if(this.node.hidden){
35538 this.addClass("x-tree-node-disabled");
35540 var ot = this.node.getOwnerTree();
35541 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35542 if(dd && (!this.node.isRoot || ot.rootVisible)){
35543 Roo.dd.Registry.register(this.elNode, {
35545 handles: this.getDDHandles(),
35551 getDDHandles : function(){
35552 return [this.iconNode, this.textNode];
35557 this.wrap.style.display = "none";
35563 this.wrap.style.display = "";
35567 onContextMenu : function(e){
35568 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35569 e.preventDefault();
35571 this.fireEvent("contextmenu", this.node, e);
35575 onClick : function(e){
35580 if(this.fireEvent("beforeclick", this.node, e) !== false){
35581 if(!this.disabled && this.node.attributes.href){
35582 this.fireEvent("click", this.node, e);
35585 e.preventDefault();
35590 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35591 this.node.toggle();
35594 this.fireEvent("click", this.node, e);
35600 onDblClick : function(e){
35601 e.preventDefault();
35606 this.toggleCheck();
35608 if(!this.animating && this.node.hasChildNodes()){
35609 this.node.toggle();
35611 this.fireEvent("dblclick", this.node, e);
35614 onCheckChange : function(){
35615 var checked = this.checkbox.checked;
35616 this.node.attributes.checked = checked;
35617 this.fireEvent('checkchange', this.node, checked);
35620 ecClick : function(e){
35621 if(!this.animating && this.node.hasChildNodes()){
35622 this.node.toggle();
35626 startDrop : function(){
35627 this.dropping = true;
35630 // delayed drop so the click event doesn't get fired on a drop
35631 endDrop : function(){
35632 setTimeout(function(){
35633 this.dropping = false;
35634 }.createDelegate(this), 50);
35637 expand : function(){
35638 this.updateExpandIcon();
35639 this.ctNode.style.display = "";
35642 focus : function(){
35643 if(!this.node.preventHScroll){
35644 try{this.anchor.focus();
35646 }else if(!Roo.isIE){
35648 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35649 var l = noscroll.scrollLeft;
35650 this.anchor.focus();
35651 noscroll.scrollLeft = l;
35656 toggleCheck : function(value){
35657 var cb = this.checkbox;
35659 cb.checked = (value === undefined ? !cb.checked : value);
35665 this.anchor.blur();
35669 animExpand : function(callback){
35670 var ct = Roo.get(this.ctNode);
35672 if(!this.node.hasChildNodes()){
35673 this.updateExpandIcon();
35674 this.ctNode.style.display = "";
35675 Roo.callback(callback);
35678 this.animating = true;
35679 this.updateExpandIcon();
35682 callback : function(){
35683 this.animating = false;
35684 Roo.callback(callback);
35687 duration: this.node.ownerTree.duration || .25
35691 highlight : function(){
35692 var tree = this.node.getOwnerTree();
35693 Roo.fly(this.wrap).highlight(
35694 tree.hlColor || "C3DAF9",
35695 {endColor: tree.hlBaseColor}
35699 collapse : function(){
35700 this.updateExpandIcon();
35701 this.ctNode.style.display = "none";
35704 animCollapse : function(callback){
35705 var ct = Roo.get(this.ctNode);
35706 ct.enableDisplayMode('block');
35709 this.animating = true;
35710 this.updateExpandIcon();
35713 callback : function(){
35714 this.animating = false;
35715 Roo.callback(callback);
35718 duration: this.node.ownerTree.duration || .25
35722 getContainer : function(){
35723 return this.ctNode;
35726 getEl : function(){
35730 appendDDGhost : function(ghostNode){
35731 ghostNode.appendChild(this.elNode.cloneNode(true));
35734 getDDRepairXY : function(){
35735 return Roo.lib.Dom.getXY(this.iconNode);
35738 onRender : function(){
35742 render : function(bulkRender){
35743 var n = this.node, a = n.attributes;
35744 var targetNode = n.parentNode ?
35745 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35747 if(!this.rendered){
35748 this.rendered = true;
35750 this.renderElements(n, a, targetNode, bulkRender);
35753 if(this.textNode.setAttributeNS){
35754 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35756 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35759 this.textNode.setAttribute("ext:qtip", a.qtip);
35761 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35764 }else if(a.qtipCfg){
35765 a.qtipCfg.target = Roo.id(this.textNode);
35766 Roo.QuickTips.register(a.qtipCfg);
35769 if(!this.node.expanded){
35770 this.updateExpandIcon();
35773 if(bulkRender === true) {
35774 targetNode.appendChild(this.wrap);
35779 renderElements : function(n, a, targetNode, bulkRender)
35781 // add some indent caching, this helps performance when rendering a large tree
35782 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35783 var t = n.getOwnerTree();
35784 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35785 if (typeof(n.attributes.html) != 'undefined') {
35786 txt = n.attributes.html;
35788 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35789 var cb = typeof a.checked == 'boolean';
35790 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35791 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35792 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35793 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35794 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35795 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35796 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35797 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35798 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35799 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35802 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35803 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35804 n.nextSibling.ui.getEl(), buf.join(""));
35806 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35809 this.elNode = this.wrap.childNodes[0];
35810 this.ctNode = this.wrap.childNodes[1];
35811 var cs = this.elNode.childNodes;
35812 this.indentNode = cs[0];
35813 this.ecNode = cs[1];
35814 this.iconNode = cs[2];
35817 this.checkbox = cs[3];
35820 this.anchor = cs[index];
35821 this.textNode = cs[index].firstChild;
35824 getAnchor : function(){
35825 return this.anchor;
35828 getTextEl : function(){
35829 return this.textNode;
35832 getIconEl : function(){
35833 return this.iconNode;
35836 isChecked : function(){
35837 return this.checkbox ? this.checkbox.checked : false;
35840 updateExpandIcon : function(){
35842 var n = this.node, c1, c2;
35843 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35844 var hasChild = n.hasChildNodes();
35848 c1 = "x-tree-node-collapsed";
35849 c2 = "x-tree-node-expanded";
35852 c1 = "x-tree-node-expanded";
35853 c2 = "x-tree-node-collapsed";
35856 this.removeClass("x-tree-node-leaf");
35857 this.wasLeaf = false;
35859 if(this.c1 != c1 || this.c2 != c2){
35860 Roo.fly(this.elNode).replaceClass(c1, c2);
35861 this.c1 = c1; this.c2 = c2;
35864 // this changes non-leafs into leafs if they have no children.
35865 // it's not very rational behaviour..
35867 if(!this.wasLeaf && this.node.leaf){
35868 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35871 this.wasLeaf = true;
35874 var ecc = "x-tree-ec-icon "+cls;
35875 if(this.ecc != ecc){
35876 this.ecNode.className = ecc;
35882 getChildIndent : function(){
35883 if(!this.childIndent){
35887 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35889 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35891 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35896 this.childIndent = buf.join("");
35898 return this.childIndent;
35901 renderIndent : function(){
35904 var p = this.node.parentNode;
35906 indent = p.ui.getChildIndent();
35908 if(this.indentMarkup != indent){ // don't rerender if not required
35909 this.indentNode.innerHTML = indent;
35910 this.indentMarkup = indent;
35912 this.updateExpandIcon();
35917 Roo.tree.RootTreeNodeUI = function(){
35918 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35920 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35921 render : function(){
35922 if(!this.rendered){
35923 var targetNode = this.node.ownerTree.innerCt.dom;
35924 this.node.expanded = true;
35925 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35926 this.wrap = this.ctNode = targetNode.firstChild;
35929 collapse : function(){
35931 expand : function(){
35935 * Ext JS Library 1.1.1
35936 * Copyright(c) 2006-2007, Ext JS, LLC.
35938 * Originally Released Under LGPL - original licence link has changed is not relivant.
35941 * <script type="text/javascript">
35944 * @class Roo.tree.TreeLoader
35945 * @extends Roo.util.Observable
35946 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35947 * nodes from a specified URL. The response must be a javascript Array definition
35948 * who's elements are node definition objects. eg:
35953 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35954 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35961 * The old style respose with just an array is still supported, but not recommended.
35964 * A server request is sent, and child nodes are loaded only when a node is expanded.
35965 * The loading node's id is passed to the server under the parameter name "node" to
35966 * enable the server to produce the correct child nodes.
35968 * To pass extra parameters, an event handler may be attached to the "beforeload"
35969 * event, and the parameters specified in the TreeLoader's baseParams property:
35971 myTreeLoader.on("beforeload", function(treeLoader, node) {
35972 this.baseParams.category = node.attributes.category;
35975 * This would pass an HTTP parameter called "category" to the server containing
35976 * the value of the Node's "category" attribute.
35978 * Creates a new Treeloader.
35979 * @param {Object} config A config object containing config properties.
35981 Roo.tree.TreeLoader = function(config){
35982 this.baseParams = {};
35983 this.requestMethod = "POST";
35984 Roo.apply(this, config);
35989 * @event beforeload
35990 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35991 * @param {Object} This TreeLoader object.
35992 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35993 * @param {Object} callback The callback function specified in the {@link #load} call.
35998 * Fires when the node has been successfuly loaded.
35999 * @param {Object} This TreeLoader object.
36000 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36001 * @param {Object} response The response object containing the data from the server.
36005 * @event loadexception
36006 * Fires if the network request failed.
36007 * @param {Object} This TreeLoader object.
36008 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36009 * @param {Object} response The response object containing the data from the server.
36011 loadexception : true,
36014 * Fires before a node is created, enabling you to return custom Node types
36015 * @param {Object} This TreeLoader object.
36016 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36021 Roo.tree.TreeLoader.superclass.constructor.call(this);
36024 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36026 * @cfg {String} dataUrl The URL from which to request a Json string which
36027 * specifies an array of node definition object representing the child nodes
36031 * @cfg {String} requestMethod either GET or POST
36032 * defaults to POST (due to BC)
36036 * @cfg {Object} baseParams (optional) An object containing properties which
36037 * specify HTTP parameters to be passed to each request for child nodes.
36040 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36041 * created by this loader. If the attributes sent by the server have an attribute in this object,
36042 * they take priority.
36045 * @cfg {Object} uiProviders (optional) An object containing properties which
36047 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36048 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36049 * <i>uiProvider</i> attribute of a returned child node is a string rather
36050 * than a reference to a TreeNodeUI implementation, this that string value
36051 * is used as a property name in the uiProviders object. You can define the provider named
36052 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36057 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36058 * child nodes before loading.
36060 clearOnLoad : true,
36063 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36064 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36065 * Grid query { data : [ .....] }
36070 * @cfg {String} queryParam (optional)
36071 * Name of the query as it will be passed on the querystring (defaults to 'node')
36072 * eg. the request will be ?node=[id]
36079 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36080 * This is called automatically when a node is expanded, but may be used to reload
36081 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36082 * @param {Roo.tree.TreeNode} node
36083 * @param {Function} callback
36085 load : function(node, callback){
36086 if(this.clearOnLoad){
36087 while(node.firstChild){
36088 node.removeChild(node.firstChild);
36091 if(node.attributes.children){ // preloaded json children
36092 var cs = node.attributes.children;
36093 for(var i = 0, len = cs.length; i < len; i++){
36094 node.appendChild(this.createNode(cs[i]));
36096 if(typeof callback == "function"){
36099 }else if(this.dataUrl){
36100 this.requestData(node, callback);
36104 getParams: function(node){
36105 var buf = [], bp = this.baseParams;
36106 for(var key in bp){
36107 if(typeof bp[key] != "function"){
36108 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36111 var n = this.queryParam === false ? 'node' : this.queryParam;
36112 buf.push(n + "=", encodeURIComponent(node.id));
36113 return buf.join("");
36116 requestData : function(node, callback){
36117 if(this.fireEvent("beforeload", this, node, callback) !== false){
36118 this.transId = Roo.Ajax.request({
36119 method:this.requestMethod,
36120 url: this.dataUrl||this.url,
36121 success: this.handleResponse,
36122 failure: this.handleFailure,
36124 argument: {callback: callback, node: node},
36125 params: this.getParams(node)
36128 // if the load is cancelled, make sure we notify
36129 // the node that we are done
36130 if(typeof callback == "function"){
36136 isLoading : function(){
36137 return this.transId ? true : false;
36140 abort : function(){
36141 if(this.isLoading()){
36142 Roo.Ajax.abort(this.transId);
36147 createNode : function(attr)
36149 // apply baseAttrs, nice idea Corey!
36150 if(this.baseAttrs){
36151 Roo.applyIf(attr, this.baseAttrs);
36153 if(this.applyLoader !== false){
36154 attr.loader = this;
36156 // uiProvider = depreciated..
36158 if(typeof(attr.uiProvider) == 'string'){
36159 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36160 /** eval:var:attr */ eval(attr.uiProvider);
36162 if(typeof(this.uiProviders['default']) != 'undefined') {
36163 attr.uiProvider = this.uiProviders['default'];
36166 this.fireEvent('create', this, attr);
36168 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36170 new Roo.tree.TreeNode(attr) :
36171 new Roo.tree.AsyncTreeNode(attr));
36174 processResponse : function(response, node, callback)
36176 var json = response.responseText;
36179 var o = Roo.decode(json);
36181 if (this.root === false && typeof(o.success) != undefined) {
36182 this.root = 'data'; // the default behaviour for list like data..
36185 if (this.root !== false && !o.success) {
36186 // it's a failure condition.
36187 var a = response.argument;
36188 this.fireEvent("loadexception", this, a.node, response);
36189 Roo.log("Load failed - should have a handler really");
36195 if (this.root !== false) {
36199 for(var i = 0, len = o.length; i < len; i++){
36200 var n = this.createNode(o[i]);
36202 node.appendChild(n);
36205 if(typeof callback == "function"){
36206 callback(this, node);
36209 this.handleFailure(response);
36213 handleResponse : function(response){
36214 this.transId = false;
36215 var a = response.argument;
36216 this.processResponse(response, a.node, a.callback);
36217 this.fireEvent("load", this, a.node, response);
36220 handleFailure : function(response)
36222 // should handle failure better..
36223 this.transId = false;
36224 var a = response.argument;
36225 this.fireEvent("loadexception", this, a.node, response);
36226 if(typeof a.callback == "function"){
36227 a.callback(this, a.node);
36232 * Ext JS Library 1.1.1
36233 * Copyright(c) 2006-2007, Ext JS, LLC.
36235 * Originally Released Under LGPL - original licence link has changed is not relivant.
36238 * <script type="text/javascript">
36242 * @class Roo.tree.TreeFilter
36243 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36244 * @param {TreePanel} tree
36245 * @param {Object} config (optional)
36247 Roo.tree.TreeFilter = function(tree, config){
36249 this.filtered = {};
36250 Roo.apply(this, config);
36253 Roo.tree.TreeFilter.prototype = {
36260 * Filter the data by a specific attribute.
36261 * @param {String/RegExp} value Either string that the attribute value
36262 * should start with or a RegExp to test against the attribute
36263 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36264 * @param {TreeNode} startNode (optional) The node to start the filter at.
36266 filter : function(value, attr, startNode){
36267 attr = attr || "text";
36269 if(typeof value == "string"){
36270 var vlen = value.length;
36271 // auto clear empty filter
36272 if(vlen == 0 && this.clearBlank){
36276 value = value.toLowerCase();
36278 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36280 }else if(value.exec){ // regex?
36282 return value.test(n.attributes[attr]);
36285 throw 'Illegal filter type, must be string or regex';
36287 this.filterBy(f, null, startNode);
36291 * Filter by a function. The passed function will be called with each
36292 * node in the tree (or from the startNode). If the function returns true, the node is kept
36293 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36294 * @param {Function} fn The filter function
36295 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36297 filterBy : function(fn, scope, startNode){
36298 startNode = startNode || this.tree.root;
36299 if(this.autoClear){
36302 var af = this.filtered, rv = this.reverse;
36303 var f = function(n){
36304 if(n == startNode){
36310 var m = fn.call(scope || n, n);
36318 startNode.cascade(f);
36321 if(typeof id != "function"){
36323 if(n && n.parentNode){
36324 n.parentNode.removeChild(n);
36332 * Clears the current filter. Note: with the "remove" option
36333 * set a filter cannot be cleared.
36335 clear : function(){
36337 var af = this.filtered;
36339 if(typeof id != "function"){
36346 this.filtered = {};
36351 * Ext JS Library 1.1.1
36352 * Copyright(c) 2006-2007, Ext JS, LLC.
36354 * Originally Released Under LGPL - original licence link has changed is not relivant.
36357 * <script type="text/javascript">
36362 * @class Roo.tree.TreeSorter
36363 * Provides sorting of nodes in a TreePanel
36365 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36366 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36367 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36368 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36369 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36370 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36372 * @param {TreePanel} tree
36373 * @param {Object} config
36375 Roo.tree.TreeSorter = function(tree, config){
36376 Roo.apply(this, config);
36377 tree.on("beforechildrenrendered", this.doSort, this);
36378 tree.on("append", this.updateSort, this);
36379 tree.on("insert", this.updateSort, this);
36381 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36382 var p = this.property || "text";
36383 var sortType = this.sortType;
36384 var fs = this.folderSort;
36385 var cs = this.caseSensitive === true;
36386 var leafAttr = this.leafAttr || 'leaf';
36388 this.sortFn = function(n1, n2){
36390 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36393 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36397 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36398 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36400 return dsc ? +1 : -1;
36402 return dsc ? -1 : +1;
36409 Roo.tree.TreeSorter.prototype = {
36410 doSort : function(node){
36411 node.sort(this.sortFn);
36414 compareNodes : function(n1, n2){
36415 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36418 updateSort : function(tree, node){
36419 if(node.childrenRendered){
36420 this.doSort.defer(1, this, [node]);
36425 * Ext JS Library 1.1.1
36426 * Copyright(c) 2006-2007, Ext JS, LLC.
36428 * Originally Released Under LGPL - original licence link has changed is not relivant.
36431 * <script type="text/javascript">
36434 if(Roo.dd.DropZone){
36436 Roo.tree.TreeDropZone = function(tree, config){
36437 this.allowParentInsert = false;
36438 this.allowContainerDrop = false;
36439 this.appendOnly = false;
36440 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36442 this.lastInsertClass = "x-tree-no-status";
36443 this.dragOverData = {};
36446 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36447 ddGroup : "TreeDD",
36450 expandDelay : 1000,
36452 expandNode : function(node){
36453 if(node.hasChildNodes() && !node.isExpanded()){
36454 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36458 queueExpand : function(node){
36459 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36462 cancelExpand : function(){
36463 if(this.expandProcId){
36464 clearTimeout(this.expandProcId);
36465 this.expandProcId = false;
36469 isValidDropPoint : function(n, pt, dd, e, data){
36470 if(!n || !data){ return false; }
36471 var targetNode = n.node;
36472 var dropNode = data.node;
36473 // default drop rules
36474 if(!(targetNode && targetNode.isTarget && pt)){
36477 if(pt == "append" && targetNode.allowChildren === false){
36480 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36483 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36486 // reuse the object
36487 var overEvent = this.dragOverData;
36488 overEvent.tree = this.tree;
36489 overEvent.target = targetNode;
36490 overEvent.data = data;
36491 overEvent.point = pt;
36492 overEvent.source = dd;
36493 overEvent.rawEvent = e;
36494 overEvent.dropNode = dropNode;
36495 overEvent.cancel = false;
36496 var result = this.tree.fireEvent("nodedragover", overEvent);
36497 return overEvent.cancel === false && result !== false;
36500 getDropPoint : function(e, n, dd)
36504 return tn.allowChildren !== false ? "append" : false; // always append for root
36506 var dragEl = n.ddel;
36507 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36508 var y = Roo.lib.Event.getPageY(e);
36509 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36511 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36512 var noAppend = tn.allowChildren === false;
36513 if(this.appendOnly || tn.parentNode.allowChildren === false){
36514 return noAppend ? false : "append";
36516 var noBelow = false;
36517 if(!this.allowParentInsert){
36518 noBelow = tn.hasChildNodes() && tn.isExpanded();
36520 var q = (b - t) / (noAppend ? 2 : 3);
36521 if(y >= t && y < (t + q)){
36523 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36530 onNodeEnter : function(n, dd, e, data)
36532 this.cancelExpand();
36535 onNodeOver : function(n, dd, e, data)
36538 var pt = this.getDropPoint(e, n, dd);
36541 // auto node expand check
36542 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36543 this.queueExpand(node);
36544 }else if(pt != "append"){
36545 this.cancelExpand();
36548 // set the insert point style on the target node
36549 var returnCls = this.dropNotAllowed;
36550 if(this.isValidDropPoint(n, pt, dd, e, data)){
36555 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36556 cls = "x-tree-drag-insert-above";
36557 }else if(pt == "below"){
36558 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36559 cls = "x-tree-drag-insert-below";
36561 returnCls = "x-tree-drop-ok-append";
36562 cls = "x-tree-drag-append";
36564 if(this.lastInsertClass != cls){
36565 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36566 this.lastInsertClass = cls;
36573 onNodeOut : function(n, dd, e, data){
36575 this.cancelExpand();
36576 this.removeDropIndicators(n);
36579 onNodeDrop : function(n, dd, e, data){
36580 var point = this.getDropPoint(e, n, dd);
36581 var targetNode = n.node;
36582 targetNode.ui.startDrop();
36583 if(!this.isValidDropPoint(n, point, dd, e, data)){
36584 targetNode.ui.endDrop();
36587 // first try to find the drop node
36588 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36591 target: targetNode,
36596 dropNode: dropNode,
36599 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36600 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36601 targetNode.ui.endDrop();
36604 // allow target changing
36605 targetNode = dropEvent.target;
36606 if(point == "append" && !targetNode.isExpanded()){
36607 targetNode.expand(false, null, function(){
36608 this.completeDrop(dropEvent);
36609 }.createDelegate(this));
36611 this.completeDrop(dropEvent);
36616 completeDrop : function(de){
36617 var ns = de.dropNode, p = de.point, t = de.target;
36618 if(!(ns instanceof Array)){
36622 for(var i = 0, len = ns.length; i < len; i++){
36625 t.parentNode.insertBefore(n, t);
36626 }else if(p == "below"){
36627 t.parentNode.insertBefore(n, t.nextSibling);
36633 if(this.tree.hlDrop){
36637 this.tree.fireEvent("nodedrop", de);
36640 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36641 if(this.tree.hlDrop){
36642 dropNode.ui.focus();
36643 dropNode.ui.highlight();
36645 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36648 getTree : function(){
36652 removeDropIndicators : function(n){
36655 Roo.fly(el).removeClass([
36656 "x-tree-drag-insert-above",
36657 "x-tree-drag-insert-below",
36658 "x-tree-drag-append"]);
36659 this.lastInsertClass = "_noclass";
36663 beforeDragDrop : function(target, e, id){
36664 this.cancelExpand();
36668 afterRepair : function(data){
36669 if(data && Roo.enableFx){
36670 data.node.ui.highlight();
36680 * Ext JS Library 1.1.1
36681 * Copyright(c) 2006-2007, Ext JS, LLC.
36683 * Originally Released Under LGPL - original licence link has changed is not relivant.
36686 * <script type="text/javascript">
36690 if(Roo.dd.DragZone){
36691 Roo.tree.TreeDragZone = function(tree, config){
36692 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36696 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36697 ddGroup : "TreeDD",
36699 onBeforeDrag : function(data, e){
36701 return n && n.draggable && !n.disabled;
36705 onInitDrag : function(e){
36706 var data = this.dragData;
36707 this.tree.getSelectionModel().select(data.node);
36708 this.proxy.update("");
36709 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36710 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36713 getRepairXY : function(e, data){
36714 return data.node.ui.getDDRepairXY();
36717 onEndDrag : function(data, e){
36718 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36723 onValidDrop : function(dd, e, id){
36724 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36728 beforeInvalidDrop : function(e, id){
36729 // this scrolls the original position back into view
36730 var sm = this.tree.getSelectionModel();
36731 sm.clearSelections();
36732 sm.select(this.dragData.node);
36737 * Ext JS Library 1.1.1
36738 * Copyright(c) 2006-2007, Ext JS, LLC.
36740 * Originally Released Under LGPL - original licence link has changed is not relivant.
36743 * <script type="text/javascript">
36746 * @class Roo.tree.TreeEditor
36747 * @extends Roo.Editor
36748 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36749 * as the editor field.
36751 * @param {Object} config (used to be the tree panel.)
36752 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36754 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36755 * @cfg {Roo.form.TextField|Object} field The field configuration
36759 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36762 if (oldconfig) { // old style..
36763 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36766 tree = config.tree;
36767 config.field = config.field || {};
36768 config.field.xtype = 'TextField';
36769 field = Roo.factory(config.field, Roo.form);
36771 config = config || {};
36776 * @event beforenodeedit
36777 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36778 * false from the handler of this event.
36779 * @param {Editor} this
36780 * @param {Roo.tree.Node} node
36782 "beforenodeedit" : true
36786 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36790 tree.on('beforeclick', this.beforeNodeClick, this);
36791 tree.getTreeEl().on('mousedown', this.hide, this);
36792 this.on('complete', this.updateNode, this);
36793 this.on('beforestartedit', this.fitToTree, this);
36794 this.on('startedit', this.bindScroll, this, {delay:10});
36795 this.on('specialkey', this.onSpecialKey, this);
36798 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36800 * @cfg {String} alignment
36801 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36807 * @cfg {Boolean} hideEl
36808 * True to hide the bound element while the editor is displayed (defaults to false)
36812 * @cfg {String} cls
36813 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36815 cls: "x-small-editor x-tree-editor",
36817 * @cfg {Boolean} shim
36818 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36824 * @cfg {Number} maxWidth
36825 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36826 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36827 * scroll and client offsets into account prior to each edit.
36834 fitToTree : function(ed, el){
36835 var td = this.tree.getTreeEl().dom, nd = el.dom;
36836 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36837 td.scrollLeft = nd.offsetLeft;
36841 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36842 this.setSize(w, '');
36844 return this.fireEvent('beforenodeedit', this, this.editNode);
36849 triggerEdit : function(node){
36850 this.completeEdit();
36851 this.editNode = node;
36852 this.startEdit(node.ui.textNode, node.text);
36856 bindScroll : function(){
36857 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36861 beforeNodeClick : function(node, e){
36862 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36863 this.lastClick = new Date();
36864 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36866 this.triggerEdit(node);
36873 updateNode : function(ed, value){
36874 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36875 this.editNode.setText(value);
36879 onHide : function(){
36880 Roo.tree.TreeEditor.superclass.onHide.call(this);
36882 this.editNode.ui.focus();
36887 onSpecialKey : function(field, e){
36888 var k = e.getKey();
36892 }else if(k == e.ENTER && !e.hasModifier()){
36894 this.completeEdit();
36897 });//<Script type="text/javascript">
36900 * Ext JS Library 1.1.1
36901 * Copyright(c) 2006-2007, Ext JS, LLC.
36903 * Originally Released Under LGPL - original licence link has changed is not relivant.
36906 * <script type="text/javascript">
36910 * Not documented??? - probably should be...
36913 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36914 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36916 renderElements : function(n, a, targetNode, bulkRender){
36917 //consel.log("renderElements?");
36918 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36920 var t = n.getOwnerTree();
36921 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36923 var cols = t.columns;
36924 var bw = t.borderWidth;
36926 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36927 var cb = typeof a.checked == "boolean";
36928 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36929 var colcls = 'x-t-' + tid + '-c0';
36931 '<li class="x-tree-node">',
36934 '<div class="x-tree-node-el ', a.cls,'">',
36936 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36939 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36940 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36941 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36942 (a.icon ? ' x-tree-node-inline-icon' : ''),
36943 (a.iconCls ? ' '+a.iconCls : ''),
36944 '" unselectable="on" />',
36945 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36946 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36948 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36949 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36950 '<span unselectable="on" qtip="' + tx + '">',
36954 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36955 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36957 for(var i = 1, len = cols.length; i < len; i++){
36959 colcls = 'x-t-' + tid + '-c' +i;
36960 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36961 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36962 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36968 '<div class="x-clear"></div></div>',
36969 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36972 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36973 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36974 n.nextSibling.ui.getEl(), buf.join(""));
36976 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36978 var el = this.wrap.firstChild;
36980 this.elNode = el.firstChild;
36981 this.ranchor = el.childNodes[1];
36982 this.ctNode = this.wrap.childNodes[1];
36983 var cs = el.firstChild.childNodes;
36984 this.indentNode = cs[0];
36985 this.ecNode = cs[1];
36986 this.iconNode = cs[2];
36989 this.checkbox = cs[3];
36992 this.anchor = cs[index];
36994 this.textNode = cs[index].firstChild;
36996 //el.on("click", this.onClick, this);
36997 //el.on("dblclick", this.onDblClick, this);
37000 // console.log(this);
37002 initEvents : function(){
37003 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37006 var a = this.ranchor;
37008 var el = Roo.get(a);
37010 if(Roo.isOpera){ // opera render bug ignores the CSS
37011 el.setStyle("text-decoration", "none");
37014 el.on("click", this.onClick, this);
37015 el.on("dblclick", this.onDblClick, this);
37016 el.on("contextmenu", this.onContextMenu, this);
37020 /*onSelectedChange : function(state){
37023 this.addClass("x-tree-selected");
37026 this.removeClass("x-tree-selected");
37029 addClass : function(cls){
37031 Roo.fly(this.elRow).addClass(cls);
37037 removeClass : function(cls){
37039 Roo.fly(this.elRow).removeClass(cls);
37045 });//<Script type="text/javascript">
37049 * Ext JS Library 1.1.1
37050 * Copyright(c) 2006-2007, Ext JS, LLC.
37052 * Originally Released Under LGPL - original licence link has changed is not relivant.
37055 * <script type="text/javascript">
37060 * @class Roo.tree.ColumnTree
37061 * @extends Roo.data.TreePanel
37062 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37063 * @cfg {int} borderWidth compined right/left border allowance
37065 * @param {String/HTMLElement/Element} el The container element
37066 * @param {Object} config
37068 Roo.tree.ColumnTree = function(el, config)
37070 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37074 * Fire this event on a container when it resizes
37075 * @param {int} w Width
37076 * @param {int} h Height
37080 this.on('resize', this.onResize, this);
37083 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37087 borderWidth: Roo.isBorderBox ? 0 : 2,
37090 render : function(){
37091 // add the header.....
37093 Roo.tree.ColumnTree.superclass.render.apply(this);
37095 this.el.addClass('x-column-tree');
37097 this.headers = this.el.createChild(
37098 {cls:'x-tree-headers'},this.innerCt.dom);
37100 var cols = this.columns, c;
37101 var totalWidth = 0;
37103 var len = cols.length;
37104 for(var i = 0; i < len; i++){
37106 totalWidth += c.width;
37107 this.headEls.push(this.headers.createChild({
37108 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37110 cls:'x-tree-hd-text',
37113 style:'width:'+(c.width-this.borderWidth)+'px;'
37116 this.headers.createChild({cls:'x-clear'});
37117 // prevent floats from wrapping when clipped
37118 this.headers.setWidth(totalWidth);
37119 //this.innerCt.setWidth(totalWidth);
37120 this.innerCt.setStyle({ overflow: 'auto' });
37121 this.onResize(this.width, this.height);
37125 onResize : function(w,h)
37130 this.innerCt.setWidth(this.width);
37131 this.innerCt.setHeight(this.height-20);
37134 var cols = this.columns, c;
37135 var totalWidth = 0;
37137 var len = cols.length;
37138 for(var i = 0; i < len; i++){
37140 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37141 // it's the expander..
37142 expEl = this.headEls[i];
37145 totalWidth += c.width;
37149 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37151 this.headers.setWidth(w-20);
37160 * Ext JS Library 1.1.1
37161 * Copyright(c) 2006-2007, Ext JS, LLC.
37163 * Originally Released Under LGPL - original licence link has changed is not relivant.
37166 * <script type="text/javascript">
37170 * @class Roo.menu.Menu
37171 * @extends Roo.util.Observable
37172 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37173 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37175 * Creates a new Menu
37176 * @param {Object} config Configuration options
37178 Roo.menu.Menu = function(config){
37179 Roo.apply(this, config);
37180 this.id = this.id || Roo.id();
37183 * @event beforeshow
37184 * Fires before this menu is displayed
37185 * @param {Roo.menu.Menu} this
37189 * @event beforehide
37190 * Fires before this menu is hidden
37191 * @param {Roo.menu.Menu} this
37196 * Fires after this menu is displayed
37197 * @param {Roo.menu.Menu} this
37202 * Fires after this menu is hidden
37203 * @param {Roo.menu.Menu} this
37208 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37209 * @param {Roo.menu.Menu} this
37210 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37211 * @param {Roo.EventObject} e
37216 * Fires when the mouse is hovering over this menu
37217 * @param {Roo.menu.Menu} this
37218 * @param {Roo.EventObject} e
37219 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37224 * Fires when the mouse exits this menu
37225 * @param {Roo.menu.Menu} this
37226 * @param {Roo.EventObject} e
37227 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37232 * Fires when a menu item contained in this menu is clicked
37233 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37234 * @param {Roo.EventObject} e
37238 if (this.registerMenu) {
37239 Roo.menu.MenuMgr.register(this);
37242 var mis = this.items;
37243 this.items = new Roo.util.MixedCollection();
37245 this.add.apply(this, mis);
37249 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37251 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37255 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37256 * for bottom-right shadow (defaults to "sides")
37260 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37261 * this menu (defaults to "tl-tr?")
37263 subMenuAlign : "tl-tr?",
37265 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37266 * relative to its element of origin (defaults to "tl-bl?")
37268 defaultAlign : "tl-bl?",
37270 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37272 allowOtherMenus : false,
37274 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37276 registerMenu : true,
37281 render : function(){
37285 var el = this.el = new Roo.Layer({
37287 shadow:this.shadow,
37289 parentEl: this.parentEl || document.body,
37293 this.keyNav = new Roo.menu.MenuNav(this);
37296 el.addClass("x-menu-plain");
37299 el.addClass(this.cls);
37301 // generic focus element
37302 this.focusEl = el.createChild({
37303 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37305 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37306 //disabling touch- as it's causing issues ..
37307 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37308 ul.on('click' , this.onClick, this);
37311 ul.on("mouseover", this.onMouseOver, this);
37312 ul.on("mouseout", this.onMouseOut, this);
37313 this.items.each(function(item){
37318 var li = document.createElement("li");
37319 li.className = "x-menu-list-item";
37320 ul.dom.appendChild(li);
37321 item.render(li, this);
37328 autoWidth : function(){
37329 var el = this.el, ul = this.ul;
37333 var w = this.width;
37336 }else if(Roo.isIE){
37337 el.setWidth(this.minWidth);
37338 var t = el.dom.offsetWidth; // force recalc
37339 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37344 delayAutoWidth : function(){
37347 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37349 this.awTask.delay(20);
37354 findTargetItem : function(e){
37355 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37356 if(t && t.menuItemId){
37357 return this.items.get(t.menuItemId);
37362 onClick : function(e){
37363 Roo.log("menu.onClick");
37364 var t = this.findTargetItem(e);
37369 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37370 if(t == this.activeItem && t.shouldDeactivate(e)){
37371 this.activeItem.deactivate();
37372 delete this.activeItem;
37376 this.setActiveItem(t, true);
37384 this.fireEvent("click", this, t, e);
37388 setActiveItem : function(item, autoExpand){
37389 if(item != this.activeItem){
37390 if(this.activeItem){
37391 this.activeItem.deactivate();
37393 this.activeItem = item;
37394 item.activate(autoExpand);
37395 }else if(autoExpand){
37401 tryActivate : function(start, step){
37402 var items = this.items;
37403 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37404 var item = items.get(i);
37405 if(!item.disabled && item.canActivate){
37406 this.setActiveItem(item, false);
37414 onMouseOver : function(e){
37416 if(t = this.findTargetItem(e)){
37417 if(t.canActivate && !t.disabled){
37418 this.setActiveItem(t, true);
37421 this.fireEvent("mouseover", this, e, t);
37425 onMouseOut : function(e){
37427 if(t = this.findTargetItem(e)){
37428 if(t == this.activeItem && t.shouldDeactivate(e)){
37429 this.activeItem.deactivate();
37430 delete this.activeItem;
37433 this.fireEvent("mouseout", this, e, t);
37437 * Read-only. Returns true if the menu is currently displayed, else false.
37440 isVisible : function(){
37441 return this.el && !this.hidden;
37445 * Displays this menu relative to another element
37446 * @param {String/HTMLElement/Roo.Element} element The element to align to
37447 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37448 * the element (defaults to this.defaultAlign)
37449 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37451 show : function(el, pos, parentMenu){
37452 this.parentMenu = parentMenu;
37456 this.fireEvent("beforeshow", this);
37457 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37461 * Displays this menu at a specific xy position
37462 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37463 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37465 showAt : function(xy, parentMenu, /* private: */_e){
37466 this.parentMenu = parentMenu;
37471 this.fireEvent("beforeshow", this);
37472 xy = this.el.adjustForConstraints(xy);
37476 this.hidden = false;
37478 this.fireEvent("show", this);
37481 focus : function(){
37483 this.doFocus.defer(50, this);
37487 doFocus : function(){
37489 this.focusEl.focus();
37494 * Hides this menu and optionally all parent menus
37495 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37497 hide : function(deep){
37498 if(this.el && this.isVisible()){
37499 this.fireEvent("beforehide", this);
37500 if(this.activeItem){
37501 this.activeItem.deactivate();
37502 this.activeItem = null;
37505 this.hidden = true;
37506 this.fireEvent("hide", this);
37508 if(deep === true && this.parentMenu){
37509 this.parentMenu.hide(true);
37514 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37515 * Any of the following are valid:
37517 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37518 * <li>An HTMLElement object which will be converted to a menu item</li>
37519 * <li>A menu item config object that will be created as a new menu item</li>
37520 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37521 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37526 var menu = new Roo.menu.Menu();
37528 // Create a menu item to add by reference
37529 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37531 // Add a bunch of items at once using different methods.
37532 // Only the last item added will be returned.
37533 var item = menu.add(
37534 menuItem, // add existing item by ref
37535 'Dynamic Item', // new TextItem
37536 '-', // new separator
37537 { text: 'Config Item' } // new item by config
37540 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37541 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37544 var a = arguments, l = a.length, item;
37545 for(var i = 0; i < l; i++){
37547 if ((typeof(el) == "object") && el.xtype && el.xns) {
37548 el = Roo.factory(el, Roo.menu);
37551 if(el.render){ // some kind of Item
37552 item = this.addItem(el);
37553 }else if(typeof el == "string"){ // string
37554 if(el == "separator" || el == "-"){
37555 item = this.addSeparator();
37557 item = this.addText(el);
37559 }else if(el.tagName || el.el){ // element
37560 item = this.addElement(el);
37561 }else if(typeof el == "object"){ // must be menu item config?
37562 item = this.addMenuItem(el);
37569 * Returns this menu's underlying {@link Roo.Element} object
37570 * @return {Roo.Element} The element
37572 getEl : function(){
37580 * Adds a separator bar to the menu
37581 * @return {Roo.menu.Item} The menu item that was added
37583 addSeparator : function(){
37584 return this.addItem(new Roo.menu.Separator());
37588 * Adds an {@link Roo.Element} object to the menu
37589 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37590 * @return {Roo.menu.Item} The menu item that was added
37592 addElement : function(el){
37593 return this.addItem(new Roo.menu.BaseItem(el));
37597 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37598 * @param {Roo.menu.Item} item The menu item to add
37599 * @return {Roo.menu.Item} The menu item that was added
37601 addItem : function(item){
37602 this.items.add(item);
37604 var li = document.createElement("li");
37605 li.className = "x-menu-list-item";
37606 this.ul.dom.appendChild(li);
37607 item.render(li, this);
37608 this.delayAutoWidth();
37614 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37615 * @param {Object} config A MenuItem config object
37616 * @return {Roo.menu.Item} The menu item that was added
37618 addMenuItem : function(config){
37619 if(!(config instanceof Roo.menu.Item)){
37620 if(typeof config.checked == "boolean"){ // must be check menu item config?
37621 config = new Roo.menu.CheckItem(config);
37623 config = new Roo.menu.Item(config);
37626 return this.addItem(config);
37630 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37631 * @param {String} text The text to display in the menu item
37632 * @return {Roo.menu.Item} The menu item that was added
37634 addText : function(text){
37635 return this.addItem(new Roo.menu.TextItem({ text : text }));
37639 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37640 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37641 * @param {Roo.menu.Item} item The menu item to add
37642 * @return {Roo.menu.Item} The menu item that was added
37644 insert : function(index, item){
37645 this.items.insert(index, item);
37647 var li = document.createElement("li");
37648 li.className = "x-menu-list-item";
37649 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37650 item.render(li, this);
37651 this.delayAutoWidth();
37657 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37658 * @param {Roo.menu.Item} item The menu item to remove
37660 remove : function(item){
37661 this.items.removeKey(item.id);
37666 * Removes and destroys all items in the menu
37668 removeAll : function(){
37670 while(f = this.items.first()){
37676 // MenuNav is a private utility class used internally by the Menu
37677 Roo.menu.MenuNav = function(menu){
37678 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37679 this.scope = this.menu = menu;
37682 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37683 doRelay : function(e, h){
37684 var k = e.getKey();
37685 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37686 this.menu.tryActivate(0, 1);
37689 return h.call(this.scope || this, e, this.menu);
37692 up : function(e, m){
37693 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37694 m.tryActivate(m.items.length-1, -1);
37698 down : function(e, m){
37699 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37700 m.tryActivate(0, 1);
37704 right : function(e, m){
37706 m.activeItem.expandMenu(true);
37710 left : function(e, m){
37712 if(m.parentMenu && m.parentMenu.activeItem){
37713 m.parentMenu.activeItem.activate();
37717 enter : function(e, m){
37719 e.stopPropagation();
37720 m.activeItem.onClick(e);
37721 m.fireEvent("click", this, m.activeItem);
37727 * Ext JS Library 1.1.1
37728 * Copyright(c) 2006-2007, Ext JS, LLC.
37730 * Originally Released Under LGPL - original licence link has changed is not relivant.
37733 * <script type="text/javascript">
37737 * @class Roo.menu.MenuMgr
37738 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37741 Roo.menu.MenuMgr = function(){
37742 var menus, active, groups = {}, attached = false, lastShow = new Date();
37744 // private - called when first menu is created
37747 active = new Roo.util.MixedCollection();
37748 Roo.get(document).addKeyListener(27, function(){
37749 if(active.length > 0){
37756 function hideAll(){
37757 if(active && active.length > 0){
37758 var c = active.clone();
37759 c.each(function(m){
37766 function onHide(m){
37768 if(active.length < 1){
37769 Roo.get(document).un("mousedown", onMouseDown);
37775 function onShow(m){
37776 var last = active.last();
37777 lastShow = new Date();
37780 Roo.get(document).on("mousedown", onMouseDown);
37784 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37785 m.parentMenu.activeChild = m;
37786 }else if(last && last.isVisible()){
37787 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37792 function onBeforeHide(m){
37794 m.activeChild.hide();
37796 if(m.autoHideTimer){
37797 clearTimeout(m.autoHideTimer);
37798 delete m.autoHideTimer;
37803 function onBeforeShow(m){
37804 var pm = m.parentMenu;
37805 if(!pm && !m.allowOtherMenus){
37807 }else if(pm && pm.activeChild && active != m){
37808 pm.activeChild.hide();
37813 function onMouseDown(e){
37814 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37820 function onBeforeCheck(mi, state){
37822 var g = groups[mi.group];
37823 for(var i = 0, l = g.length; i < l; i++){
37825 g[i].setChecked(false);
37834 * Hides all menus that are currently visible
37836 hideAll : function(){
37841 register : function(menu){
37845 menus[menu.id] = menu;
37846 menu.on("beforehide", onBeforeHide);
37847 menu.on("hide", onHide);
37848 menu.on("beforeshow", onBeforeShow);
37849 menu.on("show", onShow);
37850 var g = menu.group;
37851 if(g && menu.events["checkchange"]){
37855 groups[g].push(menu);
37856 menu.on("checkchange", onCheck);
37861 * Returns a {@link Roo.menu.Menu} object
37862 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37863 * be used to generate and return a new Menu instance.
37865 get : function(menu){
37866 if(typeof menu == "string"){ // menu id
37867 return menus[menu];
37868 }else if(menu.events){ // menu instance
37870 }else if(typeof menu.length == 'number'){ // array of menu items?
37871 return new Roo.menu.Menu({items:menu});
37872 }else{ // otherwise, must be a config
37873 return new Roo.menu.Menu(menu);
37878 unregister : function(menu){
37879 delete menus[menu.id];
37880 menu.un("beforehide", onBeforeHide);
37881 menu.un("hide", onHide);
37882 menu.un("beforeshow", onBeforeShow);
37883 menu.un("show", onShow);
37884 var g = menu.group;
37885 if(g && menu.events["checkchange"]){
37886 groups[g].remove(menu);
37887 menu.un("checkchange", onCheck);
37892 registerCheckable : function(menuItem){
37893 var g = menuItem.group;
37898 groups[g].push(menuItem);
37899 menuItem.on("beforecheckchange", onBeforeCheck);
37904 unregisterCheckable : function(menuItem){
37905 var g = menuItem.group;
37907 groups[g].remove(menuItem);
37908 menuItem.un("beforecheckchange", onBeforeCheck);
37914 * Ext JS Library 1.1.1
37915 * Copyright(c) 2006-2007, Ext JS, LLC.
37917 * Originally Released Under LGPL - original licence link has changed is not relivant.
37920 * <script type="text/javascript">
37925 * @class Roo.menu.BaseItem
37926 * @extends Roo.Component
37927 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37928 * management and base configuration options shared by all menu components.
37930 * Creates a new BaseItem
37931 * @param {Object} config Configuration options
37933 Roo.menu.BaseItem = function(config){
37934 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37939 * Fires when this item is clicked
37940 * @param {Roo.menu.BaseItem} this
37941 * @param {Roo.EventObject} e
37946 * Fires when this item is activated
37947 * @param {Roo.menu.BaseItem} this
37951 * @event deactivate
37952 * Fires when this item is deactivated
37953 * @param {Roo.menu.BaseItem} this
37959 this.on("click", this.handler, this.scope, true);
37963 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37965 * @cfg {Function} handler
37966 * A function that will handle the click event of this menu item (defaults to undefined)
37969 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37971 canActivate : false,
37974 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37979 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37981 activeClass : "x-menu-item-active",
37983 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37985 hideOnClick : true,
37987 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37992 ctype: "Roo.menu.BaseItem",
37995 actionMode : "container",
37998 render : function(container, parentMenu){
37999 this.parentMenu = parentMenu;
38000 Roo.menu.BaseItem.superclass.render.call(this, container);
38001 this.container.menuItemId = this.id;
38005 onRender : function(container, position){
38006 this.el = Roo.get(this.el);
38007 container.dom.appendChild(this.el.dom);
38011 onClick : function(e){
38012 if(!this.disabled && this.fireEvent("click", this, e) !== false
38013 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38014 this.handleClick(e);
38021 activate : function(){
38025 var li = this.container;
38026 li.addClass(this.activeClass);
38027 this.region = li.getRegion().adjust(2, 2, -2, -2);
38028 this.fireEvent("activate", this);
38033 deactivate : function(){
38034 this.container.removeClass(this.activeClass);
38035 this.fireEvent("deactivate", this);
38039 shouldDeactivate : function(e){
38040 return !this.region || !this.region.contains(e.getPoint());
38044 handleClick : function(e){
38045 if(this.hideOnClick){
38046 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38051 expandMenu : function(autoActivate){
38056 hideMenu : function(){
38061 * Ext JS Library 1.1.1
38062 * Copyright(c) 2006-2007, Ext JS, LLC.
38064 * Originally Released Under LGPL - original licence link has changed is not relivant.
38067 * <script type="text/javascript">
38071 * @class Roo.menu.Adapter
38072 * @extends Roo.menu.BaseItem
38073 * 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.
38074 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38076 * Creates a new Adapter
38077 * @param {Object} config Configuration options
38079 Roo.menu.Adapter = function(component, config){
38080 Roo.menu.Adapter.superclass.constructor.call(this, config);
38081 this.component = component;
38083 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38085 canActivate : true,
38088 onRender : function(container, position){
38089 this.component.render(container);
38090 this.el = this.component.getEl();
38094 activate : function(){
38098 this.component.focus();
38099 this.fireEvent("activate", this);
38104 deactivate : function(){
38105 this.fireEvent("deactivate", this);
38109 disable : function(){
38110 this.component.disable();
38111 Roo.menu.Adapter.superclass.disable.call(this);
38115 enable : function(){
38116 this.component.enable();
38117 Roo.menu.Adapter.superclass.enable.call(this);
38121 * Ext JS Library 1.1.1
38122 * Copyright(c) 2006-2007, Ext JS, LLC.
38124 * Originally Released Under LGPL - original licence link has changed is not relivant.
38127 * <script type="text/javascript">
38131 * @class Roo.menu.TextItem
38132 * @extends Roo.menu.BaseItem
38133 * Adds a static text string to a menu, usually used as either a heading or group separator.
38134 * Note: old style constructor with text is still supported.
38137 * Creates a new TextItem
38138 * @param {Object} cfg Configuration
38140 Roo.menu.TextItem = function(cfg){
38141 if (typeof(cfg) == 'string') {
38144 Roo.apply(this,cfg);
38147 Roo.menu.TextItem.superclass.constructor.call(this);
38150 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38152 * @cfg {Boolean} text Text to show on item.
38157 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38159 hideOnClick : false,
38161 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38163 itemCls : "x-menu-text",
38166 onRender : function(){
38167 var s = document.createElement("span");
38168 s.className = this.itemCls;
38169 s.innerHTML = this.text;
38171 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38175 * Ext JS Library 1.1.1
38176 * Copyright(c) 2006-2007, Ext JS, LLC.
38178 * Originally Released Under LGPL - original licence link has changed is not relivant.
38181 * <script type="text/javascript">
38185 * @class Roo.menu.Separator
38186 * @extends Roo.menu.BaseItem
38187 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38188 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38190 * @param {Object} config Configuration options
38192 Roo.menu.Separator = function(config){
38193 Roo.menu.Separator.superclass.constructor.call(this, config);
38196 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38198 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38200 itemCls : "x-menu-sep",
38202 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38204 hideOnClick : false,
38207 onRender : function(li){
38208 var s = document.createElement("span");
38209 s.className = this.itemCls;
38210 s.innerHTML = " ";
38212 li.addClass("x-menu-sep-li");
38213 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38217 * Ext JS Library 1.1.1
38218 * Copyright(c) 2006-2007, Ext JS, LLC.
38220 * Originally Released Under LGPL - original licence link has changed is not relivant.
38223 * <script type="text/javascript">
38226 * @class Roo.menu.Item
38227 * @extends Roo.menu.BaseItem
38228 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38229 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38230 * activation and click handling.
38232 * Creates a new Item
38233 * @param {Object} config Configuration options
38235 Roo.menu.Item = function(config){
38236 Roo.menu.Item.superclass.constructor.call(this, config);
38238 this.menu = Roo.menu.MenuMgr.get(this.menu);
38241 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38244 * @cfg {String} text
38245 * The text to show on the menu item.
38249 * @cfg {String} HTML to render in menu
38250 * The text to show on the menu item (HTML version).
38254 * @cfg {String} icon
38255 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38259 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38261 itemCls : "x-menu-item",
38263 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38265 canActivate : true,
38267 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38270 // doc'd in BaseItem
38274 ctype: "Roo.menu.Item",
38277 onRender : function(container, position){
38278 var el = document.createElement("a");
38279 el.hideFocus = true;
38280 el.unselectable = "on";
38281 el.href = this.href || "#";
38282 if(this.hrefTarget){
38283 el.target = this.hrefTarget;
38285 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38287 var html = this.html.length ? this.html : String.format('{0}',this.text);
38289 el.innerHTML = String.format(
38290 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38291 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38293 Roo.menu.Item.superclass.onRender.call(this, container, position);
38297 * Sets the text to display in this menu item
38298 * @param {String} text The text to display
38299 * @param {Boolean} isHTML true to indicate text is pure html.
38301 setText : function(text, isHTML){
38309 var html = this.html.length ? this.html : String.format('{0}',this.text);
38311 this.el.update(String.format(
38312 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38313 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38314 this.parentMenu.autoWidth();
38319 handleClick : function(e){
38320 if(!this.href){ // if no link defined, stop the event automatically
38323 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38327 activate : function(autoExpand){
38328 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38338 shouldDeactivate : function(e){
38339 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38340 if(this.menu && this.menu.isVisible()){
38341 return !this.menu.getEl().getRegion().contains(e.getPoint());
38349 deactivate : function(){
38350 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38355 expandMenu : function(autoActivate){
38356 if(!this.disabled && this.menu){
38357 clearTimeout(this.hideTimer);
38358 delete this.hideTimer;
38359 if(!this.menu.isVisible() && !this.showTimer){
38360 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38361 }else if (this.menu.isVisible() && autoActivate){
38362 this.menu.tryActivate(0, 1);
38368 deferExpand : function(autoActivate){
38369 delete this.showTimer;
38370 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38372 this.menu.tryActivate(0, 1);
38377 hideMenu : function(){
38378 clearTimeout(this.showTimer);
38379 delete this.showTimer;
38380 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38381 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38386 deferHide : function(){
38387 delete this.hideTimer;
38392 * Ext JS Library 1.1.1
38393 * Copyright(c) 2006-2007, Ext JS, LLC.
38395 * Originally Released Under LGPL - original licence link has changed is not relivant.
38398 * <script type="text/javascript">
38402 * @class Roo.menu.CheckItem
38403 * @extends Roo.menu.Item
38404 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38406 * Creates a new CheckItem
38407 * @param {Object} config Configuration options
38409 Roo.menu.CheckItem = function(config){
38410 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38413 * @event beforecheckchange
38414 * Fires before the checked value is set, providing an opportunity to cancel if needed
38415 * @param {Roo.menu.CheckItem} this
38416 * @param {Boolean} checked The new checked value that will be set
38418 "beforecheckchange" : true,
38420 * @event checkchange
38421 * Fires after the checked value has been set
38422 * @param {Roo.menu.CheckItem} this
38423 * @param {Boolean} checked The checked value that was set
38425 "checkchange" : true
38427 if(this.checkHandler){
38428 this.on('checkchange', this.checkHandler, this.scope);
38431 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38433 * @cfg {String} group
38434 * All check items with the same group name will automatically be grouped into a single-select
38435 * radio button group (defaults to '')
38438 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38440 itemCls : "x-menu-item x-menu-check-item",
38442 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38444 groupClass : "x-menu-group-item",
38447 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38448 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38449 * initialized with checked = true will be rendered as checked.
38454 ctype: "Roo.menu.CheckItem",
38457 onRender : function(c){
38458 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38460 this.el.addClass(this.groupClass);
38462 Roo.menu.MenuMgr.registerCheckable(this);
38464 this.checked = false;
38465 this.setChecked(true, true);
38470 destroy : function(){
38472 Roo.menu.MenuMgr.unregisterCheckable(this);
38474 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38478 * Set the checked state of this item
38479 * @param {Boolean} checked The new checked value
38480 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38482 setChecked : function(state, suppressEvent){
38483 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38484 if(this.container){
38485 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38487 this.checked = state;
38488 if(suppressEvent !== true){
38489 this.fireEvent("checkchange", this, state);
38495 handleClick : function(e){
38496 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38497 this.setChecked(!this.checked);
38499 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38503 * Ext JS Library 1.1.1
38504 * Copyright(c) 2006-2007, Ext JS, LLC.
38506 * Originally Released Under LGPL - original licence link has changed is not relivant.
38509 * <script type="text/javascript">
38513 * @class Roo.menu.DateItem
38514 * @extends Roo.menu.Adapter
38515 * A menu item that wraps the {@link Roo.DatPicker} component.
38517 * Creates a new DateItem
38518 * @param {Object} config Configuration options
38520 Roo.menu.DateItem = function(config){
38521 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38522 /** The Roo.DatePicker object @type Roo.DatePicker */
38523 this.picker = this.component;
38524 this.addEvents({select: true});
38526 this.picker.on("render", function(picker){
38527 picker.getEl().swallowEvent("click");
38528 picker.container.addClass("x-menu-date-item");
38531 this.picker.on("select", this.onSelect, this);
38534 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38536 onSelect : function(picker, date){
38537 this.fireEvent("select", this, date, picker);
38538 Roo.menu.DateItem.superclass.handleClick.call(this);
38542 * Ext JS Library 1.1.1
38543 * Copyright(c) 2006-2007, Ext JS, LLC.
38545 * Originally Released Under LGPL - original licence link has changed is not relivant.
38548 * <script type="text/javascript">
38552 * @class Roo.menu.ColorItem
38553 * @extends Roo.menu.Adapter
38554 * A menu item that wraps the {@link Roo.ColorPalette} component.
38556 * Creates a new ColorItem
38557 * @param {Object} config Configuration options
38559 Roo.menu.ColorItem = function(config){
38560 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38561 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38562 this.palette = this.component;
38563 this.relayEvents(this.palette, ["select"]);
38564 if(this.selectHandler){
38565 this.on('select', this.selectHandler, this.scope);
38568 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38570 * Ext JS Library 1.1.1
38571 * Copyright(c) 2006-2007, Ext JS, LLC.
38573 * Originally Released Under LGPL - original licence link has changed is not relivant.
38576 * <script type="text/javascript">
38581 * @class Roo.menu.DateMenu
38582 * @extends Roo.menu.Menu
38583 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38585 * Creates a new DateMenu
38586 * @param {Object} config Configuration options
38588 Roo.menu.DateMenu = function(config){
38589 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38591 var di = new Roo.menu.DateItem(config);
38594 * The {@link Roo.DatePicker} instance for this DateMenu
38597 this.picker = di.picker;
38600 * @param {DatePicker} picker
38601 * @param {Date} date
38603 this.relayEvents(di, ["select"]);
38604 this.on('beforeshow', function(){
38606 this.picker.hideMonthPicker(false);
38610 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38614 * Ext JS Library 1.1.1
38615 * Copyright(c) 2006-2007, Ext JS, LLC.
38617 * Originally Released Under LGPL - original licence link has changed is not relivant.
38620 * <script type="text/javascript">
38625 * @class Roo.menu.ColorMenu
38626 * @extends Roo.menu.Menu
38627 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38629 * Creates a new ColorMenu
38630 * @param {Object} config Configuration options
38632 Roo.menu.ColorMenu = function(config){
38633 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38635 var ci = new Roo.menu.ColorItem(config);
38638 * The {@link Roo.ColorPalette} instance for this ColorMenu
38639 * @type ColorPalette
38641 this.palette = ci.palette;
38644 * @param {ColorPalette} palette
38645 * @param {String} color
38647 this.relayEvents(ci, ["select"]);
38649 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38651 * Ext JS Library 1.1.1
38652 * Copyright(c) 2006-2007, Ext JS, LLC.
38654 * Originally Released Under LGPL - original licence link has changed is not relivant.
38657 * <script type="text/javascript">
38661 * @class Roo.form.Field
38662 * @extends Roo.BoxComponent
38663 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38665 * Creates a new Field
38666 * @param {Object} config Configuration options
38668 Roo.form.Field = function(config){
38669 Roo.form.Field.superclass.constructor.call(this, config);
38672 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38674 * @cfg {String} fieldLabel Label to use when rendering a form.
38677 * @cfg {String} qtip Mouse over tip
38681 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38683 invalidClass : "x-form-invalid",
38685 * @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")
38687 invalidText : "The value in this field is invalid",
38689 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38691 focusClass : "x-form-focus",
38693 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38694 automatic validation (defaults to "keyup").
38696 validationEvent : "keyup",
38698 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38700 validateOnBlur : true,
38702 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38704 validationDelay : 250,
38706 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38707 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38709 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38711 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38713 fieldClass : "x-form-field",
38715 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38718 ----------- ----------------------------------------------------------------------
38719 qtip Display a quick tip when the user hovers over the field
38720 title Display a default browser title attribute popup
38721 under Add a block div beneath the field containing the error text
38722 side Add an error icon to the right of the field with a popup on hover
38723 [element id] Add the error text directly to the innerHTML of the specified element
38726 msgTarget : 'qtip',
38728 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38733 * @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.
38738 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38743 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38745 inputType : undefined,
38748 * @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).
38750 tabIndex : undefined,
38753 isFormField : true,
38758 * @property {Roo.Element} fieldEl
38759 * Element Containing the rendered Field (with label etc.)
38762 * @cfg {Mixed} value A value to initialize this field with.
38767 * @cfg {String} name The field's HTML name attribute.
38770 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38773 loadedValue : false,
38777 initComponent : function(){
38778 Roo.form.Field.superclass.initComponent.call(this);
38782 * Fires when this field receives input focus.
38783 * @param {Roo.form.Field} this
38788 * Fires when this field loses input focus.
38789 * @param {Roo.form.Field} this
38793 * @event specialkey
38794 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38795 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38796 * @param {Roo.form.Field} this
38797 * @param {Roo.EventObject} e The event object
38802 * Fires just before the field blurs if the field value has changed.
38803 * @param {Roo.form.Field} this
38804 * @param {Mixed} newValue The new value
38805 * @param {Mixed} oldValue The original value
38810 * Fires after the field has been marked as invalid.
38811 * @param {Roo.form.Field} this
38812 * @param {String} msg The validation message
38817 * Fires after the field has been validated with no errors.
38818 * @param {Roo.form.Field} this
38823 * Fires after the key up
38824 * @param {Roo.form.Field} this
38825 * @param {Roo.EventObject} e The event Object
38832 * Returns the name attribute of the field if available
38833 * @return {String} name The field name
38835 getName: function(){
38836 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38840 onRender : function(ct, position){
38841 Roo.form.Field.superclass.onRender.call(this, ct, position);
38843 var cfg = this.getAutoCreate();
38845 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38847 if (!cfg.name.length) {
38850 if(this.inputType){
38851 cfg.type = this.inputType;
38853 this.el = ct.createChild(cfg, position);
38855 var type = this.el.dom.type;
38857 if(type == 'password'){
38860 this.el.addClass('x-form-'+type);
38863 this.el.dom.readOnly = true;
38865 if(this.tabIndex !== undefined){
38866 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38869 this.el.addClass([this.fieldClass, this.cls]);
38874 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38875 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38876 * @return {Roo.form.Field} this
38878 applyTo : function(target){
38879 this.allowDomMove = false;
38880 this.el = Roo.get(target);
38881 this.render(this.el.dom.parentNode);
38886 initValue : function(){
38887 if(this.value !== undefined){
38888 this.setValue(this.value);
38889 }else if(this.el.dom.value.length > 0){
38890 this.setValue(this.el.dom.value);
38895 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38896 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38898 isDirty : function() {
38899 if(this.disabled) {
38902 return String(this.getValue()) !== String(this.originalValue);
38906 * stores the current value in loadedValue
38908 resetHasChanged : function()
38910 this.loadedValue = String(this.getValue());
38913 * checks the current value against the 'loaded' value.
38914 * Note - will return false if 'resetHasChanged' has not been called first.
38916 hasChanged : function()
38918 if(this.disabled || this.readOnly) {
38921 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38927 afterRender : function(){
38928 Roo.form.Field.superclass.afterRender.call(this);
38933 fireKey : function(e){
38934 //Roo.log('field ' + e.getKey());
38935 if(e.isNavKeyPress()){
38936 this.fireEvent("specialkey", this, e);
38941 * Resets the current field value to the originally loaded value and clears any validation messages
38943 reset : function(){
38944 this.setValue(this.resetValue);
38945 this.originalValue = this.getValue();
38946 this.clearInvalid();
38950 initEvents : function(){
38951 // safari killled keypress - so keydown is now used..
38952 this.el.on("keydown" , this.fireKey, this);
38953 this.el.on("focus", this.onFocus, this);
38954 this.el.on("blur", this.onBlur, this);
38955 this.el.relayEvent('keyup', this);
38957 // reference to original value for reset
38958 this.originalValue = this.getValue();
38959 this.resetValue = this.getValue();
38963 onFocus : function(){
38964 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38965 this.el.addClass(this.focusClass);
38967 if(!this.hasFocus){
38968 this.hasFocus = true;
38969 this.startValue = this.getValue();
38970 this.fireEvent("focus", this);
38974 beforeBlur : Roo.emptyFn,
38977 onBlur : function(){
38979 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38980 this.el.removeClass(this.focusClass);
38982 this.hasFocus = false;
38983 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38986 var v = this.getValue();
38987 if(String(v) !== String(this.startValue)){
38988 this.fireEvent('change', this, v, this.startValue);
38990 this.fireEvent("blur", this);
38994 * Returns whether or not the field value is currently valid
38995 * @param {Boolean} preventMark True to disable marking the field invalid
38996 * @return {Boolean} True if the value is valid, else false
38998 isValid : function(preventMark){
39002 var restore = this.preventMark;
39003 this.preventMark = preventMark === true;
39004 var v = this.validateValue(this.processValue(this.getRawValue()));
39005 this.preventMark = restore;
39010 * Validates the field value
39011 * @return {Boolean} True if the value is valid, else false
39013 validate : function(){
39014 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39015 this.clearInvalid();
39021 processValue : function(value){
39026 // Subclasses should provide the validation implementation by overriding this
39027 validateValue : function(value){
39032 * Mark this field as invalid
39033 * @param {String} msg The validation message
39035 markInvalid : function(msg){
39036 if(!this.rendered || this.preventMark){ // not rendered
39040 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39042 obj.el.addClass(this.invalidClass);
39043 msg = msg || this.invalidText;
39044 switch(this.msgTarget){
39046 obj.el.dom.qtip = msg;
39047 obj.el.dom.qclass = 'x-form-invalid-tip';
39048 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39049 Roo.QuickTips.enable();
39053 this.el.dom.title = msg;
39057 var elp = this.el.findParent('.x-form-element', 5, true);
39058 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39059 this.errorEl.setWidth(elp.getWidth(true)-20);
39061 this.errorEl.update(msg);
39062 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39065 if(!this.errorIcon){
39066 var elp = this.el.findParent('.x-form-element', 5, true);
39067 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39069 this.alignErrorIcon();
39070 this.errorIcon.dom.qtip = msg;
39071 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39072 this.errorIcon.show();
39073 this.on('resize', this.alignErrorIcon, this);
39076 var t = Roo.getDom(this.msgTarget);
39078 t.style.display = this.msgDisplay;
39081 this.fireEvent('invalid', this, msg);
39085 alignErrorIcon : function(){
39086 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39090 * Clear any invalid styles/messages for this field
39092 clearInvalid : function(){
39093 if(!this.rendered || this.preventMark){ // not rendered
39096 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39098 obj.el.removeClass(this.invalidClass);
39099 switch(this.msgTarget){
39101 obj.el.dom.qtip = '';
39104 this.el.dom.title = '';
39108 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39112 if(this.errorIcon){
39113 this.errorIcon.dom.qtip = '';
39114 this.errorIcon.hide();
39115 this.un('resize', this.alignErrorIcon, this);
39119 var t = Roo.getDom(this.msgTarget);
39121 t.style.display = 'none';
39124 this.fireEvent('valid', this);
39128 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39129 * @return {Mixed} value The field value
39131 getRawValue : function(){
39132 var v = this.el.getValue();
39138 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39139 * @return {Mixed} value The field value
39141 getValue : function(){
39142 var v = this.el.getValue();
39148 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39149 * @param {Mixed} value The value to set
39151 setRawValue : function(v){
39152 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39156 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39157 * @param {Mixed} value The value to set
39159 setValue : function(v){
39162 this.el.dom.value = (v === null || v === undefined ? '' : v);
39167 adjustSize : function(w, h){
39168 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39169 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39173 adjustWidth : function(tag, w){
39174 tag = tag.toLowerCase();
39175 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39176 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39177 if(tag == 'input'){
39180 if(tag == 'textarea'){
39183 }else if(Roo.isOpera){
39184 if(tag == 'input'){
39187 if(tag == 'textarea'){
39197 // anything other than normal should be considered experimental
39198 Roo.form.Field.msgFx = {
39200 show: function(msgEl, f){
39201 msgEl.setDisplayed('block');
39204 hide : function(msgEl, f){
39205 msgEl.setDisplayed(false).update('');
39210 show: function(msgEl, f){
39211 msgEl.slideIn('t', {stopFx:true});
39214 hide : function(msgEl, f){
39215 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39220 show: function(msgEl, f){
39221 msgEl.fixDisplay();
39222 msgEl.alignTo(f.el, 'tl-tr');
39223 msgEl.slideIn('l', {stopFx:true});
39226 hide : function(msgEl, f){
39227 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39232 * Ext JS Library 1.1.1
39233 * Copyright(c) 2006-2007, Ext JS, LLC.
39235 * Originally Released Under LGPL - original licence link has changed is not relivant.
39238 * <script type="text/javascript">
39243 * @class Roo.form.TextField
39244 * @extends Roo.form.Field
39245 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39246 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39248 * Creates a new TextField
39249 * @param {Object} config Configuration options
39251 Roo.form.TextField = function(config){
39252 Roo.form.TextField.superclass.constructor.call(this, config);
39256 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39257 * according to the default logic, but this event provides a hook for the developer to apply additional
39258 * logic at runtime to resize the field if needed.
39259 * @param {Roo.form.Field} this This text field
39260 * @param {Number} width The new field width
39266 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39268 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39272 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39276 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39280 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39284 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39288 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39290 disableKeyFilter : false,
39292 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39296 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39300 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39302 maxLength : Number.MAX_VALUE,
39304 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39306 minLengthText : "The minimum length for this field is {0}",
39308 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39310 maxLengthText : "The maximum length for this field is {0}",
39312 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39314 selectOnFocus : false,
39316 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39318 blankText : "This field is required",
39320 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39321 * If available, this function will be called only after the basic validators all return true, and will be passed the
39322 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39326 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39327 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39328 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39332 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39336 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39342 initEvents : function()
39344 if (this.emptyText) {
39345 this.el.attr('placeholder', this.emptyText);
39348 Roo.form.TextField.superclass.initEvents.call(this);
39349 if(this.validationEvent == 'keyup'){
39350 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39351 this.el.on('keyup', this.filterValidation, this);
39353 else if(this.validationEvent !== false){
39354 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39357 if(this.selectOnFocus){
39358 this.on("focus", this.preFocus, this);
39361 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39362 this.el.on("keypress", this.filterKeys, this);
39365 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39366 this.el.on("click", this.autoSize, this);
39368 if(this.el.is('input[type=password]') && Roo.isSafari){
39369 this.el.on('keydown', this.SafariOnKeyDown, this);
39373 processValue : function(value){
39374 if(this.stripCharsRe){
39375 var newValue = value.replace(this.stripCharsRe, '');
39376 if(newValue !== value){
39377 this.setRawValue(newValue);
39384 filterValidation : function(e){
39385 if(!e.isNavKeyPress()){
39386 this.validationTask.delay(this.validationDelay);
39391 onKeyUp : function(e){
39392 if(!e.isNavKeyPress()){
39398 * Resets the current field value to the originally-loaded value and clears any validation messages.
39401 reset : function(){
39402 Roo.form.TextField.superclass.reset.call(this);
39408 preFocus : function(){
39410 if(this.selectOnFocus){
39411 this.el.dom.select();
39417 filterKeys : function(e){
39418 var k = e.getKey();
39419 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39422 var c = e.getCharCode(), cc = String.fromCharCode(c);
39423 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39426 if(!this.maskRe.test(cc)){
39431 setValue : function(v){
39433 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39439 * Validates a value according to the field's validation rules and marks the field as invalid
39440 * if the validation fails
39441 * @param {Mixed} value The value to validate
39442 * @return {Boolean} True if the value is valid, else false
39444 validateValue : function(value){
39445 if(value.length < 1) { // if it's blank
39446 if(this.allowBlank){
39447 this.clearInvalid();
39450 this.markInvalid(this.blankText);
39454 if(value.length < this.minLength){
39455 this.markInvalid(String.format(this.minLengthText, this.minLength));
39458 if(value.length > this.maxLength){
39459 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39463 var vt = Roo.form.VTypes;
39464 if(!vt[this.vtype](value, this)){
39465 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39469 if(typeof this.validator == "function"){
39470 var msg = this.validator(value);
39472 this.markInvalid(msg);
39476 if(this.regex && !this.regex.test(value)){
39477 this.markInvalid(this.regexText);
39484 * Selects text in this field
39485 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39486 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39488 selectText : function(start, end){
39489 var v = this.getRawValue();
39491 start = start === undefined ? 0 : start;
39492 end = end === undefined ? v.length : end;
39493 var d = this.el.dom;
39494 if(d.setSelectionRange){
39495 d.setSelectionRange(start, end);
39496 }else if(d.createTextRange){
39497 var range = d.createTextRange();
39498 range.moveStart("character", start);
39499 range.moveEnd("character", v.length-end);
39506 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39507 * This only takes effect if grow = true, and fires the autosize event.
39509 autoSize : function(){
39510 if(!this.grow || !this.rendered){
39514 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39517 var v = el.dom.value;
39518 var d = document.createElement('div');
39519 d.appendChild(document.createTextNode(v));
39523 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39524 this.el.setWidth(w);
39525 this.fireEvent("autosize", this, w);
39529 SafariOnKeyDown : function(event)
39531 // this is a workaround for a password hang bug on chrome/ webkit.
39533 var isSelectAll = false;
39535 if(this.el.dom.selectionEnd > 0){
39536 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39538 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39539 event.preventDefault();
39544 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39546 event.preventDefault();
39547 // this is very hacky as keydown always get's upper case.
39549 var cc = String.fromCharCode(event.getCharCode());
39552 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39560 * Ext JS Library 1.1.1
39561 * Copyright(c) 2006-2007, Ext JS, LLC.
39563 * Originally Released Under LGPL - original licence link has changed is not relivant.
39566 * <script type="text/javascript">
39570 * @class Roo.form.Hidden
39571 * @extends Roo.form.TextField
39572 * Simple Hidden element used on forms
39574 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39577 * Creates a new Hidden form element.
39578 * @param {Object} config Configuration options
39583 // easy hidden field...
39584 Roo.form.Hidden = function(config){
39585 Roo.form.Hidden.superclass.constructor.call(this, config);
39588 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39590 inputType: 'hidden',
39593 labelSeparator: '',
39595 itemCls : 'x-form-item-display-none'
39603 * Ext JS Library 1.1.1
39604 * Copyright(c) 2006-2007, Ext JS, LLC.
39606 * Originally Released Under LGPL - original licence link has changed is not relivant.
39609 * <script type="text/javascript">
39613 * @class Roo.form.TriggerField
39614 * @extends Roo.form.TextField
39615 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39616 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39617 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39618 * for which you can provide a custom implementation. For example:
39620 var trigger = new Roo.form.TriggerField();
39621 trigger.onTriggerClick = myTriggerFn;
39622 trigger.applyTo('my-field');
39625 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39626 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39627 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39628 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39630 * Create a new TriggerField.
39631 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39632 * to the base TextField)
39634 Roo.form.TriggerField = function(config){
39635 this.mimicing = false;
39636 Roo.form.TriggerField.superclass.constructor.call(this, config);
39639 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39641 * @cfg {String} triggerClass A CSS class to apply to the trigger
39644 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39645 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39647 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39649 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39653 /** @cfg {Boolean} grow @hide */
39654 /** @cfg {Number} growMin @hide */
39655 /** @cfg {Number} growMax @hide */
39661 autoSize: Roo.emptyFn,
39665 deferHeight : true,
39668 actionMode : 'wrap',
39670 onResize : function(w, h){
39671 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39672 if(typeof w == 'number'){
39673 var x = w - this.trigger.getWidth();
39674 this.el.setWidth(this.adjustWidth('input', x));
39675 this.trigger.setStyle('left', x+'px');
39680 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39683 getResizeEl : function(){
39688 getPositionEl : function(){
39693 alignErrorIcon : function(){
39694 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39698 onRender : function(ct, position){
39699 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39700 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39701 this.trigger = this.wrap.createChild(this.triggerConfig ||
39702 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39703 if(this.hideTrigger){
39704 this.trigger.setDisplayed(false);
39706 this.initTrigger();
39708 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39713 initTrigger : function(){
39714 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39715 this.trigger.addClassOnOver('x-form-trigger-over');
39716 this.trigger.addClassOnClick('x-form-trigger-click');
39720 onDestroy : function(){
39722 this.trigger.removeAllListeners();
39723 this.trigger.remove();
39726 this.wrap.remove();
39728 Roo.form.TriggerField.superclass.onDestroy.call(this);
39732 onFocus : function(){
39733 Roo.form.TriggerField.superclass.onFocus.call(this);
39734 if(!this.mimicing){
39735 this.wrap.addClass('x-trigger-wrap-focus');
39736 this.mimicing = true;
39737 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39738 if(this.monitorTab){
39739 this.el.on("keydown", this.checkTab, this);
39745 checkTab : function(e){
39746 if(e.getKey() == e.TAB){
39747 this.triggerBlur();
39752 onBlur : function(){
39757 mimicBlur : function(e, t){
39758 if(!this.wrap.contains(t) && this.validateBlur()){
39759 this.triggerBlur();
39764 triggerBlur : function(){
39765 this.mimicing = false;
39766 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39767 if(this.monitorTab){
39768 this.el.un("keydown", this.checkTab, this);
39770 this.wrap.removeClass('x-trigger-wrap-focus');
39771 Roo.form.TriggerField.superclass.onBlur.call(this);
39775 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39776 validateBlur : function(e, t){
39781 onDisable : function(){
39782 Roo.form.TriggerField.superclass.onDisable.call(this);
39784 this.wrap.addClass('x-item-disabled');
39789 onEnable : function(){
39790 Roo.form.TriggerField.superclass.onEnable.call(this);
39792 this.wrap.removeClass('x-item-disabled');
39797 onShow : function(){
39798 var ae = this.getActionEl();
39801 ae.dom.style.display = '';
39802 ae.dom.style.visibility = 'visible';
39808 onHide : function(){
39809 var ae = this.getActionEl();
39810 ae.dom.style.display = 'none';
39814 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39815 * by an implementing function.
39817 * @param {EventObject} e
39819 onTriggerClick : Roo.emptyFn
39822 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39823 // to be extended by an implementing class. For an example of implementing this class, see the custom
39824 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39825 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39826 initComponent : function(){
39827 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39829 this.triggerConfig = {
39830 tag:'span', cls:'x-form-twin-triggers', cn:[
39831 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39832 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39836 getTrigger : function(index){
39837 return this.triggers[index];
39840 initTrigger : function(){
39841 var ts = this.trigger.select('.x-form-trigger', true);
39842 this.wrap.setStyle('overflow', 'hidden');
39843 var triggerField = this;
39844 ts.each(function(t, all, index){
39845 t.hide = function(){
39846 var w = triggerField.wrap.getWidth();
39847 this.dom.style.display = 'none';
39848 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39850 t.show = function(){
39851 var w = triggerField.wrap.getWidth();
39852 this.dom.style.display = '';
39853 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39855 var triggerIndex = 'Trigger'+(index+1);
39857 if(this['hide'+triggerIndex]){
39858 t.dom.style.display = 'none';
39860 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39861 t.addClassOnOver('x-form-trigger-over');
39862 t.addClassOnClick('x-form-trigger-click');
39864 this.triggers = ts.elements;
39867 onTrigger1Click : Roo.emptyFn,
39868 onTrigger2Click : Roo.emptyFn
39871 * Ext JS Library 1.1.1
39872 * Copyright(c) 2006-2007, Ext JS, LLC.
39874 * Originally Released Under LGPL - original licence link has changed is not relivant.
39877 * <script type="text/javascript">
39881 * @class Roo.form.TextArea
39882 * @extends Roo.form.TextField
39883 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39884 * support for auto-sizing.
39886 * Creates a new TextArea
39887 * @param {Object} config Configuration options
39889 Roo.form.TextArea = function(config){
39890 Roo.form.TextArea.superclass.constructor.call(this, config);
39891 // these are provided exchanges for backwards compat
39892 // minHeight/maxHeight were replaced by growMin/growMax to be
39893 // compatible with TextField growing config values
39894 if(this.minHeight !== undefined){
39895 this.growMin = this.minHeight;
39897 if(this.maxHeight !== undefined){
39898 this.growMax = this.maxHeight;
39902 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39904 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39908 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39912 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39913 * in the field (equivalent to setting overflow: hidden, defaults to false)
39915 preventScrollbars: false,
39917 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39918 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39922 onRender : function(ct, position){
39924 this.defaultAutoCreate = {
39926 style:"width:300px;height:60px;",
39927 autocomplete: "new-password"
39930 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39932 this.textSizeEl = Roo.DomHelper.append(document.body, {
39933 tag: "pre", cls: "x-form-grow-sizer"
39935 if(this.preventScrollbars){
39936 this.el.setStyle("overflow", "hidden");
39938 this.el.setHeight(this.growMin);
39942 onDestroy : function(){
39943 if(this.textSizeEl){
39944 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39946 Roo.form.TextArea.superclass.onDestroy.call(this);
39950 onKeyUp : function(e){
39951 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39957 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39958 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39960 autoSize : function(){
39961 if(!this.grow || !this.textSizeEl){
39965 var v = el.dom.value;
39966 var ts = this.textSizeEl;
39969 ts.appendChild(document.createTextNode(v));
39972 Roo.fly(ts).setWidth(this.el.getWidth());
39974 v = "  ";
39977 v = v.replace(/\n/g, '<p> </p>');
39979 v += " \n ";
39982 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39983 if(h != this.lastHeight){
39984 this.lastHeight = h;
39985 this.el.setHeight(h);
39986 this.fireEvent("autosize", this, h);
39991 * Ext JS Library 1.1.1
39992 * Copyright(c) 2006-2007, Ext JS, LLC.
39994 * Originally Released Under LGPL - original licence link has changed is not relivant.
39997 * <script type="text/javascript">
40002 * @class Roo.form.NumberField
40003 * @extends Roo.form.TextField
40004 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40006 * Creates a new NumberField
40007 * @param {Object} config Configuration options
40009 Roo.form.NumberField = function(config){
40010 Roo.form.NumberField.superclass.constructor.call(this, config);
40013 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40015 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40017 fieldClass: "x-form-field x-form-num-field",
40019 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40021 allowDecimals : true,
40023 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40025 decimalSeparator : ".",
40027 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40029 decimalPrecision : 2,
40031 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40033 allowNegative : true,
40035 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40037 minValue : Number.NEGATIVE_INFINITY,
40039 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40041 maxValue : Number.MAX_VALUE,
40043 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40045 minText : "The minimum value for this field is {0}",
40047 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40049 maxText : "The maximum value for this field is {0}",
40051 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40052 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40054 nanText : "{0} is not a valid number",
40057 initEvents : function(){
40058 Roo.form.NumberField.superclass.initEvents.call(this);
40059 var allowed = "0123456789";
40060 if(this.allowDecimals){
40061 allowed += this.decimalSeparator;
40063 if(this.allowNegative){
40066 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40067 var keyPress = function(e){
40068 var k = e.getKey();
40069 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40072 var c = e.getCharCode();
40073 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40077 this.el.on("keypress", keyPress, this);
40081 validateValue : function(value){
40082 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40085 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40088 var num = this.parseValue(value);
40090 this.markInvalid(String.format(this.nanText, value));
40093 if(num < this.minValue){
40094 this.markInvalid(String.format(this.minText, this.minValue));
40097 if(num > this.maxValue){
40098 this.markInvalid(String.format(this.maxText, this.maxValue));
40104 getValue : function(){
40105 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40109 parseValue : function(value){
40110 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40111 return isNaN(value) ? '' : value;
40115 fixPrecision : function(value){
40116 var nan = isNaN(value);
40117 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40118 return nan ? '' : value;
40120 return parseFloat(value).toFixed(this.decimalPrecision);
40123 setValue : function(v){
40124 v = this.fixPrecision(v);
40125 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40129 decimalPrecisionFcn : function(v){
40130 return Math.floor(v);
40133 beforeBlur : function(){
40134 var v = this.parseValue(this.getRawValue());
40141 * Ext JS Library 1.1.1
40142 * Copyright(c) 2006-2007, Ext JS, LLC.
40144 * Originally Released Under LGPL - original licence link has changed is not relivant.
40147 * <script type="text/javascript">
40151 * @class Roo.form.DateField
40152 * @extends Roo.form.TriggerField
40153 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40155 * Create a new DateField
40156 * @param {Object} config
40158 Roo.form.DateField = function(config){
40159 Roo.form.DateField.superclass.constructor.call(this, config);
40165 * Fires when a date is selected
40166 * @param {Roo.form.DateField} combo This combo box
40167 * @param {Date} date The date selected
40174 if(typeof this.minValue == "string") {
40175 this.minValue = this.parseDate(this.minValue);
40177 if(typeof this.maxValue == "string") {
40178 this.maxValue = this.parseDate(this.maxValue);
40180 this.ddMatch = null;
40181 if(this.disabledDates){
40182 var dd = this.disabledDates;
40184 for(var i = 0; i < dd.length; i++){
40186 if(i != dd.length-1) {
40190 this.ddMatch = new RegExp(re + ")");
40194 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40196 * @cfg {String} format
40197 * The default date format string which can be overriden for localization support. The format must be
40198 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40202 * @cfg {String} altFormats
40203 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40204 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40206 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40208 * @cfg {Array} disabledDays
40209 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40211 disabledDays : null,
40213 * @cfg {String} disabledDaysText
40214 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40216 disabledDaysText : "Disabled",
40218 * @cfg {Array} disabledDates
40219 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40220 * expression so they are very powerful. Some examples:
40222 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40223 * <li>["03/08", "09/16"] would disable those days for every year</li>
40224 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40225 * <li>["03/../2006"] would disable every day in March 2006</li>
40226 * <li>["^03"] would disable every day in every March</li>
40228 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40229 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40231 disabledDates : null,
40233 * @cfg {String} disabledDatesText
40234 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40236 disabledDatesText : "Disabled",
40238 * @cfg {Date/String} minValue
40239 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40240 * valid format (defaults to null).
40244 * @cfg {Date/String} maxValue
40245 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40246 * valid format (defaults to null).
40250 * @cfg {String} minText
40251 * The error text to display when the date in the cell is before minValue (defaults to
40252 * 'The date in this field must be after {minValue}').
40254 minText : "The date in this field must be equal to or after {0}",
40256 * @cfg {String} maxText
40257 * The error text to display when the date in the cell is after maxValue (defaults to
40258 * 'The date in this field must be before {maxValue}').
40260 maxText : "The date in this field must be equal to or before {0}",
40262 * @cfg {String} invalidText
40263 * The error text to display when the date in the field is invalid (defaults to
40264 * '{value} is not a valid date - it must be in the format {format}').
40266 invalidText : "{0} is not a valid date - it must be in the format {1}",
40268 * @cfg {String} triggerClass
40269 * An additional CSS class used to style the trigger button. The trigger will always get the
40270 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40271 * which displays a calendar icon).
40273 triggerClass : 'x-form-date-trigger',
40277 * @cfg {Boolean} useIso
40278 * if enabled, then the date field will use a hidden field to store the
40279 * real value as iso formated date. default (false)
40283 * @cfg {String/Object} autoCreate
40284 * A DomHelper element spec, or true for a default element spec (defaults to
40285 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40288 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40291 hiddenField: false,
40293 onRender : function(ct, position)
40295 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40297 //this.el.dom.removeAttribute('name');
40298 Roo.log("Changing name?");
40299 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40300 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40302 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40303 // prevent input submission
40304 this.hiddenName = this.name;
40311 validateValue : function(value)
40313 value = this.formatDate(value);
40314 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40315 Roo.log('super failed');
40318 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40321 var svalue = value;
40322 value = this.parseDate(value);
40324 Roo.log('parse date failed' + svalue);
40325 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40328 var time = value.getTime();
40329 if(this.minValue && time < this.minValue.getTime()){
40330 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40333 if(this.maxValue && time > this.maxValue.getTime()){
40334 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40337 if(this.disabledDays){
40338 var day = value.getDay();
40339 for(var i = 0; i < this.disabledDays.length; i++) {
40340 if(day === this.disabledDays[i]){
40341 this.markInvalid(this.disabledDaysText);
40346 var fvalue = this.formatDate(value);
40347 if(this.ddMatch && this.ddMatch.test(fvalue)){
40348 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40355 // Provides logic to override the default TriggerField.validateBlur which just returns true
40356 validateBlur : function(){
40357 return !this.menu || !this.menu.isVisible();
40360 getName: function()
40362 // returns hidden if it's set..
40363 if (!this.rendered) {return ''};
40364 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40369 * Returns the current date value of the date field.
40370 * @return {Date} The date value
40372 getValue : function(){
40374 return this.hiddenField ?
40375 this.hiddenField.value :
40376 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40380 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40381 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40382 * (the default format used is "m/d/y").
40385 //All of these calls set the same date value (May 4, 2006)
40387 //Pass a date object:
40388 var dt = new Date('5/4/06');
40389 dateField.setValue(dt);
40391 //Pass a date string (default format):
40392 dateField.setValue('5/4/06');
40394 //Pass a date string (custom format):
40395 dateField.format = 'Y-m-d';
40396 dateField.setValue('2006-5-4');
40398 * @param {String/Date} date The date or valid date string
40400 setValue : function(date){
40401 if (this.hiddenField) {
40402 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40404 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40405 // make sure the value field is always stored as a date..
40406 this.value = this.parseDate(date);
40412 parseDate : function(value){
40413 if(!value || value instanceof Date){
40416 var v = Date.parseDate(value, this.format);
40417 if (!v && this.useIso) {
40418 v = Date.parseDate(value, 'Y-m-d');
40420 if(!v && this.altFormats){
40421 if(!this.altFormatsArray){
40422 this.altFormatsArray = this.altFormats.split("|");
40424 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40425 v = Date.parseDate(value, this.altFormatsArray[i]);
40432 formatDate : function(date, fmt){
40433 return (!date || !(date instanceof Date)) ?
40434 date : date.dateFormat(fmt || this.format);
40439 select: function(m, d){
40442 this.fireEvent('select', this, d);
40444 show : function(){ // retain focus styling
40448 this.focus.defer(10, this);
40449 var ml = this.menuListeners;
40450 this.menu.un("select", ml.select, this);
40451 this.menu.un("show", ml.show, this);
40452 this.menu.un("hide", ml.hide, this);
40457 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40458 onTriggerClick : function(){
40462 if(this.menu == null){
40463 this.menu = new Roo.menu.DateMenu();
40465 Roo.apply(this.menu.picker, {
40466 showClear: this.allowBlank,
40467 minDate : this.minValue,
40468 maxDate : this.maxValue,
40469 disabledDatesRE : this.ddMatch,
40470 disabledDatesText : this.disabledDatesText,
40471 disabledDays : this.disabledDays,
40472 disabledDaysText : this.disabledDaysText,
40473 format : this.useIso ? 'Y-m-d' : this.format,
40474 minText : String.format(this.minText, this.formatDate(this.minValue)),
40475 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40477 this.menu.on(Roo.apply({}, this.menuListeners, {
40480 this.menu.picker.setValue(this.getValue() || new Date());
40481 this.menu.show(this.el, "tl-bl?");
40484 beforeBlur : function(){
40485 var v = this.parseDate(this.getRawValue());
40495 isDirty : function() {
40496 if(this.disabled) {
40500 if(typeof(this.startValue) === 'undefined'){
40504 return String(this.getValue()) !== String(this.startValue);
40509 * Ext JS Library 1.1.1
40510 * Copyright(c) 2006-2007, Ext JS, LLC.
40512 * Originally Released Under LGPL - original licence link has changed is not relivant.
40515 * <script type="text/javascript">
40519 * @class Roo.form.MonthField
40520 * @extends Roo.form.TriggerField
40521 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40523 * Create a new MonthField
40524 * @param {Object} config
40526 Roo.form.MonthField = function(config){
40528 Roo.form.MonthField.superclass.constructor.call(this, config);
40534 * Fires when a date is selected
40535 * @param {Roo.form.MonthFieeld} combo This combo box
40536 * @param {Date} date The date selected
40543 if(typeof this.minValue == "string") {
40544 this.minValue = this.parseDate(this.minValue);
40546 if(typeof this.maxValue == "string") {
40547 this.maxValue = this.parseDate(this.maxValue);
40549 this.ddMatch = null;
40550 if(this.disabledDates){
40551 var dd = this.disabledDates;
40553 for(var i = 0; i < dd.length; i++){
40555 if(i != dd.length-1) {
40559 this.ddMatch = new RegExp(re + ")");
40563 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40565 * @cfg {String} format
40566 * The default date format string which can be overriden for localization support. The format must be
40567 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40571 * @cfg {String} altFormats
40572 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40573 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40575 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40577 * @cfg {Array} disabledDays
40578 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40580 disabledDays : [0,1,2,3,4,5,6],
40582 * @cfg {String} disabledDaysText
40583 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40585 disabledDaysText : "Disabled",
40587 * @cfg {Array} disabledDates
40588 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40589 * expression so they are very powerful. Some examples:
40591 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40592 * <li>["03/08", "09/16"] would disable those days for every year</li>
40593 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40594 * <li>["03/../2006"] would disable every day in March 2006</li>
40595 * <li>["^03"] would disable every day in every March</li>
40597 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40598 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40600 disabledDates : null,
40602 * @cfg {String} disabledDatesText
40603 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40605 disabledDatesText : "Disabled",
40607 * @cfg {Date/String} minValue
40608 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40609 * valid format (defaults to null).
40613 * @cfg {Date/String} maxValue
40614 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40615 * valid format (defaults to null).
40619 * @cfg {String} minText
40620 * The error text to display when the date in the cell is before minValue (defaults to
40621 * 'The date in this field must be after {minValue}').
40623 minText : "The date in this field must be equal to or after {0}",
40625 * @cfg {String} maxTextf
40626 * The error text to display when the date in the cell is after maxValue (defaults to
40627 * 'The date in this field must be before {maxValue}').
40629 maxText : "The date in this field must be equal to or before {0}",
40631 * @cfg {String} invalidText
40632 * The error text to display when the date in the field is invalid (defaults to
40633 * '{value} is not a valid date - it must be in the format {format}').
40635 invalidText : "{0} is not a valid date - it must be in the format {1}",
40637 * @cfg {String} triggerClass
40638 * An additional CSS class used to style the trigger button. The trigger will always get the
40639 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40640 * which displays a calendar icon).
40642 triggerClass : 'x-form-date-trigger',
40646 * @cfg {Boolean} useIso
40647 * if enabled, then the date field will use a hidden field to store the
40648 * real value as iso formated date. default (true)
40652 * @cfg {String/Object} autoCreate
40653 * A DomHelper element spec, or true for a default element spec (defaults to
40654 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40657 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40660 hiddenField: false,
40662 hideMonthPicker : false,
40664 onRender : function(ct, position)
40666 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40668 this.el.dom.removeAttribute('name');
40669 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40671 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40672 // prevent input submission
40673 this.hiddenName = this.name;
40680 validateValue : function(value)
40682 value = this.formatDate(value);
40683 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40686 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40689 var svalue = value;
40690 value = this.parseDate(value);
40692 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40695 var time = value.getTime();
40696 if(this.minValue && time < this.minValue.getTime()){
40697 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40700 if(this.maxValue && time > this.maxValue.getTime()){
40701 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40704 /*if(this.disabledDays){
40705 var day = value.getDay();
40706 for(var i = 0; i < this.disabledDays.length; i++) {
40707 if(day === this.disabledDays[i]){
40708 this.markInvalid(this.disabledDaysText);
40714 var fvalue = this.formatDate(value);
40715 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40716 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40724 // Provides logic to override the default TriggerField.validateBlur which just returns true
40725 validateBlur : function(){
40726 return !this.menu || !this.menu.isVisible();
40730 * Returns the current date value of the date field.
40731 * @return {Date} The date value
40733 getValue : function(){
40737 return this.hiddenField ?
40738 this.hiddenField.value :
40739 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40743 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40744 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40745 * (the default format used is "m/d/y").
40748 //All of these calls set the same date value (May 4, 2006)
40750 //Pass a date object:
40751 var dt = new Date('5/4/06');
40752 monthField.setValue(dt);
40754 //Pass a date string (default format):
40755 monthField.setValue('5/4/06');
40757 //Pass a date string (custom format):
40758 monthField.format = 'Y-m-d';
40759 monthField.setValue('2006-5-4');
40761 * @param {String/Date} date The date or valid date string
40763 setValue : function(date){
40764 Roo.log('month setValue' + date);
40765 // can only be first of month..
40767 var val = this.parseDate(date);
40769 if (this.hiddenField) {
40770 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40772 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40773 this.value = this.parseDate(date);
40777 parseDate : function(value){
40778 if(!value || value instanceof Date){
40779 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40782 var v = Date.parseDate(value, this.format);
40783 if (!v && this.useIso) {
40784 v = Date.parseDate(value, 'Y-m-d');
40788 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40792 if(!v && this.altFormats){
40793 if(!this.altFormatsArray){
40794 this.altFormatsArray = this.altFormats.split("|");
40796 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40797 v = Date.parseDate(value, this.altFormatsArray[i]);
40804 formatDate : function(date, fmt){
40805 return (!date || !(date instanceof Date)) ?
40806 date : date.dateFormat(fmt || this.format);
40811 select: function(m, d){
40813 this.fireEvent('select', this, d);
40815 show : function(){ // retain focus styling
40819 this.focus.defer(10, this);
40820 var ml = this.menuListeners;
40821 this.menu.un("select", ml.select, this);
40822 this.menu.un("show", ml.show, this);
40823 this.menu.un("hide", ml.hide, this);
40827 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40828 onTriggerClick : function(){
40832 if(this.menu == null){
40833 this.menu = new Roo.menu.DateMenu();
40837 Roo.apply(this.menu.picker, {
40839 showClear: this.allowBlank,
40840 minDate : this.minValue,
40841 maxDate : this.maxValue,
40842 disabledDatesRE : this.ddMatch,
40843 disabledDatesText : this.disabledDatesText,
40845 format : this.useIso ? 'Y-m-d' : this.format,
40846 minText : String.format(this.minText, this.formatDate(this.minValue)),
40847 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40850 this.menu.on(Roo.apply({}, this.menuListeners, {
40858 // hide month picker get's called when we called by 'before hide';
40860 var ignorehide = true;
40861 p.hideMonthPicker = function(disableAnim){
40865 if(this.monthPicker){
40866 Roo.log("hideMonthPicker called");
40867 if(disableAnim === true){
40868 this.monthPicker.hide();
40870 this.monthPicker.slideOut('t', {duration:.2});
40871 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40872 p.fireEvent("select", this, this.value);
40878 Roo.log('picker set value');
40879 Roo.log(this.getValue());
40880 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40881 m.show(this.el, 'tl-bl?');
40882 ignorehide = false;
40883 // this will trigger hideMonthPicker..
40886 // hidden the day picker
40887 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40893 p.showMonthPicker.defer(100, p);
40899 beforeBlur : function(){
40900 var v = this.parseDate(this.getRawValue());
40906 /** @cfg {Boolean} grow @hide */
40907 /** @cfg {Number} growMin @hide */
40908 /** @cfg {Number} growMax @hide */
40915 * Ext JS Library 1.1.1
40916 * Copyright(c) 2006-2007, Ext JS, LLC.
40918 * Originally Released Under LGPL - original licence link has changed is not relivant.
40921 * <script type="text/javascript">
40926 * @class Roo.form.ComboBox
40927 * @extends Roo.form.TriggerField
40928 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40930 * Create a new ComboBox.
40931 * @param {Object} config Configuration options
40933 Roo.form.ComboBox = function(config){
40934 Roo.form.ComboBox.superclass.constructor.call(this, config);
40938 * Fires when the dropdown list is expanded
40939 * @param {Roo.form.ComboBox} combo This combo box
40944 * Fires when the dropdown list is collapsed
40945 * @param {Roo.form.ComboBox} combo This combo box
40949 * @event beforeselect
40950 * Fires before a list item is selected. Return false to cancel the selection.
40951 * @param {Roo.form.ComboBox} combo This combo box
40952 * @param {Roo.data.Record} record The data record returned from the underlying store
40953 * @param {Number} index The index of the selected item in the dropdown list
40955 'beforeselect' : true,
40958 * Fires when a list item is selected
40959 * @param {Roo.form.ComboBox} combo This combo box
40960 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40961 * @param {Number} index The index of the selected item in the dropdown list
40965 * @event beforequery
40966 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40967 * The event object passed has these properties:
40968 * @param {Roo.form.ComboBox} combo This combo box
40969 * @param {String} query The query
40970 * @param {Boolean} forceAll true to force "all" query
40971 * @param {Boolean} cancel true to cancel the query
40972 * @param {Object} e The query event object
40974 'beforequery': true,
40977 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40978 * @param {Roo.form.ComboBox} combo This combo box
40983 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40984 * @param {Roo.form.ComboBox} combo This combo box
40985 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40991 if(this.transform){
40992 this.allowDomMove = false;
40993 var s = Roo.getDom(this.transform);
40994 if(!this.hiddenName){
40995 this.hiddenName = s.name;
40998 this.mode = 'local';
40999 var d = [], opts = s.options;
41000 for(var i = 0, len = opts.length;i < len; i++){
41002 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41004 this.value = value;
41006 d.push([value, o.text]);
41008 this.store = new Roo.data.SimpleStore({
41010 fields: ['value', 'text'],
41013 this.valueField = 'value';
41014 this.displayField = 'text';
41016 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41017 if(!this.lazyRender){
41018 this.target = true;
41019 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41020 s.parentNode.removeChild(s); // remove it
41021 this.render(this.el.parentNode);
41023 s.parentNode.removeChild(s); // remove it
41028 this.store = Roo.factory(this.store, Roo.data);
41031 this.selectedIndex = -1;
41032 if(this.mode == 'local'){
41033 if(config.queryDelay === undefined){
41034 this.queryDelay = 10;
41036 if(config.minChars === undefined){
41042 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41044 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41047 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41048 * rendering into an Roo.Editor, defaults to false)
41051 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41052 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41055 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41058 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41059 * the dropdown list (defaults to undefined, with no header element)
41063 * @cfg {String/Roo.Template} tpl The template to use to render the output
41067 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41069 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41071 listWidth: undefined,
41073 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41074 * mode = 'remote' or 'text' if mode = 'local')
41076 displayField: undefined,
41078 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41079 * mode = 'remote' or 'value' if mode = 'local').
41080 * Note: use of a valueField requires the user make a selection
41081 * in order for a value to be mapped.
41083 valueField: undefined,
41087 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41088 * field's data value (defaults to the underlying DOM element's name)
41090 hiddenName: undefined,
41092 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41096 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41098 selectedClass: 'x-combo-selected',
41100 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41101 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41102 * which displays a downward arrow icon).
41104 triggerClass : 'x-form-arrow-trigger',
41106 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41110 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41111 * anchor positions (defaults to 'tl-bl')
41113 listAlign: 'tl-bl?',
41115 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41119 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41120 * query specified by the allQuery config option (defaults to 'query')
41122 triggerAction: 'query',
41124 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41125 * (defaults to 4, does not apply if editable = false)
41129 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41130 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41134 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41135 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41139 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41140 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41144 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41145 * when editable = true (defaults to false)
41147 selectOnFocus:false,
41149 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41151 queryParam: 'query',
41153 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41154 * when mode = 'remote' (defaults to 'Loading...')
41156 loadingText: 'Loading...',
41158 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41162 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41166 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41167 * traditional select (defaults to true)
41171 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41175 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41179 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41180 * listWidth has a higher value)
41184 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41185 * allow the user to set arbitrary text into the field (defaults to false)
41187 forceSelection:false,
41189 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41190 * if typeAhead = true (defaults to 250)
41192 typeAheadDelay : 250,
41194 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41195 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41197 valueNotFoundText : undefined,
41199 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41201 blockFocus : false,
41204 * @cfg {Boolean} disableClear Disable showing of clear button.
41206 disableClear : false,
41208 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41210 alwaysQuery : false,
41216 // element that contains real text value.. (when hidden is used..)
41219 onRender : function(ct, position){
41220 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41221 if(this.hiddenName){
41222 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41224 this.hiddenField.value =
41225 this.hiddenValue !== undefined ? this.hiddenValue :
41226 this.value !== undefined ? this.value : '';
41228 // prevent input submission
41229 this.el.dom.removeAttribute('name');
41234 this.el.dom.setAttribute('autocomplete', 'off');
41237 var cls = 'x-combo-list';
41239 this.list = new Roo.Layer({
41240 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41243 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41244 this.list.setWidth(lw);
41245 this.list.swallowEvent('mousewheel');
41246 this.assetHeight = 0;
41249 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41250 this.assetHeight += this.header.getHeight();
41253 this.innerList = this.list.createChild({cls:cls+'-inner'});
41254 this.innerList.on('mouseover', this.onViewOver, this);
41255 this.innerList.on('mousemove', this.onViewMove, this);
41256 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41258 if(this.allowBlank && !this.pageSize && !this.disableClear){
41259 this.footer = this.list.createChild({cls:cls+'-ft'});
41260 this.pageTb = new Roo.Toolbar(this.footer);
41264 this.footer = this.list.createChild({cls:cls+'-ft'});
41265 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41266 {pageSize: this.pageSize});
41270 if (this.pageTb && this.allowBlank && !this.disableClear) {
41272 this.pageTb.add(new Roo.Toolbar.Fill(), {
41273 cls: 'x-btn-icon x-btn-clear',
41275 handler: function()
41278 _this.clearValue();
41279 _this.onSelect(false, -1);
41284 this.assetHeight += this.footer.getHeight();
41289 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41292 this.view = new Roo.View(this.innerList, this.tpl, {
41293 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41296 this.view.on('click', this.onViewClick, this);
41298 this.store.on('beforeload', this.onBeforeLoad, this);
41299 this.store.on('load', this.onLoad, this);
41300 this.store.on('loadexception', this.onLoadException, this);
41302 if(this.resizable){
41303 this.resizer = new Roo.Resizable(this.list, {
41304 pinned:true, handles:'se'
41306 this.resizer.on('resize', function(r, w, h){
41307 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41308 this.listWidth = w;
41309 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41310 this.restrictHeight();
41312 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41314 if(!this.editable){
41315 this.editable = true;
41316 this.setEditable(false);
41320 if (typeof(this.events.add.listeners) != 'undefined') {
41322 this.addicon = this.wrap.createChild(
41323 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41325 this.addicon.on('click', function(e) {
41326 this.fireEvent('add', this);
41329 if (typeof(this.events.edit.listeners) != 'undefined') {
41331 this.editicon = this.wrap.createChild(
41332 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41333 if (this.addicon) {
41334 this.editicon.setStyle('margin-left', '40px');
41336 this.editicon.on('click', function(e) {
41338 // we fire even if inothing is selected..
41339 this.fireEvent('edit', this, this.lastData );
41349 initEvents : function(){
41350 Roo.form.ComboBox.superclass.initEvents.call(this);
41352 this.keyNav = new Roo.KeyNav(this.el, {
41353 "up" : function(e){
41354 this.inKeyMode = true;
41358 "down" : function(e){
41359 if(!this.isExpanded()){
41360 this.onTriggerClick();
41362 this.inKeyMode = true;
41367 "enter" : function(e){
41368 this.onViewClick();
41372 "esc" : function(e){
41376 "tab" : function(e){
41377 this.onViewClick(false);
41378 this.fireEvent("specialkey", this, e);
41384 doRelay : function(foo, bar, hname){
41385 if(hname == 'down' || this.scope.isExpanded()){
41386 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41393 this.queryDelay = Math.max(this.queryDelay || 10,
41394 this.mode == 'local' ? 10 : 250);
41395 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41396 if(this.typeAhead){
41397 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41399 if(this.editable !== false){
41400 this.el.on("keyup", this.onKeyUp, this);
41402 if(this.forceSelection){
41403 this.on('blur', this.doForce, this);
41407 onDestroy : function(){
41409 this.view.setStore(null);
41410 this.view.el.removeAllListeners();
41411 this.view.el.remove();
41412 this.view.purgeListeners();
41415 this.list.destroy();
41418 this.store.un('beforeload', this.onBeforeLoad, this);
41419 this.store.un('load', this.onLoad, this);
41420 this.store.un('loadexception', this.onLoadException, this);
41422 Roo.form.ComboBox.superclass.onDestroy.call(this);
41426 fireKey : function(e){
41427 if(e.isNavKeyPress() && !this.list.isVisible()){
41428 this.fireEvent("specialkey", this, e);
41433 onResize: function(w, h){
41434 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41436 if(typeof w != 'number'){
41437 // we do not handle it!?!?
41440 var tw = this.trigger.getWidth();
41441 tw += this.addicon ? this.addicon.getWidth() : 0;
41442 tw += this.editicon ? this.editicon.getWidth() : 0;
41444 this.el.setWidth( this.adjustWidth('input', x));
41446 this.trigger.setStyle('left', x+'px');
41448 if(this.list && this.listWidth === undefined){
41449 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41450 this.list.setWidth(lw);
41451 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41459 * Allow or prevent the user from directly editing the field text. If false is passed,
41460 * the user will only be able to select from the items defined in the dropdown list. This method
41461 * is the runtime equivalent of setting the 'editable' config option at config time.
41462 * @param {Boolean} value True to allow the user to directly edit the field text
41464 setEditable : function(value){
41465 if(value == this.editable){
41468 this.editable = value;
41470 this.el.dom.setAttribute('readOnly', true);
41471 this.el.on('mousedown', this.onTriggerClick, this);
41472 this.el.addClass('x-combo-noedit');
41474 this.el.dom.setAttribute('readOnly', false);
41475 this.el.un('mousedown', this.onTriggerClick, this);
41476 this.el.removeClass('x-combo-noedit');
41481 onBeforeLoad : function(){
41482 if(!this.hasFocus){
41485 this.innerList.update(this.loadingText ?
41486 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41487 this.restrictHeight();
41488 this.selectedIndex = -1;
41492 onLoad : function(){
41493 if(!this.hasFocus){
41496 if(this.store.getCount() > 0){
41498 this.restrictHeight();
41499 if(this.lastQuery == this.allQuery){
41501 this.el.dom.select();
41503 if(!this.selectByValue(this.value, true)){
41504 this.select(0, true);
41508 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41509 this.taTask.delay(this.typeAheadDelay);
41513 this.onEmptyResults();
41518 onLoadException : function()
41521 Roo.log(this.store.reader.jsonData);
41522 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41523 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41529 onTypeAhead : function(){
41530 if(this.store.getCount() > 0){
41531 var r = this.store.getAt(0);
41532 var newValue = r.data[this.displayField];
41533 var len = newValue.length;
41534 var selStart = this.getRawValue().length;
41535 if(selStart != len){
41536 this.setRawValue(newValue);
41537 this.selectText(selStart, newValue.length);
41543 onSelect : function(record, index){
41544 if(this.fireEvent('beforeselect', this, record, index) !== false){
41545 this.setFromData(index > -1 ? record.data : false);
41547 this.fireEvent('select', this, record, index);
41552 * Returns the currently selected field value or empty string if no value is set.
41553 * @return {String} value The selected value
41555 getValue : function(){
41556 if(this.valueField){
41557 return typeof this.value != 'undefined' ? this.value : '';
41559 return Roo.form.ComboBox.superclass.getValue.call(this);
41563 * Clears any text/value currently set in the field
41565 clearValue : function(){
41566 if(this.hiddenField){
41567 this.hiddenField.value = '';
41570 this.setRawValue('');
41571 this.lastSelectionText = '';
41576 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41577 * will be displayed in the field. If the value does not match the data value of an existing item,
41578 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41579 * Otherwise the field will be blank (although the value will still be set).
41580 * @param {String} value The value to match
41582 setValue : function(v){
41584 if(this.valueField){
41585 var r = this.findRecord(this.valueField, v);
41587 text = r.data[this.displayField];
41588 }else if(this.valueNotFoundText !== undefined){
41589 text = this.valueNotFoundText;
41592 this.lastSelectionText = text;
41593 if(this.hiddenField){
41594 this.hiddenField.value = v;
41596 Roo.form.ComboBox.superclass.setValue.call(this, text);
41600 * @property {Object} the last set data for the element
41605 * Sets the value of the field based on a object which is related to the record format for the store.
41606 * @param {Object} value the value to set as. or false on reset?
41608 setFromData : function(o){
41609 var dv = ''; // display value
41610 var vv = ''; // value value..
41612 if (this.displayField) {
41613 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41615 // this is an error condition!!!
41616 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41619 if(this.valueField){
41620 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41622 if(this.hiddenField){
41623 this.hiddenField.value = vv;
41625 this.lastSelectionText = dv;
41626 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41630 // no hidden field.. - we store the value in 'value', but still display
41631 // display field!!!!
41632 this.lastSelectionText = dv;
41633 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41639 reset : function(){
41640 // overridden so that last data is reset..
41641 this.setValue(this.resetValue);
41642 this.originalValue = this.getValue();
41643 this.clearInvalid();
41644 this.lastData = false;
41646 this.view.clearSelections();
41650 findRecord : function(prop, value){
41652 if(this.store.getCount() > 0){
41653 this.store.each(function(r){
41654 if(r.data[prop] == value){
41664 getName: function()
41666 // returns hidden if it's set..
41667 if (!this.rendered) {return ''};
41668 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41672 onViewMove : function(e, t){
41673 this.inKeyMode = false;
41677 onViewOver : function(e, t){
41678 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41681 var item = this.view.findItemFromChild(t);
41683 var index = this.view.indexOf(item);
41684 this.select(index, false);
41689 onViewClick : function(doFocus)
41691 var index = this.view.getSelectedIndexes()[0];
41692 var r = this.store.getAt(index);
41694 this.onSelect(r, index);
41696 if(doFocus !== false && !this.blockFocus){
41702 restrictHeight : function(){
41703 this.innerList.dom.style.height = '';
41704 var inner = this.innerList.dom;
41705 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41706 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41707 this.list.beginUpdate();
41708 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41709 this.list.alignTo(this.el, this.listAlign);
41710 this.list.endUpdate();
41714 onEmptyResults : function(){
41719 * Returns true if the dropdown list is expanded, else false.
41721 isExpanded : function(){
41722 return this.list.isVisible();
41726 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41727 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41728 * @param {String} value The data value of the item to select
41729 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41730 * selected item if it is not currently in view (defaults to true)
41731 * @return {Boolean} True if the value matched an item in the list, else false
41733 selectByValue : function(v, scrollIntoView){
41734 if(v !== undefined && v !== null){
41735 var r = this.findRecord(this.valueField || this.displayField, v);
41737 this.select(this.store.indexOf(r), scrollIntoView);
41745 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41746 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41747 * @param {Number} index The zero-based index of the list item to select
41748 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41749 * selected item if it is not currently in view (defaults to true)
41751 select : function(index, scrollIntoView){
41752 this.selectedIndex = index;
41753 this.view.select(index);
41754 if(scrollIntoView !== false){
41755 var el = this.view.getNode(index);
41757 this.innerList.scrollChildIntoView(el, false);
41763 selectNext : function(){
41764 var ct = this.store.getCount();
41766 if(this.selectedIndex == -1){
41768 }else if(this.selectedIndex < ct-1){
41769 this.select(this.selectedIndex+1);
41775 selectPrev : function(){
41776 var ct = this.store.getCount();
41778 if(this.selectedIndex == -1){
41780 }else if(this.selectedIndex != 0){
41781 this.select(this.selectedIndex-1);
41787 onKeyUp : function(e){
41788 if(this.editable !== false && !e.isSpecialKey()){
41789 this.lastKey = e.getKey();
41790 this.dqTask.delay(this.queryDelay);
41795 validateBlur : function(){
41796 return !this.list || !this.list.isVisible();
41800 initQuery : function(){
41801 this.doQuery(this.getRawValue());
41805 doForce : function(){
41806 if(this.el.dom.value.length > 0){
41807 this.el.dom.value =
41808 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41814 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41815 * query allowing the query action to be canceled if needed.
41816 * @param {String} query The SQL query to execute
41817 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41818 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41819 * saved in the current store (defaults to false)
41821 doQuery : function(q, forceAll){
41822 if(q === undefined || q === null){
41827 forceAll: forceAll,
41831 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41835 forceAll = qe.forceAll;
41836 if(forceAll === true || (q.length >= this.minChars)){
41837 if(this.lastQuery != q || this.alwaysQuery){
41838 this.lastQuery = q;
41839 if(this.mode == 'local'){
41840 this.selectedIndex = -1;
41842 this.store.clearFilter();
41844 this.store.filter(this.displayField, q);
41848 this.store.baseParams[this.queryParam] = q;
41850 params: this.getParams(q)
41855 this.selectedIndex = -1;
41862 getParams : function(q){
41864 //p[this.queryParam] = q;
41867 p.limit = this.pageSize;
41873 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41875 collapse : function(){
41876 if(!this.isExpanded()){
41880 Roo.get(document).un('mousedown', this.collapseIf, this);
41881 Roo.get(document).un('mousewheel', this.collapseIf, this);
41882 if (!this.editable) {
41883 Roo.get(document).un('keydown', this.listKeyPress, this);
41885 this.fireEvent('collapse', this);
41889 collapseIf : function(e){
41890 if(!e.within(this.wrap) && !e.within(this.list)){
41896 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41898 expand : function(){
41899 if(this.isExpanded() || !this.hasFocus){
41902 this.list.alignTo(this.el, this.listAlign);
41904 Roo.get(document).on('mousedown', this.collapseIf, this);
41905 Roo.get(document).on('mousewheel', this.collapseIf, this);
41906 if (!this.editable) {
41907 Roo.get(document).on('keydown', this.listKeyPress, this);
41910 this.fireEvent('expand', this);
41914 // Implements the default empty TriggerField.onTriggerClick function
41915 onTriggerClick : function(){
41919 if(this.isExpanded()){
41921 if (!this.blockFocus) {
41926 this.hasFocus = true;
41927 if(this.triggerAction == 'all') {
41928 this.doQuery(this.allQuery, true);
41930 this.doQuery(this.getRawValue());
41932 if (!this.blockFocus) {
41937 listKeyPress : function(e)
41939 //Roo.log('listkeypress');
41940 // scroll to first matching element based on key pres..
41941 if (e.isSpecialKey()) {
41944 var k = String.fromCharCode(e.getKey()).toUpperCase();
41947 var csel = this.view.getSelectedNodes();
41948 var cselitem = false;
41950 var ix = this.view.indexOf(csel[0]);
41951 cselitem = this.store.getAt(ix);
41952 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41958 this.store.each(function(v) {
41960 // start at existing selection.
41961 if (cselitem.id == v.id) {
41967 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41968 match = this.store.indexOf(v);
41973 if (match === false) {
41974 return true; // no more action?
41977 this.view.select(match);
41978 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41979 sn.scrollIntoView(sn.dom.parentNode, false);
41983 * @cfg {Boolean} grow
41987 * @cfg {Number} growMin
41991 * @cfg {Number} growMax
41999 * Copyright(c) 2010-2012, Roo J Solutions Limited
42006 * @class Roo.form.ComboBoxArray
42007 * @extends Roo.form.TextField
42008 * A facebook style adder... for lists of email / people / countries etc...
42009 * pick multiple items from a combo box, and shows each one.
42011 * Fred [x] Brian [x] [Pick another |v]
42014 * For this to work: it needs various extra information
42015 * - normal combo problay has
42017 * + displayField, valueField
42019 * For our purpose...
42022 * If we change from 'extends' to wrapping...
42029 * Create a new ComboBoxArray.
42030 * @param {Object} config Configuration options
42034 Roo.form.ComboBoxArray = function(config)
42038 * @event beforeremove
42039 * Fires before remove the value from the list
42040 * @param {Roo.form.ComboBoxArray} _self This combo box array
42041 * @param {Roo.form.ComboBoxArray.Item} item removed item
42043 'beforeremove' : true,
42046 * Fires when remove the value from the list
42047 * @param {Roo.form.ComboBoxArray} _self This combo box array
42048 * @param {Roo.form.ComboBoxArray.Item} item removed item
42055 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42057 this.items = new Roo.util.MixedCollection(false);
42059 // construct the child combo...
42069 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42072 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42077 // behavies liek a hiddne field
42078 inputType: 'hidden',
42080 * @cfg {Number} width The width of the box that displays the selected element
42087 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42091 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42093 hiddenName : false,
42096 // private the array of items that are displayed..
42098 // private - the hidden field el.
42100 // private - the filed el..
42103 //validateValue : function() { return true; }, // all values are ok!
42104 //onAddClick: function() { },
42106 onRender : function(ct, position)
42109 // create the standard hidden element
42110 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42113 // give fake names to child combo;
42114 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42115 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42117 this.combo = Roo.factory(this.combo, Roo.form);
42118 this.combo.onRender(ct, position);
42119 if (typeof(this.combo.width) != 'undefined') {
42120 this.combo.onResize(this.combo.width,0);
42123 this.combo.initEvents();
42125 // assigned so form know we need to do this..
42126 this.store = this.combo.store;
42127 this.valueField = this.combo.valueField;
42128 this.displayField = this.combo.displayField ;
42131 this.combo.wrap.addClass('x-cbarray-grp');
42133 var cbwrap = this.combo.wrap.createChild(
42134 {tag: 'div', cls: 'x-cbarray-cb'},
42139 this.hiddenEl = this.combo.wrap.createChild({
42140 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42142 this.el = this.combo.wrap.createChild({
42143 tag: 'input', type:'hidden' , name: this.name, value : ''
42145 // this.el.dom.removeAttribute("name");
42148 this.outerWrap = this.combo.wrap;
42149 this.wrap = cbwrap;
42151 this.outerWrap.setWidth(this.width);
42152 this.outerWrap.dom.removeChild(this.el.dom);
42154 this.wrap.dom.appendChild(this.el.dom);
42155 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42156 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42158 this.combo.trigger.setStyle('position','relative');
42159 this.combo.trigger.setStyle('left', '0px');
42160 this.combo.trigger.setStyle('top', '2px');
42162 this.combo.el.setStyle('vertical-align', 'text-bottom');
42164 //this.trigger.setStyle('vertical-align', 'top');
42166 // this should use the code from combo really... on('add' ....)
42170 this.adder = this.outerWrap.createChild(
42171 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42173 this.adder.on('click', function(e) {
42174 _t.fireEvent('adderclick', this, e);
42178 //this.adder.on('click', this.onAddClick, _t);
42181 this.combo.on('select', function(cb, rec, ix) {
42182 this.addItem(rec.data);
42185 cb.el.dom.value = '';
42186 //cb.lastData = rec.data;
42195 getName: function()
42197 // returns hidden if it's set..
42198 if (!this.rendered) {return ''};
42199 return this.hiddenName ? this.hiddenName : this.name;
42204 onResize: function(w, h){
42207 // not sure if this is needed..
42208 //this.combo.onResize(w,h);
42210 if(typeof w != 'number'){
42211 // we do not handle it!?!?
42214 var tw = this.combo.trigger.getWidth();
42215 tw += this.addicon ? this.addicon.getWidth() : 0;
42216 tw += this.editicon ? this.editicon.getWidth() : 0;
42218 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42220 this.combo.trigger.setStyle('left', '0px');
42222 if(this.list && this.listWidth === undefined){
42223 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42224 this.list.setWidth(lw);
42225 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42232 addItem: function(rec)
42234 var valueField = this.combo.valueField;
42235 var displayField = this.combo.displayField;
42236 if (this.items.indexOfKey(rec[valueField]) > -1) {
42237 //console.log("GOT " + rec.data.id);
42241 var x = new Roo.form.ComboBoxArray.Item({
42242 //id : rec[this.idField],
42244 displayField : displayField ,
42245 tipField : displayField ,
42249 this.items.add(rec[valueField],x);
42250 // add it before the element..
42251 this.updateHiddenEl();
42252 x.render(this.outerWrap, this.wrap.dom);
42253 // add the image handler..
42256 updateHiddenEl : function()
42259 if (!this.hiddenEl) {
42263 var idField = this.combo.valueField;
42265 this.items.each(function(f) {
42266 ar.push(f.data[idField]);
42269 this.hiddenEl.dom.value = ar.join(',');
42275 this.items.clear();
42277 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42281 this.el.dom.value = '';
42282 if (this.hiddenEl) {
42283 this.hiddenEl.dom.value = '';
42287 getValue: function()
42289 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42291 setValue: function(v) // not a valid action - must use addItems..
42298 if (this.store.isLocal && (typeof(v) == 'string')) {
42299 // then we can use the store to find the values..
42300 // comma seperated at present.. this needs to allow JSON based encoding..
42301 this.hiddenEl.value = v;
42303 Roo.each(v.split(','), function(k) {
42304 Roo.log("CHECK " + this.valueField + ',' + k);
42305 var li = this.store.query(this.valueField, k);
42310 add[this.valueField] = k;
42311 add[this.displayField] = li.item(0).data[this.displayField];
42317 if (typeof(v) == 'object' ) {
42318 // then let's assume it's an array of objects..
42319 Roo.each(v, function(l) {
42327 setFromData: function(v)
42329 // this recieves an object, if setValues is called.
42331 this.el.dom.value = v[this.displayField];
42332 this.hiddenEl.dom.value = v[this.valueField];
42333 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42336 var kv = v[this.valueField];
42337 var dv = v[this.displayField];
42338 kv = typeof(kv) != 'string' ? '' : kv;
42339 dv = typeof(dv) != 'string' ? '' : dv;
42342 var keys = kv.split(',');
42343 var display = dv.split(',');
42344 for (var i = 0 ; i < keys.length; i++) {
42347 add[this.valueField] = keys[i];
42348 add[this.displayField] = display[i];
42356 * Validates the combox array value
42357 * @return {Boolean} True if the value is valid, else false
42359 validate : function(){
42360 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42361 this.clearInvalid();
42367 validateValue : function(value){
42368 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42376 isDirty : function() {
42377 if(this.disabled) {
42382 var d = Roo.decode(String(this.originalValue));
42384 return String(this.getValue()) !== String(this.originalValue);
42387 var originalValue = [];
42389 for (var i = 0; i < d.length; i++){
42390 originalValue.push(d[i][this.valueField]);
42393 return String(this.getValue()) !== String(originalValue.join(','));
42402 * @class Roo.form.ComboBoxArray.Item
42403 * @extends Roo.BoxComponent
42404 * A selected item in the list
42405 * Fred [x] Brian [x] [Pick another |v]
42408 * Create a new item.
42409 * @param {Object} config Configuration options
42412 Roo.form.ComboBoxArray.Item = function(config) {
42413 config.id = Roo.id();
42414 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42417 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42420 displayField : false,
42424 defaultAutoCreate : {
42426 cls: 'x-cbarray-item',
42433 src : Roo.BLANK_IMAGE_URL ,
42441 onRender : function(ct, position)
42443 Roo.form.Field.superclass.onRender.call(this, ct, position);
42446 var cfg = this.getAutoCreate();
42447 this.el = ct.createChild(cfg, position);
42450 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42452 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42453 this.cb.renderer(this.data) :
42454 String.format('{0}',this.data[this.displayField]);
42457 this.el.child('div').dom.setAttribute('qtip',
42458 String.format('{0}',this.data[this.tipField])
42461 this.el.child('img').on('click', this.remove, this);
42465 remove : function()
42467 if(this.cb.disabled){
42471 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42472 this.cb.items.remove(this);
42473 this.el.child('img').un('click', this.remove, this);
42475 this.cb.updateHiddenEl();
42477 this.cb.fireEvent('remove', this.cb, this);
42483 * Ext JS Library 1.1.1
42484 * Copyright(c) 2006-2007, Ext JS, LLC.
42486 * Originally Released Under LGPL - original licence link has changed is not relivant.
42489 * <script type="text/javascript">
42492 * @class Roo.form.Checkbox
42493 * @extends Roo.form.Field
42494 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42496 * Creates a new Checkbox
42497 * @param {Object} config Configuration options
42499 Roo.form.Checkbox = function(config){
42500 Roo.form.Checkbox.superclass.constructor.call(this, config);
42504 * Fires when the checkbox is checked or unchecked.
42505 * @param {Roo.form.Checkbox} this This checkbox
42506 * @param {Boolean} checked The new checked value
42512 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42514 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42516 focusClass : undefined,
42518 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42520 fieldClass: "x-form-field",
42522 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42526 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42527 * {tag: "input", type: "checkbox", autocomplete: "off"})
42529 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42531 * @cfg {String} boxLabel The text that appears beside the checkbox
42535 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42539 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42541 valueOff: '0', // value when not checked..
42543 actionMode : 'viewEl',
42546 itemCls : 'x-menu-check-item x-form-item',
42547 groupClass : 'x-menu-group-item',
42548 inputType : 'hidden',
42551 inSetChecked: false, // check that we are not calling self...
42553 inputElement: false, // real input element?
42554 basedOn: false, // ????
42556 isFormField: true, // not sure where this is needed!!!!
42558 onResize : function(){
42559 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42560 if(!this.boxLabel){
42561 this.el.alignTo(this.wrap, 'c-c');
42565 initEvents : function(){
42566 Roo.form.Checkbox.superclass.initEvents.call(this);
42567 this.el.on("click", this.onClick, this);
42568 this.el.on("change", this.onClick, this);
42572 getResizeEl : function(){
42576 getPositionEl : function(){
42581 onRender : function(ct, position){
42582 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42584 if(this.inputValue !== undefined){
42585 this.el.dom.value = this.inputValue;
42588 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42589 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42590 var viewEl = this.wrap.createChild({
42591 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42592 this.viewEl = viewEl;
42593 this.wrap.on('click', this.onClick, this);
42595 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42596 this.el.on('propertychange', this.setFromHidden, this); //ie
42601 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42602 // viewEl.on('click', this.onClick, this);
42604 //if(this.checked){
42605 this.setChecked(this.checked);
42607 //this.checked = this.el.dom;
42613 initValue : Roo.emptyFn,
42616 * Returns the checked state of the checkbox.
42617 * @return {Boolean} True if checked, else false
42619 getValue : function(){
42621 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42623 return this.valueOff;
42628 onClick : function(){
42629 if (this.disabled) {
42632 this.setChecked(!this.checked);
42634 //if(this.el.dom.checked != this.checked){
42635 // this.setValue(this.el.dom.checked);
42640 * Sets the checked state of the checkbox.
42641 * On is always based on a string comparison between inputValue and the param.
42642 * @param {Boolean/String} value - the value to set
42643 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42645 setValue : function(v,suppressEvent){
42648 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42649 //if(this.el && this.el.dom){
42650 // this.el.dom.checked = this.checked;
42651 // this.el.dom.defaultChecked = this.checked;
42653 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42654 //this.fireEvent("check", this, this.checked);
42657 setChecked : function(state,suppressEvent)
42659 if (this.inSetChecked) {
42660 this.checked = state;
42666 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42668 this.checked = state;
42669 if(suppressEvent !== true){
42670 this.fireEvent('check', this, state);
42672 this.inSetChecked = true;
42673 this.el.dom.value = state ? this.inputValue : this.valueOff;
42674 this.inSetChecked = false;
42677 // handle setting of hidden value by some other method!!?!?
42678 setFromHidden: function()
42683 //console.log("SET FROM HIDDEN");
42684 //alert('setFrom hidden');
42685 this.setValue(this.el.dom.value);
42688 onDestroy : function()
42691 Roo.get(this.viewEl).remove();
42694 Roo.form.Checkbox.superclass.onDestroy.call(this);
42697 setBoxLabel : function(str)
42699 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42704 * Ext JS Library 1.1.1
42705 * Copyright(c) 2006-2007, Ext JS, LLC.
42707 * Originally Released Under LGPL - original licence link has changed is not relivant.
42710 * <script type="text/javascript">
42714 * @class Roo.form.Radio
42715 * @extends Roo.form.Checkbox
42716 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42717 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42719 * Creates a new Radio
42720 * @param {Object} config Configuration options
42722 Roo.form.Radio = function(){
42723 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42725 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42726 inputType: 'radio',
42729 * If this radio is part of a group, it will return the selected value
42732 getGroupValue : function(){
42733 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42737 onRender : function(ct, position){
42738 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42740 if(this.inputValue !== undefined){
42741 this.el.dom.value = this.inputValue;
42744 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42745 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42746 //var viewEl = this.wrap.createChild({
42747 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42748 //this.viewEl = viewEl;
42749 //this.wrap.on('click', this.onClick, this);
42751 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42752 //this.el.on('propertychange', this.setFromHidden, this); //ie
42757 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42758 // viewEl.on('click', this.onClick, this);
42761 this.el.dom.checked = 'checked' ;
42767 });//<script type="text/javascript">
42770 * Based Ext JS Library 1.1.1
42771 * Copyright(c) 2006-2007, Ext JS, LLC.
42777 * @class Roo.HtmlEditorCore
42778 * @extends Roo.Component
42779 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42781 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42784 Roo.HtmlEditorCore = function(config){
42787 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42792 * @event initialize
42793 * Fires when the editor is fully initialized (including the iframe)
42794 * @param {Roo.HtmlEditorCore} this
42799 * Fires when the editor is first receives the focus. Any insertion must wait
42800 * until after this event.
42801 * @param {Roo.HtmlEditorCore} this
42805 * @event beforesync
42806 * Fires before the textarea is updated with content from the editor iframe. Return false
42807 * to cancel the sync.
42808 * @param {Roo.HtmlEditorCore} this
42809 * @param {String} html
42813 * @event beforepush
42814 * Fires before the iframe editor is updated with content from the textarea. Return false
42815 * to cancel the push.
42816 * @param {Roo.HtmlEditorCore} this
42817 * @param {String} html
42822 * Fires when the textarea is updated with content from the editor iframe.
42823 * @param {Roo.HtmlEditorCore} this
42824 * @param {String} html
42829 * Fires when the iframe editor is updated with content from the textarea.
42830 * @param {Roo.HtmlEditorCore} this
42831 * @param {String} html
42836 * @event editorevent
42837 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42838 * @param {Roo.HtmlEditorCore} this
42844 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42846 // defaults : white / black...
42847 this.applyBlacklists();
42854 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42858 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42864 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42869 * @cfg {Number} height (in pixels)
42873 * @cfg {Number} width (in pixels)
42878 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42881 stylesheets: false,
42886 // private properties
42887 validationEvent : false,
42889 initialized : false,
42891 sourceEditMode : false,
42892 onFocus : Roo.emptyFn,
42894 hideMode:'offsets',
42898 // blacklist + whitelisted elements..
42905 * Protected method that will not generally be called directly. It
42906 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42907 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42909 getDocMarkup : function(){
42913 // inherit styels from page...??
42914 if (this.stylesheets === false) {
42916 Roo.get(document.head).select('style').each(function(node) {
42917 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42920 Roo.get(document.head).select('link').each(function(node) {
42921 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42924 } else if (!this.stylesheets.length) {
42926 st = '<style type="text/css">' +
42927 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42930 st = '<style type="text/css">' +
42935 st += '<style type="text/css">' +
42936 'IMG { cursor: pointer } ' +
42939 var cls = 'roo-htmleditor-body';
42941 if(this.bodyCls.length){
42942 cls += ' ' + this.bodyCls;
42945 return '<html><head>' + st +
42946 //<style type="text/css">' +
42947 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42949 ' </head><body class="' + cls + '"></body></html>';
42953 onRender : function(ct, position)
42956 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42957 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42960 this.el.dom.style.border = '0 none';
42961 this.el.dom.setAttribute('tabIndex', -1);
42962 this.el.addClass('x-hidden hide');
42966 if(Roo.isIE){ // fix IE 1px bogus margin
42967 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42971 this.frameId = Roo.id();
42975 var iframe = this.owner.wrap.createChild({
42977 cls: 'form-control', // bootstrap..
42979 name: this.frameId,
42980 frameBorder : 'no',
42981 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42986 this.iframe = iframe.dom;
42988 this.assignDocWin();
42990 this.doc.designMode = 'on';
42993 this.doc.write(this.getDocMarkup());
42997 var task = { // must defer to wait for browser to be ready
42999 //console.log("run task?" + this.doc.readyState);
43000 this.assignDocWin();
43001 if(this.doc.body || this.doc.readyState == 'complete'){
43003 this.doc.designMode="on";
43007 Roo.TaskMgr.stop(task);
43008 this.initEditor.defer(10, this);
43015 Roo.TaskMgr.start(task);
43020 onResize : function(w, h)
43022 Roo.log('resize: ' +w + ',' + h );
43023 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43027 if(typeof w == 'number'){
43029 this.iframe.style.width = w + 'px';
43031 if(typeof h == 'number'){
43033 this.iframe.style.height = h + 'px';
43035 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43042 * Toggles the editor between standard and source edit mode.
43043 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43045 toggleSourceEdit : function(sourceEditMode){
43047 this.sourceEditMode = sourceEditMode === true;
43049 if(this.sourceEditMode){
43051 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43054 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43055 //this.iframe.className = '';
43058 //this.setSize(this.owner.wrap.getSize());
43059 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43066 * Protected method that will not generally be called directly. If you need/want
43067 * custom HTML cleanup, this is the method you should override.
43068 * @param {String} html The HTML to be cleaned
43069 * return {String} The cleaned HTML
43071 cleanHtml : function(html){
43072 html = String(html);
43073 if(html.length > 5){
43074 if(Roo.isSafari){ // strip safari nonsense
43075 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43078 if(html == ' '){
43085 * HTML Editor -> Textarea
43086 * Protected method that will not generally be called directly. Syncs the contents
43087 * of the editor iframe with the textarea.
43089 syncValue : function(){
43090 if(this.initialized){
43091 var bd = (this.doc.body || this.doc.documentElement);
43092 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43093 var html = bd.innerHTML;
43095 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43096 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43098 html = '<div style="'+m[0]+'">' + html + '</div>';
43101 html = this.cleanHtml(html);
43102 // fix up the special chars.. normaly like back quotes in word...
43103 // however we do not want to do this with chinese..
43104 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43105 var cc = b.charCodeAt();
43107 (cc >= 0x4E00 && cc < 0xA000 ) ||
43108 (cc >= 0x3400 && cc < 0x4E00 ) ||
43109 (cc >= 0xf900 && cc < 0xfb00 )
43115 if(this.owner.fireEvent('beforesync', this, html) !== false){
43116 this.el.dom.value = html;
43117 this.owner.fireEvent('sync', this, html);
43123 * Protected method that will not generally be called directly. Pushes the value of the textarea
43124 * into the iframe editor.
43126 pushValue : function(){
43127 if(this.initialized){
43128 var v = this.el.dom.value.trim();
43130 // if(v.length < 1){
43134 if(this.owner.fireEvent('beforepush', this, v) !== false){
43135 var d = (this.doc.body || this.doc.documentElement);
43137 this.cleanUpPaste();
43138 this.el.dom.value = d.innerHTML;
43139 this.owner.fireEvent('push', this, v);
43145 deferFocus : function(){
43146 this.focus.defer(10, this);
43150 focus : function(){
43151 if(this.win && !this.sourceEditMode){
43158 assignDocWin: function()
43160 var iframe = this.iframe;
43163 this.doc = iframe.contentWindow.document;
43164 this.win = iframe.contentWindow;
43166 // if (!Roo.get(this.frameId)) {
43169 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43170 // this.win = Roo.get(this.frameId).dom.contentWindow;
43172 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43176 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43177 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43182 initEditor : function(){
43183 //console.log("INIT EDITOR");
43184 this.assignDocWin();
43188 this.doc.designMode="on";
43190 this.doc.write(this.getDocMarkup());
43193 var dbody = (this.doc.body || this.doc.documentElement);
43194 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43195 // this copies styles from the containing element into thsi one..
43196 // not sure why we need all of this..
43197 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43199 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43200 //ss['background-attachment'] = 'fixed'; // w3c
43201 dbody.bgProperties = 'fixed'; // ie
43202 //Roo.DomHelper.applyStyles(dbody, ss);
43203 Roo.EventManager.on(this.doc, {
43204 //'mousedown': this.onEditorEvent,
43205 'mouseup': this.onEditorEvent,
43206 'dblclick': this.onEditorEvent,
43207 'click': this.onEditorEvent,
43208 'keyup': this.onEditorEvent,
43213 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43215 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43216 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43218 this.initialized = true;
43220 this.owner.fireEvent('initialize', this);
43225 onDestroy : function(){
43231 //for (var i =0; i < this.toolbars.length;i++) {
43232 // // fixme - ask toolbars for heights?
43233 // this.toolbars[i].onDestroy();
43236 //this.wrap.dom.innerHTML = '';
43237 //this.wrap.remove();
43242 onFirstFocus : function(){
43244 this.assignDocWin();
43247 this.activated = true;
43250 if(Roo.isGecko){ // prevent silly gecko errors
43252 var s = this.win.getSelection();
43253 if(!s.focusNode || s.focusNode.nodeType != 3){
43254 var r = s.getRangeAt(0);
43255 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43260 this.execCmd('useCSS', true);
43261 this.execCmd('styleWithCSS', false);
43264 this.owner.fireEvent('activate', this);
43268 adjustFont: function(btn){
43269 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43270 //if(Roo.isSafari){ // safari
43273 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43274 if(Roo.isSafari){ // safari
43275 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43276 v = (v < 10) ? 10 : v;
43277 v = (v > 48) ? 48 : v;
43278 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43283 v = Math.max(1, v+adjust);
43285 this.execCmd('FontSize', v );
43288 onEditorEvent : function(e)
43290 this.owner.fireEvent('editorevent', this, e);
43291 // this.updateToolbar();
43292 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43295 insertTag : function(tg)
43297 // could be a bit smarter... -> wrap the current selected tRoo..
43298 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43300 range = this.createRange(this.getSelection());
43301 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43302 wrappingNode.appendChild(range.extractContents());
43303 range.insertNode(wrappingNode);
43310 this.execCmd("formatblock", tg);
43314 insertText : function(txt)
43318 var range = this.createRange();
43319 range.deleteContents();
43320 //alert(Sender.getAttribute('label'));
43322 range.insertNode(this.doc.createTextNode(txt));
43328 * Executes a Midas editor command on the editor document and performs necessary focus and
43329 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43330 * @param {String} cmd The Midas command
43331 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43333 relayCmd : function(cmd, value){
43335 this.execCmd(cmd, value);
43336 this.owner.fireEvent('editorevent', this);
43337 //this.updateToolbar();
43338 this.owner.deferFocus();
43342 * Executes a Midas editor command directly on the editor document.
43343 * For visual commands, you should use {@link #relayCmd} instead.
43344 * <b>This should only be called after the editor is initialized.</b>
43345 * @param {String} cmd The Midas command
43346 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43348 execCmd : function(cmd, value){
43349 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43356 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43358 * @param {String} text | dom node..
43360 insertAtCursor : function(text)
43363 if(!this.activated){
43369 var r = this.doc.selection.createRange();
43380 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43384 // from jquery ui (MIT licenced)
43386 var win = this.win;
43388 if (win.getSelection && win.getSelection().getRangeAt) {
43389 range = win.getSelection().getRangeAt(0);
43390 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43391 range.insertNode(node);
43392 } else if (win.document.selection && win.document.selection.createRange) {
43393 // no firefox support
43394 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43395 win.document.selection.createRange().pasteHTML(txt);
43397 // no firefox support
43398 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43399 this.execCmd('InsertHTML', txt);
43408 mozKeyPress : function(e){
43410 var c = e.getCharCode(), cmd;
43413 c = String.fromCharCode(c).toLowerCase();
43427 this.cleanUpPaste.defer(100, this);
43435 e.preventDefault();
43443 fixKeys : function(){ // load time branching for fastest keydown performance
43445 return function(e){
43446 var k = e.getKey(), r;
43449 r = this.doc.selection.createRange();
43452 r.pasteHTML('    ');
43459 r = this.doc.selection.createRange();
43461 var target = r.parentElement();
43462 if(!target || target.tagName.toLowerCase() != 'li'){
43464 r.pasteHTML('<br />');
43470 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43471 this.cleanUpPaste.defer(100, this);
43477 }else if(Roo.isOpera){
43478 return function(e){
43479 var k = e.getKey();
43483 this.execCmd('InsertHTML','    ');
43486 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43487 this.cleanUpPaste.defer(100, this);
43492 }else if(Roo.isSafari){
43493 return function(e){
43494 var k = e.getKey();
43498 this.execCmd('InsertText','\t');
43502 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43503 this.cleanUpPaste.defer(100, this);
43511 getAllAncestors: function()
43513 var p = this.getSelectedNode();
43516 a.push(p); // push blank onto stack..
43517 p = this.getParentElement();
43521 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43525 a.push(this.doc.body);
43529 lastSelNode : false,
43532 getSelection : function()
43534 this.assignDocWin();
43535 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43538 getSelectedNode: function()
43540 // this may only work on Gecko!!!
43542 // should we cache this!!!!
43547 var range = this.createRange(this.getSelection()).cloneRange();
43550 var parent = range.parentElement();
43552 var testRange = range.duplicate();
43553 testRange.moveToElementText(parent);
43554 if (testRange.inRange(range)) {
43557 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43560 parent = parent.parentElement;
43565 // is ancestor a text element.
43566 var ac = range.commonAncestorContainer;
43567 if (ac.nodeType == 3) {
43568 ac = ac.parentNode;
43571 var ar = ac.childNodes;
43574 var other_nodes = [];
43575 var has_other_nodes = false;
43576 for (var i=0;i<ar.length;i++) {
43577 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43580 // fullly contained node.
43582 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43587 // probably selected..
43588 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43589 other_nodes.push(ar[i]);
43593 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43598 has_other_nodes = true;
43600 if (!nodes.length && other_nodes.length) {
43601 nodes= other_nodes;
43603 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43609 createRange: function(sel)
43611 // this has strange effects when using with
43612 // top toolbar - not sure if it's a great idea.
43613 //this.editor.contentWindow.focus();
43614 if (typeof sel != "undefined") {
43616 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43618 return this.doc.createRange();
43621 return this.doc.createRange();
43624 getParentElement: function()
43627 this.assignDocWin();
43628 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43630 var range = this.createRange(sel);
43633 var p = range.commonAncestorContainer;
43634 while (p.nodeType == 3) { // text node
43645 * Range intersection.. the hard stuff...
43649 * [ -- selected range --- ]
43653 * if end is before start or hits it. fail.
43654 * if start is after end or hits it fail.
43656 * if either hits (but other is outside. - then it's not
43662 // @see http://www.thismuchiknow.co.uk/?p=64.
43663 rangeIntersectsNode : function(range, node)
43665 var nodeRange = node.ownerDocument.createRange();
43667 nodeRange.selectNode(node);
43669 nodeRange.selectNodeContents(node);
43672 var rangeStartRange = range.cloneRange();
43673 rangeStartRange.collapse(true);
43675 var rangeEndRange = range.cloneRange();
43676 rangeEndRange.collapse(false);
43678 var nodeStartRange = nodeRange.cloneRange();
43679 nodeStartRange.collapse(true);
43681 var nodeEndRange = nodeRange.cloneRange();
43682 nodeEndRange.collapse(false);
43684 return rangeStartRange.compareBoundaryPoints(
43685 Range.START_TO_START, nodeEndRange) == -1 &&
43686 rangeEndRange.compareBoundaryPoints(
43687 Range.START_TO_START, nodeStartRange) == 1;
43691 rangeCompareNode : function(range, node)
43693 var nodeRange = node.ownerDocument.createRange();
43695 nodeRange.selectNode(node);
43697 nodeRange.selectNodeContents(node);
43701 range.collapse(true);
43703 nodeRange.collapse(true);
43705 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43706 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43708 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43710 var nodeIsBefore = ss == 1;
43711 var nodeIsAfter = ee == -1;
43713 if (nodeIsBefore && nodeIsAfter) {
43716 if (!nodeIsBefore && nodeIsAfter) {
43717 return 1; //right trailed.
43720 if (nodeIsBefore && !nodeIsAfter) {
43721 return 2; // left trailed.
43727 // private? - in a new class?
43728 cleanUpPaste : function()
43730 // cleans up the whole document..
43731 Roo.log('cleanuppaste');
43733 this.cleanUpChildren(this.doc.body);
43734 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43735 if (clean != this.doc.body.innerHTML) {
43736 this.doc.body.innerHTML = clean;
43741 cleanWordChars : function(input) {// change the chars to hex code
43742 var he = Roo.HtmlEditorCore;
43744 var output = input;
43745 Roo.each(he.swapCodes, function(sw) {
43746 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43748 output = output.replace(swapper, sw[1]);
43755 cleanUpChildren : function (n)
43757 if (!n.childNodes.length) {
43760 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43761 this.cleanUpChild(n.childNodes[i]);
43768 cleanUpChild : function (node)
43771 //console.log(node);
43772 if (node.nodeName == "#text") {
43773 // clean up silly Windows -- stuff?
43776 if (node.nodeName == "#comment") {
43777 node.parentNode.removeChild(node);
43778 // clean up silly Windows -- stuff?
43781 var lcname = node.tagName.toLowerCase();
43782 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43783 // whitelist of tags..
43785 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43787 node.parentNode.removeChild(node);
43792 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43794 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43795 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43797 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43798 // remove_keep_children = true;
43801 if (remove_keep_children) {
43802 this.cleanUpChildren(node);
43803 // inserts everything just before this node...
43804 while (node.childNodes.length) {
43805 var cn = node.childNodes[0];
43806 node.removeChild(cn);
43807 node.parentNode.insertBefore(cn, node);
43809 node.parentNode.removeChild(node);
43813 if (!node.attributes || !node.attributes.length) {
43814 this.cleanUpChildren(node);
43818 function cleanAttr(n,v)
43821 if (v.match(/^\./) || v.match(/^\//)) {
43824 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
43827 if (v.match(/^#/)) {
43830 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43831 node.removeAttribute(n);
43835 var cwhite = this.cwhite;
43836 var cblack = this.cblack;
43838 function cleanStyle(n,v)
43840 if (v.match(/expression/)) { //XSS?? should we even bother..
43841 node.removeAttribute(n);
43845 var parts = v.split(/;/);
43848 Roo.each(parts, function(p) {
43849 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43853 var l = p.split(':').shift().replace(/\s+/g,'');
43854 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43856 if ( cwhite.length && cblack.indexOf(l) > -1) {
43857 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43858 //node.removeAttribute(n);
43862 // only allow 'c whitelisted system attributes'
43863 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43864 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43865 //node.removeAttribute(n);
43875 if (clean.length) {
43876 node.setAttribute(n, clean.join(';'));
43878 node.removeAttribute(n);
43884 for (var i = node.attributes.length-1; i > -1 ; i--) {
43885 var a = node.attributes[i];
43888 if (a.name.toLowerCase().substr(0,2)=='on') {
43889 node.removeAttribute(a.name);
43892 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43893 node.removeAttribute(a.name);
43896 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43897 cleanAttr(a.name,a.value); // fixme..
43900 if (a.name == 'style') {
43901 cleanStyle(a.name,a.value);
43904 /// clean up MS crap..
43905 // tecnically this should be a list of valid class'es..
43908 if (a.name == 'class') {
43909 if (a.value.match(/^Mso/)) {
43910 node.className = '';
43913 if (a.value.match(/^body$/)) {
43914 node.className = '';
43925 this.cleanUpChildren(node);
43931 * Clean up MS wordisms...
43933 cleanWord : function(node)
43938 this.cleanWord(this.doc.body);
43941 if (node.nodeName == "#text") {
43942 // clean up silly Windows -- stuff?
43945 if (node.nodeName == "#comment") {
43946 node.parentNode.removeChild(node);
43947 // clean up silly Windows -- stuff?
43951 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43952 node.parentNode.removeChild(node);
43956 // remove - but keep children..
43957 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43958 while (node.childNodes.length) {
43959 var cn = node.childNodes[0];
43960 node.removeChild(cn);
43961 node.parentNode.insertBefore(cn, node);
43963 node.parentNode.removeChild(node);
43964 this.iterateChildren(node, this.cleanWord);
43968 if (node.className.length) {
43970 var cn = node.className.split(/\W+/);
43972 Roo.each(cn, function(cls) {
43973 if (cls.match(/Mso[a-zA-Z]+/)) {
43978 node.className = cna.length ? cna.join(' ') : '';
43980 node.removeAttribute("class");
43984 if (node.hasAttribute("lang")) {
43985 node.removeAttribute("lang");
43988 if (node.hasAttribute("style")) {
43990 var styles = node.getAttribute("style").split(";");
43992 Roo.each(styles, function(s) {
43993 if (!s.match(/:/)) {
43996 var kv = s.split(":");
43997 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44000 // what ever is left... we allow.
44003 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44004 if (!nstyle.length) {
44005 node.removeAttribute('style');
44008 this.iterateChildren(node, this.cleanWord);
44014 * iterateChildren of a Node, calling fn each time, using this as the scole..
44015 * @param {DomNode} node node to iterate children of.
44016 * @param {Function} fn method of this class to call on each item.
44018 iterateChildren : function(node, fn)
44020 if (!node.childNodes.length) {
44023 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44024 fn.call(this, node.childNodes[i])
44030 * cleanTableWidths.
44032 * Quite often pasting from word etc.. results in tables with column and widths.
44033 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44036 cleanTableWidths : function(node)
44041 this.cleanTableWidths(this.doc.body);
44046 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44049 Roo.log(node.tagName);
44050 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44051 this.iterateChildren(node, this.cleanTableWidths);
44054 if (node.hasAttribute('width')) {
44055 node.removeAttribute('width');
44059 if (node.hasAttribute("style")) {
44062 var styles = node.getAttribute("style").split(";");
44064 Roo.each(styles, function(s) {
44065 if (!s.match(/:/)) {
44068 var kv = s.split(":");
44069 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44072 // what ever is left... we allow.
44075 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44076 if (!nstyle.length) {
44077 node.removeAttribute('style');
44081 this.iterateChildren(node, this.cleanTableWidths);
44089 domToHTML : function(currentElement, depth, nopadtext) {
44091 depth = depth || 0;
44092 nopadtext = nopadtext || false;
44094 if (!currentElement) {
44095 return this.domToHTML(this.doc.body);
44098 //Roo.log(currentElement);
44100 var allText = false;
44101 var nodeName = currentElement.nodeName;
44102 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44104 if (nodeName == '#text') {
44106 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44111 if (nodeName != 'BODY') {
44114 // Prints the node tagName, such as <A>, <IMG>, etc
44117 for(i = 0; i < currentElement.attributes.length;i++) {
44119 var aname = currentElement.attributes.item(i).name;
44120 if (!currentElement.attributes.item(i).value.length) {
44123 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44126 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44135 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44138 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44143 // Traverse the tree
44145 var currentElementChild = currentElement.childNodes.item(i);
44146 var allText = true;
44147 var innerHTML = '';
44149 while (currentElementChild) {
44150 // Formatting code (indent the tree so it looks nice on the screen)
44151 var nopad = nopadtext;
44152 if (lastnode == 'SPAN') {
44156 if (currentElementChild.nodeName == '#text') {
44157 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44158 toadd = nopadtext ? toadd : toadd.trim();
44159 if (!nopad && toadd.length > 80) {
44160 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44162 innerHTML += toadd;
44165 currentElementChild = currentElement.childNodes.item(i);
44171 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44173 // Recursively traverse the tree structure of the child node
44174 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44175 lastnode = currentElementChild.nodeName;
44177 currentElementChild=currentElement.childNodes.item(i);
44183 // The remaining code is mostly for formatting the tree
44184 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44189 ret+= "</"+tagName+">";
44195 applyBlacklists : function()
44197 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44198 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44202 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44203 if (b.indexOf(tag) > -1) {
44206 this.white.push(tag);
44210 Roo.each(w, function(tag) {
44211 if (b.indexOf(tag) > -1) {
44214 if (this.white.indexOf(tag) > -1) {
44217 this.white.push(tag);
44222 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44223 if (w.indexOf(tag) > -1) {
44226 this.black.push(tag);
44230 Roo.each(b, function(tag) {
44231 if (w.indexOf(tag) > -1) {
44234 if (this.black.indexOf(tag) > -1) {
44237 this.black.push(tag);
44242 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44243 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44247 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44248 if (b.indexOf(tag) > -1) {
44251 this.cwhite.push(tag);
44255 Roo.each(w, function(tag) {
44256 if (b.indexOf(tag) > -1) {
44259 if (this.cwhite.indexOf(tag) > -1) {
44262 this.cwhite.push(tag);
44267 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44268 if (w.indexOf(tag) > -1) {
44271 this.cblack.push(tag);
44275 Roo.each(b, function(tag) {
44276 if (w.indexOf(tag) > -1) {
44279 if (this.cblack.indexOf(tag) > -1) {
44282 this.cblack.push(tag);
44287 setStylesheets : function(stylesheets)
44289 if(typeof(stylesheets) == 'string'){
44290 Roo.get(this.iframe.contentDocument.head).createChild({
44292 rel : 'stylesheet',
44301 Roo.each(stylesheets, function(s) {
44306 Roo.get(_this.iframe.contentDocument.head).createChild({
44308 rel : 'stylesheet',
44317 removeStylesheets : function()
44321 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44326 setStyle : function(style)
44328 Roo.get(this.iframe.contentDocument.head).createChild({
44337 // hide stuff that is not compatible
44351 * @event specialkey
44355 * @cfg {String} fieldClass @hide
44358 * @cfg {String} focusClass @hide
44361 * @cfg {String} autoCreate @hide
44364 * @cfg {String} inputType @hide
44367 * @cfg {String} invalidClass @hide
44370 * @cfg {String} invalidText @hide
44373 * @cfg {String} msgFx @hide
44376 * @cfg {String} validateOnBlur @hide
44380 Roo.HtmlEditorCore.white = [
44381 'area', 'br', 'img', 'input', 'hr', 'wbr',
44383 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44384 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44385 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44386 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44387 'table', 'ul', 'xmp',
44389 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44392 'dir', 'menu', 'ol', 'ul', 'dl',
44398 Roo.HtmlEditorCore.black = [
44399 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44401 'base', 'basefont', 'bgsound', 'blink', 'body',
44402 'frame', 'frameset', 'head', 'html', 'ilayer',
44403 'iframe', 'layer', 'link', 'meta', 'object',
44404 'script', 'style' ,'title', 'xml' // clean later..
44406 Roo.HtmlEditorCore.clean = [
44407 'script', 'style', 'title', 'xml'
44409 Roo.HtmlEditorCore.remove = [
44414 Roo.HtmlEditorCore.ablack = [
44418 Roo.HtmlEditorCore.aclean = [
44419 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44423 Roo.HtmlEditorCore.pwhite= [
44424 'http', 'https', 'mailto'
44427 // white listed style attributes.
44428 Roo.HtmlEditorCore.cwhite= [
44429 // 'text-align', /// default is to allow most things..
44435 // black listed style attributes.
44436 Roo.HtmlEditorCore.cblack= [
44437 // 'font-size' -- this can be set by the project
44441 Roo.HtmlEditorCore.swapCodes =[
44452 //<script type="text/javascript">
44455 * Ext JS Library 1.1.1
44456 * Copyright(c) 2006-2007, Ext JS, LLC.
44462 Roo.form.HtmlEditor = function(config){
44466 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44468 if (!this.toolbars) {
44469 this.toolbars = [];
44471 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44477 * @class Roo.form.HtmlEditor
44478 * @extends Roo.form.Field
44479 * Provides a lightweight HTML Editor component.
44481 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44483 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44484 * supported by this editor.</b><br/><br/>
44485 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44486 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44488 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44490 * @cfg {Boolean} clearUp
44494 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44499 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44504 * @cfg {Number} height (in pixels)
44508 * @cfg {Number} width (in pixels)
44513 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44516 stylesheets: false,
44520 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44525 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44531 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44536 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44544 // private properties
44545 validationEvent : false,
44547 initialized : false,
44550 onFocus : Roo.emptyFn,
44552 hideMode:'offsets',
44554 actionMode : 'container', // defaults to hiding it...
44556 defaultAutoCreate : { // modified by initCompnoent..
44558 style:"width:500px;height:300px;",
44559 autocomplete: "new-password"
44563 initComponent : function(){
44566 * @event initialize
44567 * Fires when the editor is fully initialized (including the iframe)
44568 * @param {HtmlEditor} this
44573 * Fires when the editor is first receives the focus. Any insertion must wait
44574 * until after this event.
44575 * @param {HtmlEditor} this
44579 * @event beforesync
44580 * Fires before the textarea is updated with content from the editor iframe. Return false
44581 * to cancel the sync.
44582 * @param {HtmlEditor} this
44583 * @param {String} html
44587 * @event beforepush
44588 * Fires before the iframe editor is updated with content from the textarea. Return false
44589 * to cancel the push.
44590 * @param {HtmlEditor} this
44591 * @param {String} html
44596 * Fires when the textarea is updated with content from the editor iframe.
44597 * @param {HtmlEditor} this
44598 * @param {String} html
44603 * Fires when the iframe editor is updated with content from the textarea.
44604 * @param {HtmlEditor} this
44605 * @param {String} html
44609 * @event editmodechange
44610 * Fires when the editor switches edit modes
44611 * @param {HtmlEditor} this
44612 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44614 editmodechange: true,
44616 * @event editorevent
44617 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44618 * @param {HtmlEditor} this
44622 * @event firstfocus
44623 * Fires when on first focus - needed by toolbars..
44624 * @param {HtmlEditor} this
44629 * Auto save the htmlEditor value as a file into Events
44630 * @param {HtmlEditor} this
44634 * @event savedpreview
44635 * preview the saved version of htmlEditor
44636 * @param {HtmlEditor} this
44638 savedpreview: true,
44641 * @event stylesheetsclick
44642 * Fires when press the Sytlesheets button
44643 * @param {Roo.HtmlEditorCore} this
44645 stylesheetsclick: true
44647 this.defaultAutoCreate = {
44649 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44650 autocomplete: "new-password"
44655 * Protected method that will not generally be called directly. It
44656 * is called when the editor creates its toolbar. Override this method if you need to
44657 * add custom toolbar buttons.
44658 * @param {HtmlEditor} editor
44660 createToolbar : function(editor){
44661 Roo.log("create toolbars");
44662 if (!editor.toolbars || !editor.toolbars.length) {
44663 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44666 for (var i =0 ; i < editor.toolbars.length;i++) {
44667 editor.toolbars[i] = Roo.factory(
44668 typeof(editor.toolbars[i]) == 'string' ?
44669 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44670 Roo.form.HtmlEditor);
44671 editor.toolbars[i].init(editor);
44679 onRender : function(ct, position)
44682 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44684 this.wrap = this.el.wrap({
44685 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44688 this.editorcore.onRender(ct, position);
44690 if (this.resizable) {
44691 this.resizeEl = new Roo.Resizable(this.wrap, {
44695 minHeight : this.height,
44696 height: this.height,
44697 handles : this.resizable,
44700 resize : function(r, w, h) {
44701 _t.onResize(w,h); // -something
44707 this.createToolbar(this);
44711 this.setSize(this.wrap.getSize());
44713 if (this.resizeEl) {
44714 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44715 // should trigger onReize..
44718 this.keyNav = new Roo.KeyNav(this.el, {
44720 "tab" : function(e){
44721 e.preventDefault();
44723 var value = this.getValue();
44725 var start = this.el.dom.selectionStart;
44726 var end = this.el.dom.selectionEnd;
44730 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44731 this.el.dom.setSelectionRange(end + 1, end + 1);
44735 var f = value.substring(0, start).split("\t");
44737 if(f.pop().length != 0){
44741 this.setValue(f.join("\t") + value.substring(end));
44742 this.el.dom.setSelectionRange(start - 1, start - 1);
44746 "home" : function(e){
44747 e.preventDefault();
44749 var curr = this.el.dom.selectionStart;
44750 var lines = this.getValue().split("\n");
44757 this.el.dom.setSelectionRange(0, 0);
44763 for (var i = 0; i < lines.length;i++) {
44764 pos += lines[i].length;
44774 pos -= lines[i].length;
44780 this.el.dom.setSelectionRange(pos, pos);
44784 this.el.dom.selectionStart = pos;
44785 this.el.dom.selectionEnd = curr;
44788 "end" : function(e){
44789 e.preventDefault();
44791 var curr = this.el.dom.selectionStart;
44792 var lines = this.getValue().split("\n");
44799 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44805 for (var i = 0; i < lines.length;i++) {
44807 pos += lines[i].length;
44821 this.el.dom.setSelectionRange(pos, pos);
44825 this.el.dom.selectionStart = curr;
44826 this.el.dom.selectionEnd = pos;
44831 doRelay : function(foo, bar, hname){
44832 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44838 // if(this.autosave && this.w){
44839 // this.autoSaveFn = setInterval(this.autosave, 1000);
44844 onResize : function(w, h)
44846 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44851 if(typeof w == 'number'){
44852 var aw = w - this.wrap.getFrameWidth('lr');
44853 this.el.setWidth(this.adjustWidth('textarea', aw));
44856 if(typeof h == 'number'){
44858 for (var i =0; i < this.toolbars.length;i++) {
44859 // fixme - ask toolbars for heights?
44860 tbh += this.toolbars[i].tb.el.getHeight();
44861 if (this.toolbars[i].footer) {
44862 tbh += this.toolbars[i].footer.el.getHeight();
44869 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44870 ah -= 5; // knock a few pixes off for look..
44872 this.el.setHeight(this.adjustWidth('textarea', ah));
44876 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44877 this.editorcore.onResize(ew,eh);
44882 * Toggles the editor between standard and source edit mode.
44883 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44885 toggleSourceEdit : function(sourceEditMode)
44887 this.editorcore.toggleSourceEdit(sourceEditMode);
44889 if(this.editorcore.sourceEditMode){
44890 Roo.log('editor - showing textarea');
44893 // Roo.log(this.syncValue());
44894 this.editorcore.syncValue();
44895 this.el.removeClass('x-hidden');
44896 this.el.dom.removeAttribute('tabIndex');
44899 for (var i = 0; i < this.toolbars.length; i++) {
44900 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44901 this.toolbars[i].tb.hide();
44902 this.toolbars[i].footer.hide();
44907 Roo.log('editor - hiding textarea');
44909 // Roo.log(this.pushValue());
44910 this.editorcore.pushValue();
44912 this.el.addClass('x-hidden');
44913 this.el.dom.setAttribute('tabIndex', -1);
44915 for (var i = 0; i < this.toolbars.length; i++) {
44916 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44917 this.toolbars[i].tb.show();
44918 this.toolbars[i].footer.show();
44922 //this.deferFocus();
44925 this.setSize(this.wrap.getSize());
44926 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44928 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44931 // private (for BoxComponent)
44932 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44934 // private (for BoxComponent)
44935 getResizeEl : function(){
44939 // private (for BoxComponent)
44940 getPositionEl : function(){
44945 initEvents : function(){
44946 this.originalValue = this.getValue();
44950 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44953 markInvalid : Roo.emptyFn,
44955 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44958 clearInvalid : Roo.emptyFn,
44960 setValue : function(v){
44961 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44962 this.editorcore.pushValue();
44967 deferFocus : function(){
44968 this.focus.defer(10, this);
44972 focus : function(){
44973 this.editorcore.focus();
44979 onDestroy : function(){
44985 for (var i =0; i < this.toolbars.length;i++) {
44986 // fixme - ask toolbars for heights?
44987 this.toolbars[i].onDestroy();
44990 this.wrap.dom.innerHTML = '';
44991 this.wrap.remove();
44996 onFirstFocus : function(){
44997 //Roo.log("onFirstFocus");
44998 this.editorcore.onFirstFocus();
44999 for (var i =0; i < this.toolbars.length;i++) {
45000 this.toolbars[i].onFirstFocus();
45006 syncValue : function()
45008 this.editorcore.syncValue();
45011 pushValue : function()
45013 this.editorcore.pushValue();
45016 setStylesheets : function(stylesheets)
45018 this.editorcore.setStylesheets(stylesheets);
45021 removeStylesheets : function()
45023 this.editorcore.removeStylesheets();
45027 // hide stuff that is not compatible
45041 * @event specialkey
45045 * @cfg {String} fieldClass @hide
45048 * @cfg {String} focusClass @hide
45051 * @cfg {String} autoCreate @hide
45054 * @cfg {String} inputType @hide
45057 * @cfg {String} invalidClass @hide
45060 * @cfg {String} invalidText @hide
45063 * @cfg {String} msgFx @hide
45066 * @cfg {String} validateOnBlur @hide
45070 // <script type="text/javascript">
45073 * Ext JS Library 1.1.1
45074 * Copyright(c) 2006-2007, Ext JS, LLC.
45080 * @class Roo.form.HtmlEditorToolbar1
45085 new Roo.form.HtmlEditor({
45088 new Roo.form.HtmlEditorToolbar1({
45089 disable : { fonts: 1 , format: 1, ..., ... , ...],
45095 * @cfg {Object} disable List of elements to disable..
45096 * @cfg {Array} btns List of additional buttons.
45100 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45103 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45106 Roo.apply(this, config);
45108 // default disabled, based on 'good practice'..
45109 this.disable = this.disable || {};
45110 Roo.applyIf(this.disable, {
45113 specialElements : true
45117 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45118 // dont call parent... till later.
45121 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45128 editorcore : false,
45130 * @cfg {Object} disable List of toolbar elements to disable
45137 * @cfg {String} createLinkText The default text for the create link prompt
45139 createLinkText : 'Please enter the URL for the link:',
45141 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45143 defaultLinkValue : 'http:/'+'/',
45147 * @cfg {Array} fontFamilies An array of available font families
45165 // "á" , ?? a acute?
45170 "°" // , // degrees
45172 // "é" , // e ecute
45173 // "ú" , // u ecute?
45176 specialElements : [
45178 text: "Insert Table",
45181 ihtml : '<table><tr><td>Cell</td></tr></table>'
45185 text: "Insert Image",
45188 ihtml : '<img src="about:blank"/>'
45197 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45198 "input:submit", "input:button", "select", "textarea", "label" ],
45201 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45203 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45211 * @cfg {String} defaultFont default font to use.
45213 defaultFont: 'tahoma',
45215 fontSelect : false,
45218 formatCombo : false,
45220 init : function(editor)
45222 this.editor = editor;
45223 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45224 var editorcore = this.editorcore;
45228 var fid = editorcore.frameId;
45230 function btn(id, toggle, handler){
45231 var xid = fid + '-'+ id ;
45235 cls : 'x-btn-icon x-edit-'+id,
45236 enableToggle:toggle !== false,
45237 scope: _t, // was editor...
45238 handler:handler||_t.relayBtnCmd,
45239 clickEvent:'mousedown',
45240 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45247 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45249 // stop form submits
45250 tb.el.on('click', function(e){
45251 e.preventDefault(); // what does this do?
45254 if(!this.disable.font) { // && !Roo.isSafari){
45255 /* why no safari for fonts
45256 editor.fontSelect = tb.el.createChild({
45259 cls:'x-font-select',
45260 html: this.createFontOptions()
45263 editor.fontSelect.on('change', function(){
45264 var font = editor.fontSelect.dom.value;
45265 editor.relayCmd('fontname', font);
45266 editor.deferFocus();
45270 editor.fontSelect.dom,
45276 if(!this.disable.formats){
45277 this.formatCombo = new Roo.form.ComboBox({
45278 store: new Roo.data.SimpleStore({
45281 data : this.formats // from states.js
45285 //autoCreate : {tag: "div", size: "20"},
45286 displayField:'tag',
45290 triggerAction: 'all',
45291 emptyText:'Add tag',
45292 selectOnFocus:true,
45295 'select': function(c, r, i) {
45296 editorcore.insertTag(r.get('tag'));
45302 tb.addField(this.formatCombo);
45306 if(!this.disable.format){
45311 btn('strikethrough')
45314 if(!this.disable.fontSize){
45319 btn('increasefontsize', false, editorcore.adjustFont),
45320 btn('decreasefontsize', false, editorcore.adjustFont)
45325 if(!this.disable.colors){
45328 id:editorcore.frameId +'-forecolor',
45329 cls:'x-btn-icon x-edit-forecolor',
45330 clickEvent:'mousedown',
45331 tooltip: this.buttonTips['forecolor'] || undefined,
45333 menu : new Roo.menu.ColorMenu({
45334 allowReselect: true,
45335 focus: Roo.emptyFn,
45338 selectHandler: function(cp, color){
45339 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45340 editor.deferFocus();
45343 clickEvent:'mousedown'
45346 id:editorcore.frameId +'backcolor',
45347 cls:'x-btn-icon x-edit-backcolor',
45348 clickEvent:'mousedown',
45349 tooltip: this.buttonTips['backcolor'] || undefined,
45351 menu : new Roo.menu.ColorMenu({
45352 focus: Roo.emptyFn,
45355 allowReselect: true,
45356 selectHandler: function(cp, color){
45358 editorcore.execCmd('useCSS', false);
45359 editorcore.execCmd('hilitecolor', color);
45360 editorcore.execCmd('useCSS', true);
45361 editor.deferFocus();
45363 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45364 Roo.isSafari || Roo.isIE ? '#'+color : color);
45365 editor.deferFocus();
45369 clickEvent:'mousedown'
45374 // now add all the items...
45377 if(!this.disable.alignments){
45380 btn('justifyleft'),
45381 btn('justifycenter'),
45382 btn('justifyright')
45386 //if(!Roo.isSafari){
45387 if(!this.disable.links){
45390 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45394 if(!this.disable.lists){
45397 btn('insertorderedlist'),
45398 btn('insertunorderedlist')
45401 if(!this.disable.sourceEdit){
45404 btn('sourceedit', true, function(btn){
45405 this.toggleSourceEdit(btn.pressed);
45412 // special menu.. - needs to be tidied up..
45413 if (!this.disable.special) {
45416 cls: 'x-edit-none',
45422 for (var i =0; i < this.specialChars.length; i++) {
45423 smenu.menu.items.push({
45425 html: this.specialChars[i],
45426 handler: function(a,b) {
45427 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45428 //editor.insertAtCursor(a.html);
45442 if (!this.disable.cleanStyles) {
45444 cls: 'x-btn-icon x-btn-clear',
45450 for (var i =0; i < this.cleanStyles.length; i++) {
45451 cmenu.menu.items.push({
45452 actiontype : this.cleanStyles[i],
45453 html: 'Remove ' + this.cleanStyles[i],
45454 handler: function(a,b) {
45457 var c = Roo.get(editorcore.doc.body);
45458 c.select('[style]').each(function(s) {
45459 s.dom.style.removeProperty(a.actiontype);
45461 editorcore.syncValue();
45466 cmenu.menu.items.push({
45467 actiontype : 'tablewidths',
45468 html: 'Remove Table Widths',
45469 handler: function(a,b) {
45470 editorcore.cleanTableWidths();
45471 editorcore.syncValue();
45475 cmenu.menu.items.push({
45476 actiontype : 'word',
45477 html: 'Remove MS Word Formating',
45478 handler: function(a,b) {
45479 editorcore.cleanWord();
45480 editorcore.syncValue();
45485 cmenu.menu.items.push({
45486 actiontype : 'all',
45487 html: 'Remove All Styles',
45488 handler: function(a,b) {
45490 var c = Roo.get(editorcore.doc.body);
45491 c.select('[style]').each(function(s) {
45492 s.dom.removeAttribute('style');
45494 editorcore.syncValue();
45499 cmenu.menu.items.push({
45500 actiontype : 'all',
45501 html: 'Remove All CSS Classes',
45502 handler: function(a,b) {
45504 var c = Roo.get(editorcore.doc.body);
45505 c.select('[class]').each(function(s) {
45506 s.dom.className = '';
45508 editorcore.syncValue();
45513 cmenu.menu.items.push({
45514 actiontype : 'tidy',
45515 html: 'Tidy HTML Source',
45516 handler: function(a,b) {
45517 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45518 editorcore.syncValue();
45527 if (!this.disable.specialElements) {
45530 cls: 'x-edit-none',
45535 for (var i =0; i < this.specialElements.length; i++) {
45536 semenu.menu.items.push(
45538 handler: function(a,b) {
45539 editor.insertAtCursor(this.ihtml);
45541 }, this.specialElements[i])
45553 for(var i =0; i< this.btns.length;i++) {
45554 var b = Roo.factory(this.btns[i],Roo.form);
45555 b.cls = 'x-edit-none';
45557 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45558 b.cls += ' x-init-enable';
45561 b.scope = editorcore;
45569 // disable everything...
45571 this.tb.items.each(function(item){
45574 item.id != editorcore.frameId+ '-sourceedit' &&
45575 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45581 this.rendered = true;
45583 // the all the btns;
45584 editor.on('editorevent', this.updateToolbar, this);
45585 // other toolbars need to implement this..
45586 //editor.on('editmodechange', this.updateToolbar, this);
45590 relayBtnCmd : function(btn) {
45591 this.editorcore.relayCmd(btn.cmd);
45593 // private used internally
45594 createLink : function(){
45595 Roo.log("create link?");
45596 var url = prompt(this.createLinkText, this.defaultLinkValue);
45597 if(url && url != 'http:/'+'/'){
45598 this.editorcore.relayCmd('createlink', url);
45604 * Protected method that will not generally be called directly. It triggers
45605 * a toolbar update by reading the markup state of the current selection in the editor.
45607 updateToolbar: function(){
45609 if(!this.editorcore.activated){
45610 this.editor.onFirstFocus();
45614 var btns = this.tb.items.map,
45615 doc = this.editorcore.doc,
45616 frameId = this.editorcore.frameId;
45618 if(!this.disable.font && !Roo.isSafari){
45620 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45621 if(name != this.fontSelect.dom.value){
45622 this.fontSelect.dom.value = name;
45626 if(!this.disable.format){
45627 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45628 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45629 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45630 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45632 if(!this.disable.alignments){
45633 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45634 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45635 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45637 if(!Roo.isSafari && !this.disable.lists){
45638 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45639 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45642 var ans = this.editorcore.getAllAncestors();
45643 if (this.formatCombo) {
45646 var store = this.formatCombo.store;
45647 this.formatCombo.setValue("");
45648 for (var i =0; i < ans.length;i++) {
45649 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45651 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45659 // hides menus... - so this cant be on a menu...
45660 Roo.menu.MenuMgr.hideAll();
45662 //this.editorsyncValue();
45666 createFontOptions : function(){
45667 var buf = [], fs = this.fontFamilies, ff, lc;
45671 for(var i = 0, len = fs.length; i< len; i++){
45673 lc = ff.toLowerCase();
45675 '<option value="',lc,'" style="font-family:',ff,';"',
45676 (this.defaultFont == lc ? ' selected="true">' : '>'),
45681 return buf.join('');
45684 toggleSourceEdit : function(sourceEditMode){
45686 Roo.log("toolbar toogle");
45687 if(sourceEditMode === undefined){
45688 sourceEditMode = !this.sourceEditMode;
45690 this.sourceEditMode = sourceEditMode === true;
45691 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45692 // just toggle the button?
45693 if(btn.pressed !== this.sourceEditMode){
45694 btn.toggle(this.sourceEditMode);
45698 if(sourceEditMode){
45699 Roo.log("disabling buttons");
45700 this.tb.items.each(function(item){
45701 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45707 Roo.log("enabling buttons");
45708 if(this.editorcore.initialized){
45709 this.tb.items.each(function(item){
45715 Roo.log("calling toggole on editor");
45716 // tell the editor that it's been pressed..
45717 this.editor.toggleSourceEdit(sourceEditMode);
45721 * Object collection of toolbar tooltips for the buttons in the editor. The key
45722 * is the command id associated with that button and the value is a valid QuickTips object.
45727 title: 'Bold (Ctrl+B)',
45728 text: 'Make the selected text bold.',
45729 cls: 'x-html-editor-tip'
45732 title: 'Italic (Ctrl+I)',
45733 text: 'Make the selected text italic.',
45734 cls: 'x-html-editor-tip'
45742 title: 'Bold (Ctrl+B)',
45743 text: 'Make the selected text bold.',
45744 cls: 'x-html-editor-tip'
45747 title: 'Italic (Ctrl+I)',
45748 text: 'Make the selected text italic.',
45749 cls: 'x-html-editor-tip'
45752 title: 'Underline (Ctrl+U)',
45753 text: 'Underline the selected text.',
45754 cls: 'x-html-editor-tip'
45757 title: 'Strikethrough',
45758 text: 'Strikethrough the selected text.',
45759 cls: 'x-html-editor-tip'
45761 increasefontsize : {
45762 title: 'Grow Text',
45763 text: 'Increase the font size.',
45764 cls: 'x-html-editor-tip'
45766 decreasefontsize : {
45767 title: 'Shrink Text',
45768 text: 'Decrease the font size.',
45769 cls: 'x-html-editor-tip'
45772 title: 'Text Highlight Color',
45773 text: 'Change the background color of the selected text.',
45774 cls: 'x-html-editor-tip'
45777 title: 'Font Color',
45778 text: 'Change the color of the selected text.',
45779 cls: 'x-html-editor-tip'
45782 title: 'Align Text Left',
45783 text: 'Align text to the left.',
45784 cls: 'x-html-editor-tip'
45787 title: 'Center Text',
45788 text: 'Center text in the editor.',
45789 cls: 'x-html-editor-tip'
45792 title: 'Align Text Right',
45793 text: 'Align text to the right.',
45794 cls: 'x-html-editor-tip'
45796 insertunorderedlist : {
45797 title: 'Bullet List',
45798 text: 'Start a bulleted list.',
45799 cls: 'x-html-editor-tip'
45801 insertorderedlist : {
45802 title: 'Numbered List',
45803 text: 'Start a numbered list.',
45804 cls: 'x-html-editor-tip'
45807 title: 'Hyperlink',
45808 text: 'Make the selected text a hyperlink.',
45809 cls: 'x-html-editor-tip'
45812 title: 'Source Edit',
45813 text: 'Switch to source editing mode.',
45814 cls: 'x-html-editor-tip'
45818 onDestroy : function(){
45821 this.tb.items.each(function(item){
45823 item.menu.removeAll();
45825 item.menu.el.destroy();
45833 onFirstFocus: function() {
45834 this.tb.items.each(function(item){
45843 // <script type="text/javascript">
45846 * Ext JS Library 1.1.1
45847 * Copyright(c) 2006-2007, Ext JS, LLC.
45854 * @class Roo.form.HtmlEditor.ToolbarContext
45859 new Roo.form.HtmlEditor({
45862 { xtype: 'ToolbarStandard', styles : {} }
45863 { xtype: 'ToolbarContext', disable : {} }
45869 * @config : {Object} disable List of elements to disable.. (not done yet.)
45870 * @config : {Object} styles Map of styles available.
45874 Roo.form.HtmlEditor.ToolbarContext = function(config)
45877 Roo.apply(this, config);
45878 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45879 // dont call parent... till later.
45880 this.styles = this.styles || {};
45885 Roo.form.HtmlEditor.ToolbarContext.types = {
45897 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45963 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45968 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45978 style : 'fontFamily',
45979 displayField: 'display',
45980 optname : 'font-family',
46029 // should we really allow this??
46030 // should this just be
46041 style : 'fontFamily',
46042 displayField: 'display',
46043 optname : 'font-family',
46050 style : 'fontFamily',
46051 displayField: 'display',
46052 optname : 'font-family',
46059 style : 'fontFamily',
46060 displayField: 'display',
46061 optname : 'font-family',
46072 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46073 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46075 Roo.form.HtmlEditor.ToolbarContext.options = {
46077 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46078 [ 'Courier New', 'Courier New'],
46079 [ 'Tahoma', 'Tahoma'],
46080 [ 'Times New Roman,serif', 'Times'],
46081 [ 'Verdana','Verdana' ]
46085 // fixme - these need to be configurable..
46088 //Roo.form.HtmlEditor.ToolbarContext.types
46091 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46098 editorcore : false,
46100 * @cfg {Object} disable List of toolbar elements to disable
46105 * @cfg {Object} styles List of styles
46106 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46108 * These must be defined in the page, so they get rendered correctly..
46119 init : function(editor)
46121 this.editor = editor;
46122 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46123 var editorcore = this.editorcore;
46125 var fid = editorcore.frameId;
46127 function btn(id, toggle, handler){
46128 var xid = fid + '-'+ id ;
46132 cls : 'x-btn-icon x-edit-'+id,
46133 enableToggle:toggle !== false,
46134 scope: editorcore, // was editor...
46135 handler:handler||editorcore.relayBtnCmd,
46136 clickEvent:'mousedown',
46137 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46141 // create a new element.
46142 var wdiv = editor.wrap.createChild({
46144 }, editor.wrap.dom.firstChild.nextSibling, true);
46146 // can we do this more than once??
46148 // stop form submits
46151 // disable everything...
46152 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46153 this.toolbars = {};
46155 for (var i in ty) {
46157 this.toolbars[i] = this.buildToolbar(ty[i],i);
46159 this.tb = this.toolbars.BODY;
46161 this.buildFooter();
46162 this.footer.show();
46163 editor.on('hide', function( ) { this.footer.hide() }, this);
46164 editor.on('show', function( ) { this.footer.show() }, this);
46167 this.rendered = true;
46169 // the all the btns;
46170 editor.on('editorevent', this.updateToolbar, this);
46171 // other toolbars need to implement this..
46172 //editor.on('editmodechange', this.updateToolbar, this);
46178 * Protected method that will not generally be called directly. It triggers
46179 * a toolbar update by reading the markup state of the current selection in the editor.
46181 * Note you can force an update by calling on('editorevent', scope, false)
46183 updateToolbar: function(editor,ev,sel){
46186 // capture mouse up - this is handy for selecting images..
46187 // perhaps should go somewhere else...
46188 if(!this.editorcore.activated){
46189 this.editor.onFirstFocus();
46195 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46196 // selectNode - might want to handle IE?
46198 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46199 ev.target && ev.target.tagName == 'IMG') {
46200 // they have click on an image...
46201 // let's see if we can change the selection...
46204 var nodeRange = sel.ownerDocument.createRange();
46206 nodeRange.selectNode(sel);
46208 nodeRange.selectNodeContents(sel);
46210 //nodeRange.collapse(true);
46211 var s = this.editorcore.win.getSelection();
46212 s.removeAllRanges();
46213 s.addRange(nodeRange);
46217 var updateFooter = sel ? false : true;
46220 var ans = this.editorcore.getAllAncestors();
46223 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46226 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46227 sel = sel ? sel : this.editorcore.doc.body;
46228 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46231 // pick a menu that exists..
46232 var tn = sel.tagName.toUpperCase();
46233 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46235 tn = sel.tagName.toUpperCase();
46237 var lastSel = this.tb.selectedNode;
46239 this.tb.selectedNode = sel;
46241 // if current menu does not match..
46243 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46246 ///console.log("show: " + tn);
46247 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46250 this.tb.items.first().el.innerHTML = tn + ': ';
46253 // update attributes
46254 if (this.tb.fields) {
46255 this.tb.fields.each(function(e) {
46257 e.setValue(sel.style[e.stylename]);
46260 e.setValue(sel.getAttribute(e.attrname));
46264 var hasStyles = false;
46265 for(var i in this.styles) {
46272 var st = this.tb.fields.item(0);
46274 st.store.removeAll();
46277 var cn = sel.className.split(/\s+/);
46280 if (this.styles['*']) {
46282 Roo.each(this.styles['*'], function(v) {
46283 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46286 if (this.styles[tn]) {
46287 Roo.each(this.styles[tn], function(v) {
46288 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46292 st.store.loadData(avs);
46296 // flag our selected Node.
46297 this.tb.selectedNode = sel;
46300 Roo.menu.MenuMgr.hideAll();
46304 if (!updateFooter) {
46305 //this.footDisp.dom.innerHTML = '';
46308 // update the footer
46312 this.footerEls = ans.reverse();
46313 Roo.each(this.footerEls, function(a,i) {
46314 if (!a) { return; }
46315 html += html.length ? ' > ' : '';
46317 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46322 var sz = this.footDisp.up('td').getSize();
46323 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46324 this.footDisp.dom.style.marginLeft = '5px';
46326 this.footDisp.dom.style.overflow = 'hidden';
46328 this.footDisp.dom.innerHTML = html;
46330 //this.editorsyncValue();
46337 onDestroy : function(){
46340 this.tb.items.each(function(item){
46342 item.menu.removeAll();
46344 item.menu.el.destroy();
46352 onFirstFocus: function() {
46353 // need to do this for all the toolbars..
46354 this.tb.items.each(function(item){
46358 buildToolbar: function(tlist, nm)
46360 var editor = this.editor;
46361 var editorcore = this.editorcore;
46362 // create a new element.
46363 var wdiv = editor.wrap.createChild({
46365 }, editor.wrap.dom.firstChild.nextSibling, true);
46368 var tb = new Roo.Toolbar(wdiv);
46371 tb.add(nm+ ": ");
46374 for(var i in this.styles) {
46379 if (styles && styles.length) {
46381 // this needs a multi-select checkbox...
46382 tb.addField( new Roo.form.ComboBox({
46383 store: new Roo.data.SimpleStore({
46385 fields: ['val', 'selected'],
46388 name : '-roo-edit-className',
46389 attrname : 'className',
46390 displayField: 'val',
46394 triggerAction: 'all',
46395 emptyText:'Select Style',
46396 selectOnFocus:true,
46399 'select': function(c, r, i) {
46400 // initial support only for on class per el..
46401 tb.selectedNode.className = r ? r.get('val') : '';
46402 editorcore.syncValue();
46409 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46410 var tbops = tbc.options;
46412 for (var i in tlist) {
46414 var item = tlist[i];
46415 tb.add(item.title + ": ");
46418 //optname == used so you can configure the options available..
46419 var opts = item.opts ? item.opts : false;
46420 if (item.optname) {
46421 opts = tbops[item.optname];
46426 // opts == pulldown..
46427 tb.addField( new Roo.form.ComboBox({
46428 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46430 fields: ['val', 'display'],
46433 name : '-roo-edit-' + i,
46435 stylename : item.style ? item.style : false,
46436 displayField: item.displayField ? item.displayField : 'val',
46437 valueField : 'val',
46439 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46441 triggerAction: 'all',
46442 emptyText:'Select',
46443 selectOnFocus:true,
46444 width: item.width ? item.width : 130,
46446 'select': function(c, r, i) {
46448 tb.selectedNode.style[c.stylename] = r.get('val');
46451 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46460 tb.addField( new Roo.form.TextField({
46463 //allowBlank:false,
46468 tb.addField( new Roo.form.TextField({
46469 name: '-roo-edit-' + i,
46476 'change' : function(f, nv, ov) {
46477 tb.selectedNode.setAttribute(f.attrname, nv);
46478 editorcore.syncValue();
46491 text: 'Stylesheets',
46494 click : function ()
46496 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46504 text: 'Remove Tag',
46507 click : function ()
46510 // undo does not work.
46512 var sn = tb.selectedNode;
46514 var pn = sn.parentNode;
46516 var stn = sn.childNodes[0];
46517 var en = sn.childNodes[sn.childNodes.length - 1 ];
46518 while (sn.childNodes.length) {
46519 var node = sn.childNodes[0];
46520 sn.removeChild(node);
46522 pn.insertBefore(node, sn);
46525 pn.removeChild(sn);
46526 var range = editorcore.createRange();
46528 range.setStart(stn,0);
46529 range.setEnd(en,0); //????
46530 //range.selectNode(sel);
46533 var selection = editorcore.getSelection();
46534 selection.removeAllRanges();
46535 selection.addRange(range);
46539 //_this.updateToolbar(null, null, pn);
46540 _this.updateToolbar(null, null, null);
46541 _this.footDisp.dom.innerHTML = '';
46551 tb.el.on('click', function(e){
46552 e.preventDefault(); // what does this do?
46554 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46557 // dont need to disable them... as they will get hidden
46562 buildFooter : function()
46565 var fel = this.editor.wrap.createChild();
46566 this.footer = new Roo.Toolbar(fel);
46567 // toolbar has scrolly on left / right?
46568 var footDisp= new Roo.Toolbar.Fill();
46574 handler : function() {
46575 _t.footDisp.scrollTo('left',0,true)
46579 this.footer.add( footDisp );
46584 handler : function() {
46586 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46590 var fel = Roo.get(footDisp.el);
46591 fel.addClass('x-editor-context');
46592 this.footDispWrap = fel;
46593 this.footDispWrap.overflow = 'hidden';
46595 this.footDisp = fel.createChild();
46596 this.footDispWrap.on('click', this.onContextClick, this)
46600 onContextClick : function (ev,dom)
46602 ev.preventDefault();
46603 var cn = dom.className;
46605 if (!cn.match(/x-ed-loc-/)) {
46608 var n = cn.split('-').pop();
46609 var ans = this.footerEls;
46613 var range = this.editorcore.createRange();
46615 range.selectNodeContents(sel);
46616 //range.selectNode(sel);
46619 var selection = this.editorcore.getSelection();
46620 selection.removeAllRanges();
46621 selection.addRange(range);
46625 this.updateToolbar(null, null, sel);
46642 * Ext JS Library 1.1.1
46643 * Copyright(c) 2006-2007, Ext JS, LLC.
46645 * Originally Released Under LGPL - original licence link has changed is not relivant.
46648 * <script type="text/javascript">
46652 * @class Roo.form.BasicForm
46653 * @extends Roo.util.Observable
46654 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46656 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46657 * @param {Object} config Configuration options
46659 Roo.form.BasicForm = function(el, config){
46660 this.allItems = [];
46661 this.childForms = [];
46662 Roo.apply(this, config);
46664 * The Roo.form.Field items in this form.
46665 * @type MixedCollection
46669 this.items = new Roo.util.MixedCollection(false, function(o){
46670 return o.id || (o.id = Roo.id());
46674 * @event beforeaction
46675 * Fires before any action is performed. Return false to cancel the action.
46676 * @param {Form} this
46677 * @param {Action} action The action to be performed
46679 beforeaction: true,
46681 * @event actionfailed
46682 * Fires when an action fails.
46683 * @param {Form} this
46684 * @param {Action} action The action that failed
46686 actionfailed : true,
46688 * @event actioncomplete
46689 * Fires when an action is completed.
46690 * @param {Form} this
46691 * @param {Action} action The action that completed
46693 actioncomplete : true
46698 Roo.form.BasicForm.superclass.constructor.call(this);
46701 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46703 * @cfg {String} method
46704 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46707 * @cfg {DataReader} reader
46708 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46709 * This is optional as there is built-in support for processing JSON.
46712 * @cfg {DataReader} errorReader
46713 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46714 * This is completely optional as there is built-in support for processing JSON.
46717 * @cfg {String} url
46718 * The URL to use for form actions if one isn't supplied in the action options.
46721 * @cfg {Boolean} fileUpload
46722 * Set to true if this form is a file upload.
46726 * @cfg {Object} baseParams
46727 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46732 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46737 activeAction : null,
46740 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46741 * or setValues() data instead of when the form was first created.
46743 trackResetOnLoad : false,
46747 * childForms - used for multi-tab forms
46750 childForms : false,
46753 * allItems - full list of fields.
46759 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46760 * element by passing it or its id or mask the form itself by passing in true.
46763 waitMsgTarget : false,
46766 initEl : function(el){
46767 this.el = Roo.get(el);
46768 this.id = this.el.id || Roo.id();
46769 this.el.on('submit', this.onSubmit, this);
46770 this.el.addClass('x-form');
46774 onSubmit : function(e){
46779 * Returns true if client-side validation on the form is successful.
46782 isValid : function(){
46784 this.items.each(function(f){
46793 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46796 isDirty : function(){
46798 this.items.each(function(f){
46808 * Returns true if any fields in this form have changed since their original load. (New version)
46812 hasChanged : function()
46815 this.items.each(function(f){
46816 if(f.hasChanged()){
46825 * Resets all hasChanged to 'false' -
46826 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46827 * So hasChanged storage is only to be used for this purpose
46830 resetHasChanged : function()
46832 this.items.each(function(f){
46833 f.resetHasChanged();
46840 * Performs a predefined action (submit or load) or custom actions you define on this form.
46841 * @param {String} actionName The name of the action type
46842 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46843 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46844 * accept other config options):
46846 Property Type Description
46847 ---------------- --------------- ----------------------------------------------------------------------------------
46848 url String The url for the action (defaults to the form's url)
46849 method String The form method to use (defaults to the form's method, or POST if not defined)
46850 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46851 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46852 validate the form on the client (defaults to false)
46854 * @return {BasicForm} this
46856 doAction : function(action, options){
46857 if(typeof action == 'string'){
46858 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46860 if(this.fireEvent('beforeaction', this, action) !== false){
46861 this.beforeAction(action);
46862 action.run.defer(100, action);
46868 * Shortcut to do a submit action.
46869 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46870 * @return {BasicForm} this
46872 submit : function(options){
46873 this.doAction('submit', options);
46878 * Shortcut to do a load action.
46879 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46880 * @return {BasicForm} this
46882 load : function(options){
46883 this.doAction('load', options);
46888 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46889 * @param {Record} record The record to edit
46890 * @return {BasicForm} this
46892 updateRecord : function(record){
46893 record.beginEdit();
46894 var fs = record.fields;
46895 fs.each(function(f){
46896 var field = this.findField(f.name);
46898 record.set(f.name, field.getValue());
46906 * Loads an Roo.data.Record into this form.
46907 * @param {Record} record The record to load
46908 * @return {BasicForm} this
46910 loadRecord : function(record){
46911 this.setValues(record.data);
46916 beforeAction : function(action){
46917 var o = action.options;
46920 if(this.waitMsgTarget === true){
46921 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46922 }else if(this.waitMsgTarget){
46923 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46924 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46926 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46932 afterAction : function(action, success){
46933 this.activeAction = null;
46934 var o = action.options;
46936 if(this.waitMsgTarget === true){
46938 }else if(this.waitMsgTarget){
46939 this.waitMsgTarget.unmask();
46941 Roo.MessageBox.updateProgress(1);
46942 Roo.MessageBox.hide();
46949 Roo.callback(o.success, o.scope, [this, action]);
46950 this.fireEvent('actioncomplete', this, action);
46954 // failure condition..
46955 // we have a scenario where updates need confirming.
46956 // eg. if a locking scenario exists..
46957 // we look for { errors : { needs_confirm : true }} in the response.
46959 (typeof(action.result) != 'undefined') &&
46960 (typeof(action.result.errors) != 'undefined') &&
46961 (typeof(action.result.errors.needs_confirm) != 'undefined')
46964 Roo.MessageBox.confirm(
46965 "Change requires confirmation",
46966 action.result.errorMsg,
46971 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46981 Roo.callback(o.failure, o.scope, [this, action]);
46982 // show an error message if no failed handler is set..
46983 if (!this.hasListener('actionfailed')) {
46984 Roo.MessageBox.alert("Error",
46985 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46986 action.result.errorMsg :
46987 "Saving Failed, please check your entries or try again"
46991 this.fireEvent('actionfailed', this, action);
46997 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46998 * @param {String} id The value to search for
47001 findField : function(id){
47002 var field = this.items.get(id);
47004 this.items.each(function(f){
47005 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47011 return field || null;
47015 * Add a secondary form to this one,
47016 * Used to provide tabbed forms. One form is primary, with hidden values
47017 * which mirror the elements from the other forms.
47019 * @param {Roo.form.Form} form to add.
47022 addForm : function(form)
47025 if (this.childForms.indexOf(form) > -1) {
47029 this.childForms.push(form);
47031 Roo.each(form.allItems, function (fe) {
47033 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47034 if (this.findField(n)) { // already added..
47037 var add = new Roo.form.Hidden({
47040 add.render(this.el);
47047 * Mark fields in this form invalid in bulk.
47048 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47049 * @return {BasicForm} this
47051 markInvalid : function(errors){
47052 if(errors instanceof Array){
47053 for(var i = 0, len = errors.length; i < len; i++){
47054 var fieldError = errors[i];
47055 var f = this.findField(fieldError.id);
47057 f.markInvalid(fieldError.msg);
47063 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47064 field.markInvalid(errors[id]);
47068 Roo.each(this.childForms || [], function (f) {
47069 f.markInvalid(errors);
47076 * Set values for fields in this form in bulk.
47077 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47078 * @return {BasicForm} this
47080 setValues : function(values){
47081 if(values instanceof Array){ // array of objects
47082 for(var i = 0, len = values.length; i < len; i++){
47084 var f = this.findField(v.id);
47086 f.setValue(v.value);
47087 if(this.trackResetOnLoad){
47088 f.originalValue = f.getValue();
47092 }else{ // object hash
47095 if(typeof values[id] != 'function' && (field = this.findField(id))){
47097 if (field.setFromData &&
47098 field.valueField &&
47099 field.displayField &&
47100 // combos' with local stores can
47101 // be queried via setValue()
47102 // to set their value..
47103 (field.store && !field.store.isLocal)
47107 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47108 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47109 field.setFromData(sd);
47112 field.setValue(values[id]);
47116 if(this.trackResetOnLoad){
47117 field.originalValue = field.getValue();
47122 this.resetHasChanged();
47125 Roo.each(this.childForms || [], function (f) {
47126 f.setValues(values);
47127 f.resetHasChanged();
47134 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47135 * they are returned as an array.
47136 * @param {Boolean} asString
47139 getValues : function(asString){
47140 if (this.childForms) {
47141 // copy values from the child forms
47142 Roo.each(this.childForms, function (f) {
47143 this.setValues(f.getValues());
47149 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47150 if(asString === true){
47153 return Roo.urlDecode(fs);
47157 * Returns the fields in this form as an object with key/value pairs.
47158 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47161 getFieldValues : function(with_hidden)
47163 if (this.childForms) {
47164 // copy values from the child forms
47165 // should this call getFieldValues - probably not as we do not currently copy
47166 // hidden fields when we generate..
47167 Roo.each(this.childForms, function (f) {
47168 this.setValues(f.getValues());
47173 this.items.each(function(f){
47174 if (!f.getName()) {
47177 var v = f.getValue();
47178 if (f.inputType =='radio') {
47179 if (typeof(ret[f.getName()]) == 'undefined') {
47180 ret[f.getName()] = ''; // empty..
47183 if (!f.el.dom.checked) {
47187 v = f.el.dom.value;
47191 // not sure if this supported any more..
47192 if ((typeof(v) == 'object') && f.getRawValue) {
47193 v = f.getRawValue() ; // dates..
47195 // combo boxes where name != hiddenName...
47196 if (f.name != f.getName()) {
47197 ret[f.name] = f.getRawValue();
47199 ret[f.getName()] = v;
47206 * Clears all invalid messages in this form.
47207 * @return {BasicForm} this
47209 clearInvalid : function(){
47210 this.items.each(function(f){
47214 Roo.each(this.childForms || [], function (f) {
47223 * Resets this form.
47224 * @return {BasicForm} this
47226 reset : function(){
47227 this.items.each(function(f){
47231 Roo.each(this.childForms || [], function (f) {
47234 this.resetHasChanged();
47240 * Add Roo.form components to this form.
47241 * @param {Field} field1
47242 * @param {Field} field2 (optional)
47243 * @param {Field} etc (optional)
47244 * @return {BasicForm} this
47247 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47253 * Removes a field from the items collection (does NOT remove its markup).
47254 * @param {Field} field
47255 * @return {BasicForm} this
47257 remove : function(field){
47258 this.items.remove(field);
47263 * Looks at the fields in this form, checks them for an id attribute,
47264 * and calls applyTo on the existing dom element with that id.
47265 * @return {BasicForm} this
47267 render : function(){
47268 this.items.each(function(f){
47269 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47277 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47278 * @param {Object} values
47279 * @return {BasicForm} this
47281 applyToFields : function(o){
47282 this.items.each(function(f){
47289 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47290 * @param {Object} values
47291 * @return {BasicForm} this
47293 applyIfToFields : function(o){
47294 this.items.each(function(f){
47302 Roo.BasicForm = Roo.form.BasicForm;/*
47304 * Ext JS Library 1.1.1
47305 * Copyright(c) 2006-2007, Ext JS, LLC.
47307 * Originally Released Under LGPL - original licence link has changed is not relivant.
47310 * <script type="text/javascript">
47314 * @class Roo.form.Form
47315 * @extends Roo.form.BasicForm
47316 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47318 * @param {Object} config Configuration options
47320 Roo.form.Form = function(config){
47322 if (config.items) {
47323 xitems = config.items;
47324 delete config.items;
47328 Roo.form.Form.superclass.constructor.call(this, null, config);
47329 this.url = this.url || this.action;
47331 this.root = new Roo.form.Layout(Roo.applyIf({
47335 this.active = this.root;
47337 * Array of all the buttons that have been added to this form via {@link addButton}
47341 this.allItems = [];
47344 * @event clientvalidation
47345 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47346 * @param {Form} this
47347 * @param {Boolean} valid true if the form has passed client-side validation
47349 clientvalidation: true,
47352 * Fires when the form is rendered
47353 * @param {Roo.form.Form} form
47358 if (this.progressUrl) {
47359 // push a hidden field onto the list of fields..
47363 name : 'UPLOAD_IDENTIFIER'
47368 Roo.each(xitems, this.addxtype, this);
47374 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47376 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47379 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47382 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47384 buttonAlign:'center',
47387 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47392 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47393 * This property cascades to child containers if not set.
47398 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47399 * fires a looping event with that state. This is required to bind buttons to the valid
47400 * state using the config value formBind:true on the button.
47402 monitorValid : false,
47405 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47410 * @cfg {String} progressUrl - Url to return progress data
47413 progressUrl : false,
47416 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47417 * fields are added and the column is closed. If no fields are passed the column remains open
47418 * until end() is called.
47419 * @param {Object} config The config to pass to the column
47420 * @param {Field} field1 (optional)
47421 * @param {Field} field2 (optional)
47422 * @param {Field} etc (optional)
47423 * @return Column The column container object
47425 column : function(c){
47426 var col = new Roo.form.Column(c);
47428 if(arguments.length > 1){ // duplicate code required because of Opera
47429 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47436 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47437 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47438 * until end() is called.
47439 * @param {Object} config The config to pass to the fieldset
47440 * @param {Field} field1 (optional)
47441 * @param {Field} field2 (optional)
47442 * @param {Field} etc (optional)
47443 * @return FieldSet The fieldset container object
47445 fieldset : function(c){
47446 var fs = new Roo.form.FieldSet(c);
47448 if(arguments.length > 1){ // duplicate code required because of Opera
47449 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47456 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47457 * fields are added and the container is closed. If no fields are passed the container remains open
47458 * until end() is called.
47459 * @param {Object} config The config to pass to the Layout
47460 * @param {Field} field1 (optional)
47461 * @param {Field} field2 (optional)
47462 * @param {Field} etc (optional)
47463 * @return Layout The container object
47465 container : function(c){
47466 var l = new Roo.form.Layout(c);
47468 if(arguments.length > 1){ // duplicate code required because of Opera
47469 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47476 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47477 * @param {Object} container A Roo.form.Layout or subclass of Layout
47478 * @return {Form} this
47480 start : function(c){
47481 // cascade label info
47482 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47483 this.active.stack.push(c);
47484 c.ownerCt = this.active;
47490 * Closes the current open container
47491 * @return {Form} this
47494 if(this.active == this.root){
47497 this.active = this.active.ownerCt;
47502 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47503 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47504 * as the label of the field.
47505 * @param {Field} field1
47506 * @param {Field} field2 (optional)
47507 * @param {Field} etc. (optional)
47508 * @return {Form} this
47511 this.active.stack.push.apply(this.active.stack, arguments);
47512 this.allItems.push.apply(this.allItems,arguments);
47514 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47515 if(a[i].isFormField){
47520 Roo.form.Form.superclass.add.apply(this, r);
47530 * Find any element that has been added to a form, using it's ID or name
47531 * This can include framesets, columns etc. along with regular fields..
47532 * @param {String} id - id or name to find.
47534 * @return {Element} e - or false if nothing found.
47536 findbyId : function(id)
47542 Roo.each(this.allItems, function(f){
47543 if (f.id == id || f.name == id ){
47554 * Render this form into the passed container. This should only be called once!
47555 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47556 * @return {Form} this
47558 render : function(ct)
47564 var o = this.autoCreate || {
47566 method : this.method || 'POST',
47567 id : this.id || Roo.id()
47569 this.initEl(ct.createChild(o));
47571 this.root.render(this.el);
47575 this.items.each(function(f){
47576 f.render('x-form-el-'+f.id);
47579 if(this.buttons.length > 0){
47580 // tables are required to maintain order and for correct IE layout
47581 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47582 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47583 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47585 var tr = tb.getElementsByTagName('tr')[0];
47586 for(var i = 0, len = this.buttons.length; i < len; i++) {
47587 var b = this.buttons[i];
47588 var td = document.createElement('td');
47589 td.className = 'x-form-btn-td';
47590 b.render(tr.appendChild(td));
47593 if(this.monitorValid){ // initialize after render
47594 this.startMonitoring();
47596 this.fireEvent('rendered', this);
47601 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47602 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47603 * object or a valid Roo.DomHelper element config
47604 * @param {Function} handler The function called when the button is clicked
47605 * @param {Object} scope (optional) The scope of the handler function
47606 * @return {Roo.Button}
47608 addButton : function(config, handler, scope){
47612 minWidth: this.minButtonWidth,
47615 if(typeof config == "string"){
47618 Roo.apply(bc, config);
47620 var btn = new Roo.Button(null, bc);
47621 this.buttons.push(btn);
47626 * Adds a series of form elements (using the xtype property as the factory method.
47627 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47628 * @param {Object} config
47631 addxtype : function()
47633 var ar = Array.prototype.slice.call(arguments, 0);
47635 for(var i = 0; i < ar.length; i++) {
47637 continue; // skip -- if this happends something invalid got sent, we
47638 // should ignore it, as basically that interface element will not show up
47639 // and that should be pretty obvious!!
47642 if (Roo.form[ar[i].xtype]) {
47644 var fe = Roo.factory(ar[i], Roo.form);
47650 fe.store.form = this;
47655 this.allItems.push(fe);
47656 if (fe.items && fe.addxtype) {
47657 fe.addxtype.apply(fe, fe.items);
47667 // console.log('adding ' + ar[i].xtype);
47669 if (ar[i].xtype == 'Button') {
47670 //console.log('adding button');
47671 //console.log(ar[i]);
47672 this.addButton(ar[i]);
47673 this.allItems.push(fe);
47677 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47678 alert('end is not supported on xtype any more, use items');
47680 // //console.log('adding end');
47688 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47689 * option "monitorValid"
47691 startMonitoring : function(){
47694 Roo.TaskMgr.start({
47695 run : this.bindHandler,
47696 interval : this.monitorPoll || 200,
47703 * Stops monitoring of the valid state of this form
47705 stopMonitoring : function(){
47706 this.bound = false;
47710 bindHandler : function(){
47712 return false; // stops binding
47715 this.items.each(function(f){
47716 if(!f.isValid(true)){
47721 for(var i = 0, len = this.buttons.length; i < len; i++){
47722 var btn = this.buttons[i];
47723 if(btn.formBind === true && btn.disabled === valid){
47724 btn.setDisabled(!valid);
47727 this.fireEvent('clientvalidation', this, valid);
47741 Roo.Form = Roo.form.Form;
47744 * Ext JS Library 1.1.1
47745 * Copyright(c) 2006-2007, Ext JS, LLC.
47747 * Originally Released Under LGPL - original licence link has changed is not relivant.
47750 * <script type="text/javascript">
47753 // as we use this in bootstrap.
47754 Roo.namespace('Roo.form');
47756 * @class Roo.form.Action
47757 * Internal Class used to handle form actions
47759 * @param {Roo.form.BasicForm} el The form element or its id
47760 * @param {Object} config Configuration options
47765 // define the action interface
47766 Roo.form.Action = function(form, options){
47768 this.options = options || {};
47771 * Client Validation Failed
47774 Roo.form.Action.CLIENT_INVALID = 'client';
47776 * Server Validation Failed
47779 Roo.form.Action.SERVER_INVALID = 'server';
47781 * Connect to Server Failed
47784 Roo.form.Action.CONNECT_FAILURE = 'connect';
47786 * Reading Data from Server Failed
47789 Roo.form.Action.LOAD_FAILURE = 'load';
47791 Roo.form.Action.prototype = {
47793 failureType : undefined,
47794 response : undefined,
47795 result : undefined,
47797 // interface method
47798 run : function(options){
47802 // interface method
47803 success : function(response){
47807 // interface method
47808 handleResponse : function(response){
47812 // default connection failure
47813 failure : function(response){
47815 this.response = response;
47816 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47817 this.form.afterAction(this, false);
47820 processResponse : function(response){
47821 this.response = response;
47822 if(!response.responseText){
47825 this.result = this.handleResponse(response);
47826 return this.result;
47829 // utility functions used internally
47830 getUrl : function(appendParams){
47831 var url = this.options.url || this.form.url || this.form.el.dom.action;
47833 var p = this.getParams();
47835 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47841 getMethod : function(){
47842 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47845 getParams : function(){
47846 var bp = this.form.baseParams;
47847 var p = this.options.params;
47849 if(typeof p == "object"){
47850 p = Roo.urlEncode(Roo.applyIf(p, bp));
47851 }else if(typeof p == 'string' && bp){
47852 p += '&' + Roo.urlEncode(bp);
47855 p = Roo.urlEncode(bp);
47860 createCallback : function(){
47862 success: this.success,
47863 failure: this.failure,
47865 timeout: (this.form.timeout*1000),
47866 upload: this.form.fileUpload ? this.success : undefined
47871 Roo.form.Action.Submit = function(form, options){
47872 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47875 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47878 haveProgress : false,
47879 uploadComplete : false,
47881 // uploadProgress indicator.
47882 uploadProgress : function()
47884 if (!this.form.progressUrl) {
47888 if (!this.haveProgress) {
47889 Roo.MessageBox.progress("Uploading", "Uploading");
47891 if (this.uploadComplete) {
47892 Roo.MessageBox.hide();
47896 this.haveProgress = true;
47898 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47900 var c = new Roo.data.Connection();
47902 url : this.form.progressUrl,
47907 success : function(req){
47908 //console.log(data);
47912 rdata = Roo.decode(req.responseText)
47914 Roo.log("Invalid data from server..");
47918 if (!rdata || !rdata.success) {
47920 Roo.MessageBox.alert(Roo.encode(rdata));
47923 var data = rdata.data;
47925 if (this.uploadComplete) {
47926 Roo.MessageBox.hide();
47931 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47932 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47935 this.uploadProgress.defer(2000,this);
47938 failure: function(data) {
47939 Roo.log('progress url failed ');
47950 // run get Values on the form, so it syncs any secondary forms.
47951 this.form.getValues();
47953 var o = this.options;
47954 var method = this.getMethod();
47955 var isPost = method == 'POST';
47956 if(o.clientValidation === false || this.form.isValid()){
47958 if (this.form.progressUrl) {
47959 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47960 (new Date() * 1) + '' + Math.random());
47965 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47966 form:this.form.el.dom,
47967 url:this.getUrl(!isPost),
47969 params:isPost ? this.getParams() : null,
47970 isUpload: this.form.fileUpload
47973 this.uploadProgress();
47975 }else if (o.clientValidation !== false){ // client validation failed
47976 this.failureType = Roo.form.Action.CLIENT_INVALID;
47977 this.form.afterAction(this, false);
47981 success : function(response)
47983 this.uploadComplete= true;
47984 if (this.haveProgress) {
47985 Roo.MessageBox.hide();
47989 var result = this.processResponse(response);
47990 if(result === true || result.success){
47991 this.form.afterAction(this, true);
47995 this.form.markInvalid(result.errors);
47996 this.failureType = Roo.form.Action.SERVER_INVALID;
47998 this.form.afterAction(this, false);
48000 failure : function(response)
48002 this.uploadComplete= true;
48003 if (this.haveProgress) {
48004 Roo.MessageBox.hide();
48007 this.response = response;
48008 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48009 this.form.afterAction(this, false);
48012 handleResponse : function(response){
48013 if(this.form.errorReader){
48014 var rs = this.form.errorReader.read(response);
48017 for(var i = 0, len = rs.records.length; i < len; i++) {
48018 var r = rs.records[i];
48019 errors[i] = r.data;
48022 if(errors.length < 1){
48026 success : rs.success,
48032 ret = Roo.decode(response.responseText);
48036 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
48046 Roo.form.Action.Load = function(form, options){
48047 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
48048 this.reader = this.form.reader;
48051 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
48056 Roo.Ajax.request(Roo.apply(
48057 this.createCallback(), {
48058 method:this.getMethod(),
48059 url:this.getUrl(false),
48060 params:this.getParams()
48064 success : function(response){
48066 var result = this.processResponse(response);
48067 if(result === true || !result.success || !result.data){
48068 this.failureType = Roo.form.Action.LOAD_FAILURE;
48069 this.form.afterAction(this, false);
48072 this.form.clearInvalid();
48073 this.form.setValues(result.data);
48074 this.form.afterAction(this, true);
48077 handleResponse : function(response){
48078 if(this.form.reader){
48079 var rs = this.form.reader.read(response);
48080 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
48082 success : rs.success,
48086 return Roo.decode(response.responseText);
48090 Roo.form.Action.ACTION_TYPES = {
48091 'load' : Roo.form.Action.Load,
48092 'submit' : Roo.form.Action.Submit
48095 * Ext JS Library 1.1.1
48096 * Copyright(c) 2006-2007, Ext JS, LLC.
48098 * Originally Released Under LGPL - original licence link has changed is not relivant.
48101 * <script type="text/javascript">
48105 * @class Roo.form.Layout
48106 * @extends Roo.Component
48107 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48109 * @param {Object} config Configuration options
48111 Roo.form.Layout = function(config){
48113 if (config.items) {
48114 xitems = config.items;
48115 delete config.items;
48117 Roo.form.Layout.superclass.constructor.call(this, config);
48119 Roo.each(xitems, this.addxtype, this);
48123 Roo.extend(Roo.form.Layout, Roo.Component, {
48125 * @cfg {String/Object} autoCreate
48126 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48129 * @cfg {String/Object/Function} style
48130 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48131 * a function which returns such a specification.
48134 * @cfg {String} labelAlign
48135 * Valid values are "left," "top" and "right" (defaults to "left")
48138 * @cfg {Number} labelWidth
48139 * Fixed width in pixels of all field labels (defaults to undefined)
48142 * @cfg {Boolean} clear
48143 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48147 * @cfg {String} labelSeparator
48148 * The separator to use after field labels (defaults to ':')
48150 labelSeparator : ':',
48152 * @cfg {Boolean} hideLabels
48153 * True to suppress the display of field labels in this layout (defaults to false)
48155 hideLabels : false,
48158 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48163 onRender : function(ct, position){
48164 if(this.el){ // from markup
48165 this.el = Roo.get(this.el);
48166 }else { // generate
48167 var cfg = this.getAutoCreate();
48168 this.el = ct.createChild(cfg, position);
48171 this.el.applyStyles(this.style);
48173 if(this.labelAlign){
48174 this.el.addClass('x-form-label-'+this.labelAlign);
48176 if(this.hideLabels){
48177 this.labelStyle = "display:none";
48178 this.elementStyle = "padding-left:0;";
48180 if(typeof this.labelWidth == 'number'){
48181 this.labelStyle = "width:"+this.labelWidth+"px;";
48182 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48184 if(this.labelAlign == 'top'){
48185 this.labelStyle = "width:auto;";
48186 this.elementStyle = "padding-left:0;";
48189 var stack = this.stack;
48190 var slen = stack.length;
48192 if(!this.fieldTpl){
48193 var t = new Roo.Template(
48194 '<div class="x-form-item {5}">',
48195 '<label for="{0}" style="{2}">{1}{4}</label>',
48196 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48198 '</div><div class="x-form-clear-left"></div>'
48200 t.disableFormats = true;
48202 Roo.form.Layout.prototype.fieldTpl = t;
48204 for(var i = 0; i < slen; i++) {
48205 if(stack[i].isFormField){
48206 this.renderField(stack[i]);
48208 this.renderComponent(stack[i]);
48213 this.el.createChild({cls:'x-form-clear'});
48218 renderField : function(f){
48219 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48222 f.labelStyle||this.labelStyle||'', //2
48223 this.elementStyle||'', //3
48224 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48225 f.itemCls||this.itemCls||'' //5
48226 ], true).getPrevSibling());
48230 renderComponent : function(c){
48231 c.render(c.isLayout ? this.el : this.el.createChild());
48234 * Adds a object form elements (using the xtype property as the factory method.)
48235 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48236 * @param {Object} config
48238 addxtype : function(o)
48240 // create the lement.
48241 o.form = this.form;
48242 var fe = Roo.factory(o, Roo.form);
48243 this.form.allItems.push(fe);
48244 this.stack.push(fe);
48246 if (fe.isFormField) {
48247 this.form.items.add(fe);
48255 * @class Roo.form.Column
48256 * @extends Roo.form.Layout
48257 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48259 * @param {Object} config Configuration options
48261 Roo.form.Column = function(config){
48262 Roo.form.Column.superclass.constructor.call(this, config);
48265 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48267 * @cfg {Number/String} width
48268 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48271 * @cfg {String/Object} autoCreate
48272 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48276 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48279 onRender : function(ct, position){
48280 Roo.form.Column.superclass.onRender.call(this, ct, position);
48282 this.el.setWidth(this.width);
48289 * @class Roo.form.Row
48290 * @extends Roo.form.Layout
48291 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48293 * @param {Object} config Configuration options
48297 Roo.form.Row = function(config){
48298 Roo.form.Row.superclass.constructor.call(this, config);
48301 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48303 * @cfg {Number/String} width
48304 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48307 * @cfg {Number/String} height
48308 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48310 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48314 onRender : function(ct, position){
48315 //console.log('row render');
48317 var t = new Roo.Template(
48318 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48319 '<label for="{0}" style="{2}">{1}{4}</label>',
48320 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48324 t.disableFormats = true;
48326 Roo.form.Layout.prototype.rowTpl = t;
48328 this.fieldTpl = this.rowTpl;
48330 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48331 var labelWidth = 100;
48333 if ((this.labelAlign != 'top')) {
48334 if (typeof this.labelWidth == 'number') {
48335 labelWidth = this.labelWidth
48337 this.padWidth = 20 + labelWidth;
48341 Roo.form.Column.superclass.onRender.call(this, ct, position);
48343 this.el.setWidth(this.width);
48346 this.el.setHeight(this.height);
48351 renderField : function(f){
48352 f.fieldEl = this.fieldTpl.append(this.el, [
48353 f.id, f.fieldLabel,
48354 f.labelStyle||this.labelStyle||'',
48355 this.elementStyle||'',
48356 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48357 f.itemCls||this.itemCls||'',
48358 f.width ? f.width + this.padWidth : 160 + this.padWidth
48365 * @class Roo.form.FieldSet
48366 * @extends Roo.form.Layout
48367 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48369 * @param {Object} config Configuration options
48371 Roo.form.FieldSet = function(config){
48372 Roo.form.FieldSet.superclass.constructor.call(this, config);
48375 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48377 * @cfg {String} legend
48378 * The text to display as the legend for the FieldSet (defaults to '')
48381 * @cfg {String/Object} autoCreate
48382 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48386 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48389 onRender : function(ct, position){
48390 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48392 this.setLegend(this.legend);
48397 setLegend : function(text){
48399 this.el.child('legend').update(text);
48404 * Ext JS Library 1.1.1
48405 * Copyright(c) 2006-2007, Ext JS, LLC.
48407 * Originally Released Under LGPL - original licence link has changed is not relivant.
48410 * <script type="text/javascript">
48413 * @class Roo.form.VTypes
48414 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48417 Roo.form.VTypes = function(){
48418 // closure these in so they are only created once.
48419 var alpha = /^[a-zA-Z_]+$/;
48420 var alphanum = /^[a-zA-Z0-9_]+$/;
48421 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48422 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48424 // All these messages and functions are configurable
48427 * The function used to validate email addresses
48428 * @param {String} value The email address
48430 'email' : function(v){
48431 return email.test(v);
48434 * The error text to display when the email validation function returns false
48437 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48439 * The keystroke filter mask to be applied on email input
48442 'emailMask' : /[a-z0-9_\.\-@]/i,
48445 * The function used to validate URLs
48446 * @param {String} value The URL
48448 'url' : function(v){
48449 return url.test(v);
48452 * The error text to display when the url validation function returns false
48455 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48458 * The function used to validate alpha values
48459 * @param {String} value The value
48461 'alpha' : function(v){
48462 return alpha.test(v);
48465 * The error text to display when the alpha validation function returns false
48468 'alphaText' : 'This field should only contain letters and _',
48470 * The keystroke filter mask to be applied on alpha input
48473 'alphaMask' : /[a-z_]/i,
48476 * The function used to validate alphanumeric values
48477 * @param {String} value The value
48479 'alphanum' : function(v){
48480 return alphanum.test(v);
48483 * The error text to display when the alphanumeric validation function returns false
48486 'alphanumText' : 'This field should only contain letters, numbers and _',
48488 * The keystroke filter mask to be applied on alphanumeric input
48491 'alphanumMask' : /[a-z0-9_]/i
48493 }();//<script type="text/javascript">
48496 * @class Roo.form.FCKeditor
48497 * @extends Roo.form.TextArea
48498 * Wrapper around the FCKEditor http://www.fckeditor.net
48500 * Creates a new FCKeditor
48501 * @param {Object} config Configuration options
48503 Roo.form.FCKeditor = function(config){
48504 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48507 * @event editorinit
48508 * Fired when the editor is initialized - you can add extra handlers here..
48509 * @param {FCKeditor} this
48510 * @param {Object} the FCK object.
48517 Roo.form.FCKeditor.editors = { };
48518 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48520 //defaultAutoCreate : {
48521 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48525 * @cfg {Object} fck options - see fck manual for details.
48530 * @cfg {Object} fck toolbar set (Basic or Default)
48532 toolbarSet : 'Basic',
48534 * @cfg {Object} fck BasePath
48536 basePath : '/fckeditor/',
48544 onRender : function(ct, position)
48547 this.defaultAutoCreate = {
48549 style:"width:300px;height:60px;",
48550 autocomplete: "new-password"
48553 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48556 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48557 if(this.preventScrollbars){
48558 this.el.setStyle("overflow", "hidden");
48560 this.el.setHeight(this.growMin);
48563 //console.log('onrender' + this.getId() );
48564 Roo.form.FCKeditor.editors[this.getId()] = this;
48567 this.replaceTextarea() ;
48571 getEditor : function() {
48572 return this.fckEditor;
48575 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48576 * @param {Mixed} value The value to set
48580 setValue : function(value)
48582 //console.log('setValue: ' + value);
48584 if(typeof(value) == 'undefined') { // not sure why this is happending...
48587 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48589 //if(!this.el || !this.getEditor()) {
48590 // this.value = value;
48591 //this.setValue.defer(100,this,[value]);
48595 if(!this.getEditor()) {
48599 this.getEditor().SetData(value);
48606 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48607 * @return {Mixed} value The field value
48609 getValue : function()
48612 if (this.frame && this.frame.dom.style.display == 'none') {
48613 return Roo.form.FCKeditor.superclass.getValue.call(this);
48616 if(!this.el || !this.getEditor()) {
48618 // this.getValue.defer(100,this);
48623 var value=this.getEditor().GetData();
48624 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48625 return Roo.form.FCKeditor.superclass.getValue.call(this);
48631 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48632 * @return {Mixed} value The field value
48634 getRawValue : function()
48636 if (this.frame && this.frame.dom.style.display == 'none') {
48637 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48640 if(!this.el || !this.getEditor()) {
48641 //this.getRawValue.defer(100,this);
48648 var value=this.getEditor().GetData();
48649 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48650 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48654 setSize : function(w,h) {
48658 //if (this.frame && this.frame.dom.style.display == 'none') {
48659 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48662 //if(!this.el || !this.getEditor()) {
48663 // this.setSize.defer(100,this, [w,h]);
48669 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48671 this.frame.dom.setAttribute('width', w);
48672 this.frame.dom.setAttribute('height', h);
48673 this.frame.setSize(w,h);
48677 toggleSourceEdit : function(value) {
48681 this.el.dom.style.display = value ? '' : 'none';
48682 this.frame.dom.style.display = value ? 'none' : '';
48687 focus: function(tag)
48689 if (this.frame.dom.style.display == 'none') {
48690 return Roo.form.FCKeditor.superclass.focus.call(this);
48692 if(!this.el || !this.getEditor()) {
48693 this.focus.defer(100,this, [tag]);
48700 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48701 this.getEditor().Focus();
48703 if (!this.getEditor().Selection.GetSelection()) {
48704 this.focus.defer(100,this, [tag]);
48709 var r = this.getEditor().EditorDocument.createRange();
48710 r.setStart(tgs[0],0);
48711 r.setEnd(tgs[0],0);
48712 this.getEditor().Selection.GetSelection().removeAllRanges();
48713 this.getEditor().Selection.GetSelection().addRange(r);
48714 this.getEditor().Focus();
48721 replaceTextarea : function()
48723 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48726 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48728 // We must check the elements firstly using the Id and then the name.
48729 var oTextarea = document.getElementById( this.getId() );
48731 var colElementsByName = document.getElementsByName( this.getId() ) ;
48733 oTextarea.style.display = 'none' ;
48735 if ( oTextarea.tabIndex ) {
48736 this.TabIndex = oTextarea.tabIndex ;
48739 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48740 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48741 this.frame = Roo.get(this.getId() + '___Frame')
48744 _getConfigHtml : function()
48748 for ( var o in this.fckconfig ) {
48749 sConfig += sConfig.length > 0 ? '&' : '';
48750 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48753 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48757 _getIFrameHtml : function()
48759 var sFile = 'fckeditor.html' ;
48760 /* no idea what this is about..
48763 if ( (/fcksource=true/i).test( window.top.location.search ) )
48764 sFile = 'fckeditor.original.html' ;
48769 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48770 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48773 var html = '<iframe id="' + this.getId() +
48774 '___Frame" src="' + sLink +
48775 '" width="' + this.width +
48776 '" height="' + this.height + '"' +
48777 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48778 ' frameborder="0" scrolling="no"></iframe>' ;
48783 _insertHtmlBefore : function( html, element )
48785 if ( element.insertAdjacentHTML ) {
48787 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48789 var oRange = document.createRange() ;
48790 oRange.setStartBefore( element ) ;
48791 var oFragment = oRange.createContextualFragment( html );
48792 element.parentNode.insertBefore( oFragment, element ) ;
48805 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48807 function FCKeditor_OnComplete(editorInstance){
48808 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48809 f.fckEditor = editorInstance;
48810 //console.log("loaded");
48811 f.fireEvent('editorinit', f, editorInstance);
48831 //<script type="text/javascript">
48833 * @class Roo.form.GridField
48834 * @extends Roo.form.Field
48835 * Embed a grid (or editable grid into a form)
48838 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48840 * xgrid.store = Roo.data.Store
48841 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48842 * xgrid.store.reader = Roo.data.JsonReader
48846 * Creates a new GridField
48847 * @param {Object} config Configuration options
48849 Roo.form.GridField = function(config){
48850 Roo.form.GridField.superclass.constructor.call(this, config);
48854 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48856 * @cfg {Number} width - used to restrict width of grid..
48860 * @cfg {Number} height - used to restrict height of grid..
48864 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48870 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48871 * {tag: "input", type: "checkbox", autocomplete: "off"})
48873 // defaultAutoCreate : { tag: 'div' },
48874 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48876 * @cfg {String} addTitle Text to include for adding a title.
48880 onResize : function(){
48881 Roo.form.Field.superclass.onResize.apply(this, arguments);
48884 initEvents : function(){
48885 // Roo.form.Checkbox.superclass.initEvents.call(this);
48886 // has no events...
48891 getResizeEl : function(){
48895 getPositionEl : function(){
48900 onRender : function(ct, position){
48902 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48903 var style = this.style;
48906 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48907 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48908 this.viewEl = this.wrap.createChild({ tag: 'div' });
48910 this.viewEl.applyStyles(style);
48913 this.viewEl.setWidth(this.width);
48916 this.viewEl.setHeight(this.height);
48918 //if(this.inputValue !== undefined){
48919 //this.setValue(this.value);
48922 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48925 this.grid.render();
48926 this.grid.getDataSource().on('remove', this.refreshValue, this);
48927 this.grid.getDataSource().on('update', this.refreshValue, this);
48928 this.grid.on('afteredit', this.refreshValue, this);
48934 * Sets the value of the item.
48935 * @param {String} either an object or a string..
48937 setValue : function(v){
48939 v = v || []; // empty set..
48940 // this does not seem smart - it really only affects memoryproxy grids..
48941 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48942 var ds = this.grid.getDataSource();
48943 // assumes a json reader..
48945 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48946 ds.loadData( data);
48948 // clear selection so it does not get stale.
48949 if (this.grid.sm) {
48950 this.grid.sm.clearSelections();
48953 Roo.form.GridField.superclass.setValue.call(this, v);
48954 this.refreshValue();
48955 // should load data in the grid really....
48959 refreshValue: function() {
48961 this.grid.getDataSource().each(function(r) {
48964 this.el.dom.value = Roo.encode(val);
48972 * Ext JS Library 1.1.1
48973 * Copyright(c) 2006-2007, Ext JS, LLC.
48975 * Originally Released Under LGPL - original licence link has changed is not relivant.
48978 * <script type="text/javascript">
48981 * @class Roo.form.DisplayField
48982 * @extends Roo.form.Field
48983 * A generic Field to display non-editable data.
48984 * @cfg {Boolean} closable (true|false) default false
48986 * Creates a new Display Field item.
48987 * @param {Object} config Configuration options
48989 Roo.form.DisplayField = function(config){
48990 Roo.form.DisplayField.superclass.constructor.call(this, config);
48995 * Fires after the click the close btn
48996 * @param {Roo.form.DisplayField} this
49002 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
49003 inputType: 'hidden',
49009 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49011 focusClass : undefined,
49013 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49015 fieldClass: 'x-form-field',
49018 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
49020 valueRenderer: undefined,
49024 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49025 * {tag: "input", type: "checkbox", autocomplete: "off"})
49028 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
49032 onResize : function(){
49033 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
49037 initEvents : function(){
49038 // Roo.form.Checkbox.superclass.initEvents.call(this);
49039 // has no events...
49042 this.closeEl.on('click', this.onClose, this);
49048 getResizeEl : function(){
49052 getPositionEl : function(){
49057 onRender : function(ct, position){
49059 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
49060 //if(this.inputValue !== undefined){
49061 this.wrap = this.el.wrap();
49063 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
49066 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
49069 if (this.bodyStyle) {
49070 this.viewEl.applyStyles(this.bodyStyle);
49072 //this.viewEl.setStyle('padding', '2px');
49074 this.setValue(this.value);
49079 initValue : Roo.emptyFn,
49084 onClick : function(){
49089 * Sets the checked state of the checkbox.
49090 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49092 setValue : function(v){
49094 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49095 // this might be called before we have a dom element..
49096 if (!this.viewEl) {
49099 this.viewEl.dom.innerHTML = html;
49100 Roo.form.DisplayField.superclass.setValue.call(this, v);
49104 onClose : function(e)
49106 e.preventDefault();
49108 this.fireEvent('close', this);
49117 * @class Roo.form.DayPicker
49118 * @extends Roo.form.Field
49119 * A Day picker show [M] [T] [W] ....
49121 * Creates a new Day Picker
49122 * @param {Object} config Configuration options
49124 Roo.form.DayPicker= function(config){
49125 Roo.form.DayPicker.superclass.constructor.call(this, config);
49129 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49131 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49133 focusClass : undefined,
49135 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49137 fieldClass: "x-form-field",
49140 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49141 * {tag: "input", type: "checkbox", autocomplete: "off"})
49143 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49146 actionMode : 'viewEl',
49150 inputType : 'hidden',
49153 inputElement: false, // real input element?
49154 basedOn: false, // ????
49156 isFormField: true, // not sure where this is needed!!!!
49158 onResize : function(){
49159 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49160 if(!this.boxLabel){
49161 this.el.alignTo(this.wrap, 'c-c');
49165 initEvents : function(){
49166 Roo.form.Checkbox.superclass.initEvents.call(this);
49167 this.el.on("click", this.onClick, this);
49168 this.el.on("change", this.onClick, this);
49172 getResizeEl : function(){
49176 getPositionEl : function(){
49182 onRender : function(ct, position){
49183 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49185 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49187 var r1 = '<table><tr>';
49188 var r2 = '<tr class="x-form-daypick-icons">';
49189 for (var i=0; i < 7; i++) {
49190 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49191 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49194 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49195 viewEl.select('img').on('click', this.onClick, this);
49196 this.viewEl = viewEl;
49199 // this will not work on Chrome!!!
49200 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49201 this.el.on('propertychange', this.setFromHidden, this); //ie
49209 initValue : Roo.emptyFn,
49212 * Returns the checked state of the checkbox.
49213 * @return {Boolean} True if checked, else false
49215 getValue : function(){
49216 return this.el.dom.value;
49221 onClick : function(e){
49222 //this.setChecked(!this.checked);
49223 Roo.get(e.target).toggleClass('x-menu-item-checked');
49224 this.refreshValue();
49225 //if(this.el.dom.checked != this.checked){
49226 // this.setValue(this.el.dom.checked);
49231 refreshValue : function()
49234 this.viewEl.select('img',true).each(function(e,i,n) {
49235 val += e.is(".x-menu-item-checked") ? String(n) : '';
49237 this.setValue(val, true);
49241 * Sets the checked state of the checkbox.
49242 * On is always based on a string comparison between inputValue and the param.
49243 * @param {Boolean/String} value - the value to set
49244 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49246 setValue : function(v,suppressEvent){
49247 if (!this.el.dom) {
49250 var old = this.el.dom.value ;
49251 this.el.dom.value = v;
49252 if (suppressEvent) {
49256 // update display..
49257 this.viewEl.select('img',true).each(function(e,i,n) {
49259 var on = e.is(".x-menu-item-checked");
49260 var newv = v.indexOf(String(n)) > -1;
49262 e.toggleClass('x-menu-item-checked');
49268 this.fireEvent('change', this, v, old);
49273 // handle setting of hidden value by some other method!!?!?
49274 setFromHidden: function()
49279 //console.log("SET FROM HIDDEN");
49280 //alert('setFrom hidden');
49281 this.setValue(this.el.dom.value);
49284 onDestroy : function()
49287 Roo.get(this.viewEl).remove();
49290 Roo.form.DayPicker.superclass.onDestroy.call(this);
49294 * RooJS Library 1.1.1
49295 * Copyright(c) 2008-2011 Alan Knowles
49302 * @class Roo.form.ComboCheck
49303 * @extends Roo.form.ComboBox
49304 * A combobox for multiple select items.
49306 * FIXME - could do with a reset button..
49309 * Create a new ComboCheck
49310 * @param {Object} config Configuration options
49312 Roo.form.ComboCheck = function(config){
49313 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49314 // should verify some data...
49316 // hiddenName = required..
49317 // displayField = required
49318 // valudField == required
49319 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49321 Roo.each(req, function(e) {
49322 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49323 throw "Roo.form.ComboCheck : missing value for: " + e;
49330 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49335 selectedClass: 'x-menu-item-checked',
49338 onRender : function(ct, position){
49344 var cls = 'x-combo-list';
49347 this.tpl = new Roo.Template({
49348 html : '<div class="'+cls+'-item x-menu-check-item">' +
49349 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49350 '<span>{' + this.displayField + '}</span>' +
49357 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49358 this.view.singleSelect = false;
49359 this.view.multiSelect = true;
49360 this.view.toggleSelect = true;
49361 this.pageTb.add(new Roo.Toolbar.Fill(), {
49364 handler: function()
49371 onViewOver : function(e, t){
49377 onViewClick : function(doFocus,index){
49381 select: function () {
49382 //Roo.log("SELECT CALLED");
49385 selectByValue : function(xv, scrollIntoView){
49386 var ar = this.getValueArray();
49389 Roo.each(ar, function(v) {
49390 if(v === undefined || v === null){
49393 var r = this.findRecord(this.valueField, v);
49395 sels.push(this.store.indexOf(r))
49399 this.view.select(sels);
49405 onSelect : function(record, index){
49406 // Roo.log("onselect Called");
49407 // this is only called by the clear button now..
49408 this.view.clearSelections();
49409 this.setValue('[]');
49410 if (this.value != this.valueBefore) {
49411 this.fireEvent('change', this, this.value, this.valueBefore);
49412 this.valueBefore = this.value;
49415 getValueArray : function()
49420 //Roo.log(this.value);
49421 if (typeof(this.value) == 'undefined') {
49424 var ar = Roo.decode(this.value);
49425 return ar instanceof Array ? ar : []; //?? valid?
49428 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49433 expand : function ()
49436 Roo.form.ComboCheck.superclass.expand.call(this);
49437 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49438 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49443 collapse : function(){
49444 Roo.form.ComboCheck.superclass.collapse.call(this);
49445 var sl = this.view.getSelectedIndexes();
49446 var st = this.store;
49450 Roo.each(sl, function(i) {
49452 nv.push(r.get(this.valueField));
49454 this.setValue(Roo.encode(nv));
49455 if (this.value != this.valueBefore) {
49457 this.fireEvent('change', this, this.value, this.valueBefore);
49458 this.valueBefore = this.value;
49463 setValue : function(v){
49467 var vals = this.getValueArray();
49469 Roo.each(vals, function(k) {
49470 var r = this.findRecord(this.valueField, k);
49472 tv.push(r.data[this.displayField]);
49473 }else if(this.valueNotFoundText !== undefined){
49474 tv.push( this.valueNotFoundText );
49479 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49480 this.hiddenField.value = v;
49486 * Ext JS Library 1.1.1
49487 * Copyright(c) 2006-2007, Ext JS, LLC.
49489 * Originally Released Under LGPL - original licence link has changed is not relivant.
49492 * <script type="text/javascript">
49496 * @class Roo.form.Signature
49497 * @extends Roo.form.Field
49501 * @param {Object} config Configuration options
49504 Roo.form.Signature = function(config){
49505 Roo.form.Signature.superclass.constructor.call(this, config);
49507 this.addEvents({// not in used??
49510 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49511 * @param {Roo.form.Signature} combo This combo box
49516 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49517 * @param {Roo.form.ComboBox} combo This combo box
49518 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49524 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49526 * @cfg {Object} labels Label to use when rendering a form.
49530 * confirm : "Confirm"
49535 confirm : "Confirm"
49538 * @cfg {Number} width The signature panel width (defaults to 300)
49542 * @cfg {Number} height The signature panel height (defaults to 100)
49546 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49548 allowBlank : false,
49551 // {Object} signPanel The signature SVG panel element (defaults to {})
49553 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49554 isMouseDown : false,
49555 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49556 isConfirmed : false,
49557 // {String} signatureTmp SVG mapping string (defaults to empty string)
49561 defaultAutoCreate : { // modified by initCompnoent..
49567 onRender : function(ct, position){
49569 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49571 this.wrap = this.el.wrap({
49572 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49575 this.createToolbar(this);
49576 this.signPanel = this.wrap.createChild({
49578 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49582 this.svgID = Roo.id();
49583 this.svgEl = this.signPanel.createChild({
49584 xmlns : 'http://www.w3.org/2000/svg',
49586 id : this.svgID + "-svg",
49588 height: this.height,
49589 viewBox: '0 0 '+this.width+' '+this.height,
49593 id: this.svgID + "-svg-r",
49595 height: this.height,
49600 id: this.svgID + "-svg-l",
49602 y1: (this.height*0.8), // start set the line in 80% of height
49603 x2: this.width, // end
49604 y2: (this.height*0.8), // end set the line in 80% of height
49606 'stroke-width': "1",
49607 'stroke-dasharray': "3",
49608 'shape-rendering': "crispEdges",
49609 'pointer-events': "none"
49613 id: this.svgID + "-svg-p",
49615 'stroke-width': "3",
49617 'pointer-events': 'none'
49622 this.svgBox = this.svgEl.dom.getScreenCTM();
49624 createSVG : function(){
49625 var svg = this.signPanel;
49626 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49629 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49630 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49631 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49632 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49633 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49634 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49635 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49638 isTouchEvent : function(e){
49639 return e.type.match(/^touch/);
49641 getCoords : function (e) {
49642 var pt = this.svgEl.dom.createSVGPoint();
49645 if (this.isTouchEvent(e)) {
49646 pt.x = e.targetTouches[0].clientX;
49647 pt.y = e.targetTouches[0].clientY;
49649 var a = this.svgEl.dom.getScreenCTM();
49650 var b = a.inverse();
49651 var mx = pt.matrixTransform(b);
49652 return mx.x + ',' + mx.y;
49654 //mouse event headler
49655 down : function (e) {
49656 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49657 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49659 this.isMouseDown = true;
49661 e.preventDefault();
49663 move : function (e) {
49664 if (this.isMouseDown) {
49665 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49666 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49669 e.preventDefault();
49671 up : function (e) {
49672 this.isMouseDown = false;
49673 var sp = this.signatureTmp.split(' ');
49676 if(!sp[sp.length-2].match(/^L/)){
49680 this.signatureTmp = sp.join(" ");
49683 if(this.getValue() != this.signatureTmp){
49684 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49685 this.isConfirmed = false;
49687 e.preventDefault();
49691 * Protected method that will not generally be called directly. It
49692 * is called when the editor creates its toolbar. Override this method if you need to
49693 * add custom toolbar buttons.
49694 * @param {HtmlEditor} editor
49696 createToolbar : function(editor){
49697 function btn(id, toggle, handler){
49698 var xid = fid + '-'+ id ;
49702 cls : 'x-btn-icon x-edit-'+id,
49703 enableToggle:toggle !== false,
49704 scope: editor, // was editor...
49705 handler:handler||editor.relayBtnCmd,
49706 clickEvent:'mousedown',
49707 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49713 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49717 cls : ' x-signature-btn x-signature-'+id,
49718 scope: editor, // was editor...
49719 handler: this.reset,
49720 clickEvent:'mousedown',
49721 text: this.labels.clear
49728 cls : ' x-signature-btn x-signature-'+id,
49729 scope: editor, // was editor...
49730 handler: this.confirmHandler,
49731 clickEvent:'mousedown',
49732 text: this.labels.confirm
49739 * when user is clicked confirm then show this image.....
49741 * @return {String} Image Data URI
49743 getImageDataURI : function(){
49744 var svg = this.svgEl.dom.parentNode.innerHTML;
49745 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49750 * @return {Boolean} this.isConfirmed
49752 getConfirmed : function(){
49753 return this.isConfirmed;
49757 * @return {Number} this.width
49759 getWidth : function(){
49764 * @return {Number} this.height
49766 getHeight : function(){
49767 return this.height;
49770 getSignature : function(){
49771 return this.signatureTmp;
49774 reset : function(){
49775 this.signatureTmp = '';
49776 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49777 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49778 this.isConfirmed = false;
49779 Roo.form.Signature.superclass.reset.call(this);
49781 setSignature : function(s){
49782 this.signatureTmp = s;
49783 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49784 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49786 this.isConfirmed = false;
49787 Roo.form.Signature.superclass.reset.call(this);
49790 // Roo.log(this.signPanel.dom.contentWindow.up())
49793 setConfirmed : function(){
49797 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49800 confirmHandler : function(){
49801 if(!this.getSignature()){
49805 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49806 this.setValue(this.getSignature());
49807 this.isConfirmed = true;
49809 this.fireEvent('confirm', this);
49812 // Subclasses should provide the validation implementation by overriding this
49813 validateValue : function(value){
49814 if(this.allowBlank){
49818 if(this.isConfirmed){
49825 * Ext JS Library 1.1.1
49826 * Copyright(c) 2006-2007, Ext JS, LLC.
49828 * Originally Released Under LGPL - original licence link has changed is not relivant.
49831 * <script type="text/javascript">
49836 * @class Roo.form.ComboBox
49837 * @extends Roo.form.TriggerField
49838 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49840 * Create a new ComboBox.
49841 * @param {Object} config Configuration options
49843 Roo.form.Select = function(config){
49844 Roo.form.Select.superclass.constructor.call(this, config);
49848 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49850 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49853 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49854 * rendering into an Roo.Editor, defaults to false)
49857 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49858 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49861 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49864 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49865 * the dropdown list (defaults to undefined, with no header element)
49869 * @cfg {String/Roo.Template} tpl The template to use to render the output
49873 defaultAutoCreate : {tag: "select" },
49875 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49877 listWidth: undefined,
49879 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49880 * mode = 'remote' or 'text' if mode = 'local')
49882 displayField: undefined,
49884 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49885 * mode = 'remote' or 'value' if mode = 'local').
49886 * Note: use of a valueField requires the user make a selection
49887 * in order for a value to be mapped.
49889 valueField: undefined,
49893 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49894 * field's data value (defaults to the underlying DOM element's name)
49896 hiddenName: undefined,
49898 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49902 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49904 selectedClass: 'x-combo-selected',
49906 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49907 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49908 * which displays a downward arrow icon).
49910 triggerClass : 'x-form-arrow-trigger',
49912 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49916 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49917 * anchor positions (defaults to 'tl-bl')
49919 listAlign: 'tl-bl?',
49921 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49925 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49926 * query specified by the allQuery config option (defaults to 'query')
49928 triggerAction: 'query',
49930 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49931 * (defaults to 4, does not apply if editable = false)
49935 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49936 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49940 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49941 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49945 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49946 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49950 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49951 * when editable = true (defaults to false)
49953 selectOnFocus:false,
49955 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49957 queryParam: 'query',
49959 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49960 * when mode = 'remote' (defaults to 'Loading...')
49962 loadingText: 'Loading...',
49964 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49968 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49972 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49973 * traditional select (defaults to true)
49977 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49981 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49985 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49986 * listWidth has a higher value)
49990 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49991 * allow the user to set arbitrary text into the field (defaults to false)
49993 forceSelection:false,
49995 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49996 * if typeAhead = true (defaults to 250)
49998 typeAheadDelay : 250,
50000 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
50001 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
50003 valueNotFoundText : undefined,
50006 * @cfg {String} defaultValue The value displayed after loading the store.
50011 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
50013 blockFocus : false,
50016 * @cfg {Boolean} disableClear Disable showing of clear button.
50018 disableClear : false,
50020 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
50022 alwaysQuery : false,
50028 // element that contains real text value.. (when hidden is used..)
50031 onRender : function(ct, position){
50032 Roo.form.Field.prototype.onRender.call(this, ct, position);
50035 this.store.on('beforeload', this.onBeforeLoad, this);
50036 this.store.on('load', this.onLoad, this);
50037 this.store.on('loadexception', this.onLoadException, this);
50038 this.store.load({});
50046 initEvents : function(){
50047 //Roo.form.ComboBox.superclass.initEvents.call(this);
50051 onDestroy : function(){
50054 this.store.un('beforeload', this.onBeforeLoad, this);
50055 this.store.un('load', this.onLoad, this);
50056 this.store.un('loadexception', this.onLoadException, this);
50058 //Roo.form.ComboBox.superclass.onDestroy.call(this);
50062 fireKey : function(e){
50063 if(e.isNavKeyPress() && !this.list.isVisible()){
50064 this.fireEvent("specialkey", this, e);
50069 onResize: function(w, h){
50077 * Allow or prevent the user from directly editing the field text. If false is passed,
50078 * the user will only be able to select from the items defined in the dropdown list. This method
50079 * is the runtime equivalent of setting the 'editable' config option at config time.
50080 * @param {Boolean} value True to allow the user to directly edit the field text
50082 setEditable : function(value){
50087 onBeforeLoad : function(){
50089 Roo.log("Select before load");
50092 this.innerList.update(this.loadingText ?
50093 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50094 //this.restrictHeight();
50095 this.selectedIndex = -1;
50099 onLoad : function(){
50102 var dom = this.el.dom;
50103 dom.innerHTML = '';
50104 var od = dom.ownerDocument;
50106 if (this.emptyText) {
50107 var op = od.createElement('option');
50108 op.setAttribute('value', '');
50109 op.innerHTML = String.format('{0}', this.emptyText);
50110 dom.appendChild(op);
50112 if(this.store.getCount() > 0){
50114 var vf = this.valueField;
50115 var df = this.displayField;
50116 this.store.data.each(function(r) {
50117 // which colmsn to use... testing - cdoe / title..
50118 var op = od.createElement('option');
50119 op.setAttribute('value', r.data[vf]);
50120 op.innerHTML = String.format('{0}', r.data[df]);
50121 dom.appendChild(op);
50123 if (typeof(this.defaultValue != 'undefined')) {
50124 this.setValue(this.defaultValue);
50129 //this.onEmptyResults();
50134 onLoadException : function()
50136 dom.innerHTML = '';
50138 Roo.log("Select on load exception");
50142 Roo.log(this.store.reader.jsonData);
50143 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50144 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50150 onTypeAhead : function(){
50155 onSelect : function(record, index){
50156 Roo.log('on select?');
50158 if(this.fireEvent('beforeselect', this, record, index) !== false){
50159 this.setFromData(index > -1 ? record.data : false);
50161 this.fireEvent('select', this, record, index);
50166 * Returns the currently selected field value or empty string if no value is set.
50167 * @return {String} value The selected value
50169 getValue : function(){
50170 var dom = this.el.dom;
50171 this.value = dom.options[dom.selectedIndex].value;
50177 * Clears any text/value currently set in the field
50179 clearValue : function(){
50181 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50186 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50187 * will be displayed in the field. If the value does not match the data value of an existing item,
50188 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50189 * Otherwise the field will be blank (although the value will still be set).
50190 * @param {String} value The value to match
50192 setValue : function(v){
50193 var d = this.el.dom;
50194 for (var i =0; i < d.options.length;i++) {
50195 if (v == d.options[i].value) {
50196 d.selectedIndex = i;
50204 * @property {Object} the last set data for the element
50209 * Sets the value of the field based on a object which is related to the record format for the store.
50210 * @param {Object} value the value to set as. or false on reset?
50212 setFromData : function(o){
50213 Roo.log('setfrom data?');
50219 reset : function(){
50223 findRecord : function(prop, value){
50228 if(this.store.getCount() > 0){
50229 this.store.each(function(r){
50230 if(r.data[prop] == value){
50240 getName: function()
50242 // returns hidden if it's set..
50243 if (!this.rendered) {return ''};
50244 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50252 onEmptyResults : function(){
50253 Roo.log('empty results');
50258 * Returns true if the dropdown list is expanded, else false.
50260 isExpanded : function(){
50265 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50266 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50267 * @param {String} value The data value of the item to select
50268 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50269 * selected item if it is not currently in view (defaults to true)
50270 * @return {Boolean} True if the value matched an item in the list, else false
50272 selectByValue : function(v, scrollIntoView){
50273 Roo.log('select By Value');
50276 if(v !== undefined && v !== null){
50277 var r = this.findRecord(this.valueField || this.displayField, v);
50279 this.select(this.store.indexOf(r), scrollIntoView);
50287 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50288 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50289 * @param {Number} index The zero-based index of the list item to select
50290 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50291 * selected item if it is not currently in view (defaults to true)
50293 select : function(index, scrollIntoView){
50294 Roo.log('select ');
50297 this.selectedIndex = index;
50298 this.view.select(index);
50299 if(scrollIntoView !== false){
50300 var el = this.view.getNode(index);
50302 this.innerList.scrollChildIntoView(el, false);
50310 validateBlur : function(){
50317 initQuery : function(){
50318 this.doQuery(this.getRawValue());
50322 doForce : function(){
50323 if(this.el.dom.value.length > 0){
50324 this.el.dom.value =
50325 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50331 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50332 * query allowing the query action to be canceled if needed.
50333 * @param {String} query The SQL query to execute
50334 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50335 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50336 * saved in the current store (defaults to false)
50338 doQuery : function(q, forceAll){
50340 Roo.log('doQuery?');
50341 if(q === undefined || q === null){
50346 forceAll: forceAll,
50350 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50354 forceAll = qe.forceAll;
50355 if(forceAll === true || (q.length >= this.minChars)){
50356 if(this.lastQuery != q || this.alwaysQuery){
50357 this.lastQuery = q;
50358 if(this.mode == 'local'){
50359 this.selectedIndex = -1;
50361 this.store.clearFilter();
50363 this.store.filter(this.displayField, q);
50367 this.store.baseParams[this.queryParam] = q;
50369 params: this.getParams(q)
50374 this.selectedIndex = -1;
50381 getParams : function(q){
50383 //p[this.queryParam] = q;
50386 p.limit = this.pageSize;
50392 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50394 collapse : function(){
50399 collapseIf : function(e){
50404 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50406 expand : function(){
50414 * @cfg {Boolean} grow
50418 * @cfg {Number} growMin
50422 * @cfg {Number} growMax
50430 setWidth : function()
50434 getResizeEl : function(){
50437 });//<script type="text/javasscript">
50441 * @class Roo.DDView
50442 * A DnD enabled version of Roo.View.
50443 * @param {Element/String} container The Element in which to create the View.
50444 * @param {String} tpl The template string used to create the markup for each element of the View
50445 * @param {Object} config The configuration properties. These include all the config options of
50446 * {@link Roo.View} plus some specific to this class.<br>
50448 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50449 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50451 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50452 .x-view-drag-insert-above {
50453 border-top:1px dotted #3366cc;
50455 .x-view-drag-insert-below {
50456 border-bottom:1px dotted #3366cc;
50462 Roo.DDView = function(container, tpl, config) {
50463 Roo.DDView.superclass.constructor.apply(this, arguments);
50464 this.getEl().setStyle("outline", "0px none");
50465 this.getEl().unselectable();
50466 if (this.dragGroup) {
50467 this.setDraggable(this.dragGroup.split(","));
50469 if (this.dropGroup) {
50470 this.setDroppable(this.dropGroup.split(","));
50472 if (this.deletable) {
50473 this.setDeletable();
50475 this.isDirtyFlag = false;
50481 Roo.extend(Roo.DDView, Roo.View, {
50482 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50483 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50484 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50485 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50489 reset: Roo.emptyFn,
50491 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50493 validate: function() {
50497 destroy: function() {
50498 this.purgeListeners();
50499 this.getEl.removeAllListeners();
50500 this.getEl().remove();
50501 if (this.dragZone) {
50502 if (this.dragZone.destroy) {
50503 this.dragZone.destroy();
50506 if (this.dropZone) {
50507 if (this.dropZone.destroy) {
50508 this.dropZone.destroy();
50513 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50514 getName: function() {
50518 /** Loads the View from a JSON string representing the Records to put into the Store. */
50519 setValue: function(v) {
50521 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50524 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50525 this.store.proxy = new Roo.data.MemoryProxy(data);
50529 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50530 getValue: function() {
50532 this.store.each(function(rec) {
50533 result += rec.id + ',';
50535 return result.substr(0, result.length - 1) + ')';
50538 getIds: function() {
50539 var i = 0, result = new Array(this.store.getCount());
50540 this.store.each(function(rec) {
50541 result[i++] = rec.id;
50546 isDirty: function() {
50547 return this.isDirtyFlag;
50551 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50552 * whole Element becomes the target, and this causes the drop gesture to append.
50554 getTargetFromEvent : function(e) {
50555 var target = e.getTarget();
50556 while ((target !== null) && (target.parentNode != this.el.dom)) {
50557 target = target.parentNode;
50560 target = this.el.dom.lastChild || this.el.dom;
50566 * Create the drag data which consists of an object which has the property "ddel" as
50567 * the drag proxy element.
50569 getDragData : function(e) {
50570 var target = this.findItemFromChild(e.getTarget());
50572 this.handleSelection(e);
50573 var selNodes = this.getSelectedNodes();
50576 copy: this.copy || (this.allowCopy && e.ctrlKey),
50580 var selectedIndices = this.getSelectedIndexes();
50581 for (var i = 0; i < selectedIndices.length; i++) {
50582 dragData.records.push(this.store.getAt(selectedIndices[i]));
50584 if (selNodes.length == 1) {
50585 dragData.ddel = target.cloneNode(true); // the div element
50587 var div = document.createElement('div'); // create the multi element drag "ghost"
50588 div.className = 'multi-proxy';
50589 for (var i = 0, len = selNodes.length; i < len; i++) {
50590 div.appendChild(selNodes[i].cloneNode(true));
50592 dragData.ddel = div;
50594 //console.log(dragData)
50595 //console.log(dragData.ddel.innerHTML)
50598 //console.log('nodragData')
50602 /** Specify to which ddGroup items in this DDView may be dragged. */
50603 setDraggable: function(ddGroup) {
50604 if (ddGroup instanceof Array) {
50605 Roo.each(ddGroup, this.setDraggable, this);
50608 if (this.dragZone) {
50609 this.dragZone.addToGroup(ddGroup);
50611 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50612 containerScroll: true,
50616 // Draggability implies selection. DragZone's mousedown selects the element.
50617 if (!this.multiSelect) { this.singleSelect = true; }
50619 // Wire the DragZone's handlers up to methods in *this*
50620 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50624 /** Specify from which ddGroup this DDView accepts drops. */
50625 setDroppable: function(ddGroup) {
50626 if (ddGroup instanceof Array) {
50627 Roo.each(ddGroup, this.setDroppable, this);
50630 if (this.dropZone) {
50631 this.dropZone.addToGroup(ddGroup);
50633 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50634 containerScroll: true,
50638 // Wire the DropZone's handlers up to methods in *this*
50639 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50640 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50641 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50642 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50643 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50647 /** Decide whether to drop above or below a View node. */
50648 getDropPoint : function(e, n, dd){
50649 if (n == this.el.dom) { return "above"; }
50650 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50651 var c = t + (b - t) / 2;
50652 var y = Roo.lib.Event.getPageY(e);
50660 onNodeEnter : function(n, dd, e, data){
50664 onNodeOver : function(n, dd, e, data){
50665 var pt = this.getDropPoint(e, n, dd);
50666 // set the insert point style on the target node
50667 var dragElClass = this.dropNotAllowed;
50670 if (pt == "above"){
50671 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50672 targetElClass = "x-view-drag-insert-above";
50674 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50675 targetElClass = "x-view-drag-insert-below";
50677 if (this.lastInsertClass != targetElClass){
50678 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50679 this.lastInsertClass = targetElClass;
50682 return dragElClass;
50685 onNodeOut : function(n, dd, e, data){
50686 this.removeDropIndicators(n);
50689 onNodeDrop : function(n, dd, e, data){
50690 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50693 var pt = this.getDropPoint(e, n, dd);
50694 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50695 if (pt == "below") { insertAt++; }
50696 for (var i = 0; i < data.records.length; i++) {
50697 var r = data.records[i];
50698 var dup = this.store.getById(r.id);
50699 if (dup && (dd != this.dragZone)) {
50700 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50703 this.store.insert(insertAt++, r.copy());
50705 data.source.isDirtyFlag = true;
50707 this.store.insert(insertAt++, r);
50709 this.isDirtyFlag = true;
50712 this.dragZone.cachedTarget = null;
50716 removeDropIndicators : function(n){
50718 Roo.fly(n).removeClass([
50719 "x-view-drag-insert-above",
50720 "x-view-drag-insert-below"]);
50721 this.lastInsertClass = "_noclass";
50726 * Utility method. Add a delete option to the DDView's context menu.
50727 * @param {String} imageUrl The URL of the "delete" icon image.
50729 setDeletable: function(imageUrl) {
50730 if (!this.singleSelect && !this.multiSelect) {
50731 this.singleSelect = true;
50733 var c = this.getContextMenu();
50734 this.contextMenu.on("itemclick", function(item) {
50737 this.remove(this.getSelectedIndexes());
50741 this.contextMenu.add({
50748 /** Return the context menu for this DDView. */
50749 getContextMenu: function() {
50750 if (!this.contextMenu) {
50751 // Create the View's context menu
50752 this.contextMenu = new Roo.menu.Menu({
50753 id: this.id + "-contextmenu"
50755 this.el.on("contextmenu", this.showContextMenu, this);
50757 return this.contextMenu;
50760 disableContextMenu: function() {
50761 if (this.contextMenu) {
50762 this.el.un("contextmenu", this.showContextMenu, this);
50766 showContextMenu: function(e, item) {
50767 item = this.findItemFromChild(e.getTarget());
50770 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50771 this.contextMenu.showAt(e.getXY());
50776 * Remove {@link Roo.data.Record}s at the specified indices.
50777 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50779 remove: function(selectedIndices) {
50780 selectedIndices = [].concat(selectedIndices);
50781 for (var i = 0; i < selectedIndices.length; i++) {
50782 var rec = this.store.getAt(selectedIndices[i]);
50783 this.store.remove(rec);
50788 * Double click fires the event, but also, if this is draggable, and there is only one other
50789 * related DropZone, it transfers the selected node.
50791 onDblClick : function(e){
50792 var item = this.findItemFromChild(e.getTarget());
50794 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50797 if (this.dragGroup) {
50798 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50799 while (targets.indexOf(this.dropZone) > -1) {
50800 targets.remove(this.dropZone);
50802 if (targets.length == 1) {
50803 this.dragZone.cachedTarget = null;
50804 var el = Roo.get(targets[0].getEl());
50805 var box = el.getBox(true);
50806 targets[0].onNodeDrop(el.dom, {
50808 xy: [box.x, box.y + box.height - 1]
50809 }, null, this.getDragData(e));
50815 handleSelection: function(e) {
50816 this.dragZone.cachedTarget = null;
50817 var item = this.findItemFromChild(e.getTarget());
50819 this.clearSelections(true);
50822 if (item && (this.multiSelect || this.singleSelect)){
50823 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50824 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50825 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50826 this.unselect(item);
50828 this.select(item, this.multiSelect && e.ctrlKey);
50829 this.lastSelection = item;
50834 onItemClick : function(item, index, e){
50835 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50841 unselect : function(nodeInfo, suppressEvent){
50842 var node = this.getNode(nodeInfo);
50843 if(node && this.isSelected(node)){
50844 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50845 Roo.fly(node).removeClass(this.selectedClass);
50846 this.selections.remove(node);
50847 if(!suppressEvent){
50848 this.fireEvent("selectionchange", this, this.selections);
50856 * Ext JS Library 1.1.1
50857 * Copyright(c) 2006-2007, Ext JS, LLC.
50859 * Originally Released Under LGPL - original licence link has changed is not relivant.
50862 * <script type="text/javascript">
50866 * @class Roo.LayoutManager
50867 * @extends Roo.util.Observable
50868 * Base class for layout managers.
50870 Roo.LayoutManager = function(container, config){
50871 Roo.LayoutManager.superclass.constructor.call(this);
50872 this.el = Roo.get(container);
50873 // ie scrollbar fix
50874 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50875 document.body.scroll = "no";
50876 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50877 this.el.position('relative');
50879 this.id = this.el.id;
50880 this.el.addClass("x-layout-container");
50881 /** false to disable window resize monitoring @type Boolean */
50882 this.monitorWindowResize = true;
50887 * Fires when a layout is performed.
50888 * @param {Roo.LayoutManager} this
50892 * @event regionresized
50893 * Fires when the user resizes a region.
50894 * @param {Roo.LayoutRegion} region The resized region
50895 * @param {Number} newSize The new size (width for east/west, height for north/south)
50897 "regionresized" : true,
50899 * @event regioncollapsed
50900 * Fires when a region is collapsed.
50901 * @param {Roo.LayoutRegion} region The collapsed region
50903 "regioncollapsed" : true,
50905 * @event regionexpanded
50906 * Fires when a region is expanded.
50907 * @param {Roo.LayoutRegion} region The expanded region
50909 "regionexpanded" : true
50911 this.updating = false;
50912 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50915 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50917 * Returns true if this layout is currently being updated
50918 * @return {Boolean}
50920 isUpdating : function(){
50921 return this.updating;
50925 * Suspend the LayoutManager from doing auto-layouts while
50926 * making multiple add or remove calls
50928 beginUpdate : function(){
50929 this.updating = true;
50933 * Restore auto-layouts and optionally disable the manager from performing a layout
50934 * @param {Boolean} noLayout true to disable a layout update
50936 endUpdate : function(noLayout){
50937 this.updating = false;
50943 layout: function(){
50947 onRegionResized : function(region, newSize){
50948 this.fireEvent("regionresized", region, newSize);
50952 onRegionCollapsed : function(region){
50953 this.fireEvent("regioncollapsed", region);
50956 onRegionExpanded : function(region){
50957 this.fireEvent("regionexpanded", region);
50961 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50962 * performs box-model adjustments.
50963 * @return {Object} The size as an object {width: (the width), height: (the height)}
50965 getViewSize : function(){
50967 if(this.el.dom != document.body){
50968 size = this.el.getSize();
50970 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50972 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50973 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50978 * Returns the Element this layout is bound to.
50979 * @return {Roo.Element}
50981 getEl : function(){
50986 * Returns the specified region.
50987 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50988 * @return {Roo.LayoutRegion}
50990 getRegion : function(target){
50991 return this.regions[target.toLowerCase()];
50994 onWindowResize : function(){
50995 if(this.monitorWindowResize){
51001 * Ext JS Library 1.1.1
51002 * Copyright(c) 2006-2007, Ext JS, LLC.
51004 * Originally Released Under LGPL - original licence link has changed is not relivant.
51007 * <script type="text/javascript">
51010 * @class Roo.BorderLayout
51011 * @extends Roo.LayoutManager
51012 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
51013 * please see: <br><br>
51014 * <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>
51015 * <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>
51018 var layout = new Roo.BorderLayout(document.body, {
51052 preferredTabWidth: 150
51057 var CP = Roo.ContentPanel;
51059 layout.beginUpdate();
51060 layout.add("north", new CP("north", "North"));
51061 layout.add("south", new CP("south", {title: "South", closable: true}));
51062 layout.add("west", new CP("west", {title: "West"}));
51063 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
51064 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
51065 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
51066 layout.getRegion("center").showPanel("center1");
51067 layout.endUpdate();
51070 <b>The container the layout is rendered into can be either the body element or any other element.
51071 If it is not the body element, the container needs to either be an absolute positioned element,
51072 or you will need to add "position:relative" to the css of the container. You will also need to specify
51073 the container size if it is not the body element.</b>
51076 * Create a new BorderLayout
51077 * @param {String/HTMLElement/Element} container The container this layout is bound to
51078 * @param {Object} config Configuration options
51080 Roo.BorderLayout = function(container, config){
51081 config = config || {};
51082 Roo.BorderLayout.superclass.constructor.call(this, container, config);
51083 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
51084 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
51085 var target = this.factory.validRegions[i];
51086 if(config[target]){
51087 this.addRegion(target, config[target]);
51092 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51094 * Creates and adds a new region if it doesn't already exist.
51095 * @param {String} target The target region key (north, south, east, west or center).
51096 * @param {Object} config The regions config object
51097 * @return {BorderLayoutRegion} The new region
51099 addRegion : function(target, config){
51100 if(!this.regions[target]){
51101 var r = this.factory.create(target, this, config);
51102 this.bindRegion(target, r);
51104 return this.regions[target];
51108 bindRegion : function(name, r){
51109 this.regions[name] = r;
51110 r.on("visibilitychange", this.layout, this);
51111 r.on("paneladded", this.layout, this);
51112 r.on("panelremoved", this.layout, this);
51113 r.on("invalidated", this.layout, this);
51114 r.on("resized", this.onRegionResized, this);
51115 r.on("collapsed", this.onRegionCollapsed, this);
51116 r.on("expanded", this.onRegionExpanded, this);
51120 * Performs a layout update.
51122 layout : function(){
51123 if(this.updating) {
51126 var size = this.getViewSize();
51127 var w = size.width;
51128 var h = size.height;
51133 //var x = 0, y = 0;
51135 var rs = this.regions;
51136 var north = rs["north"];
51137 var south = rs["south"];
51138 var west = rs["west"];
51139 var east = rs["east"];
51140 var center = rs["center"];
51141 //if(this.hideOnLayout){ // not supported anymore
51142 //c.el.setStyle("display", "none");
51144 if(north && north.isVisible()){
51145 var b = north.getBox();
51146 var m = north.getMargins();
51147 b.width = w - (m.left+m.right);
51150 centerY = b.height + b.y + m.bottom;
51151 centerH -= centerY;
51152 north.updateBox(this.safeBox(b));
51154 if(south && south.isVisible()){
51155 var b = south.getBox();
51156 var m = south.getMargins();
51157 b.width = w - (m.left+m.right);
51159 var totalHeight = (b.height + m.top + m.bottom);
51160 b.y = h - totalHeight + m.top;
51161 centerH -= totalHeight;
51162 south.updateBox(this.safeBox(b));
51164 if(west && west.isVisible()){
51165 var b = west.getBox();
51166 var m = west.getMargins();
51167 b.height = centerH - (m.top+m.bottom);
51169 b.y = centerY + m.top;
51170 var totalWidth = (b.width + m.left + m.right);
51171 centerX += totalWidth;
51172 centerW -= totalWidth;
51173 west.updateBox(this.safeBox(b));
51175 if(east && east.isVisible()){
51176 var b = east.getBox();
51177 var m = east.getMargins();
51178 b.height = centerH - (m.top+m.bottom);
51179 var totalWidth = (b.width + m.left + m.right);
51180 b.x = w - totalWidth + m.left;
51181 b.y = centerY + m.top;
51182 centerW -= totalWidth;
51183 east.updateBox(this.safeBox(b));
51186 var m = center.getMargins();
51188 x: centerX + m.left,
51189 y: centerY + m.top,
51190 width: centerW - (m.left+m.right),
51191 height: centerH - (m.top+m.bottom)
51193 //if(this.hideOnLayout){
51194 //center.el.setStyle("display", "block");
51196 center.updateBox(this.safeBox(centerBox));
51199 this.fireEvent("layout", this);
51203 safeBox : function(box){
51204 box.width = Math.max(0, box.width);
51205 box.height = Math.max(0, box.height);
51210 * Adds a ContentPanel (or subclass) to this layout.
51211 * @param {String} target The target region key (north, south, east, west or center).
51212 * @param {Roo.ContentPanel} panel The panel to add
51213 * @return {Roo.ContentPanel} The added panel
51215 add : function(target, panel){
51217 target = target.toLowerCase();
51218 return this.regions[target].add(panel);
51222 * Remove a ContentPanel (or subclass) to this layout.
51223 * @param {String} target The target region key (north, south, east, west or center).
51224 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51225 * @return {Roo.ContentPanel} The removed panel
51227 remove : function(target, panel){
51228 target = target.toLowerCase();
51229 return this.regions[target].remove(panel);
51233 * Searches all regions for a panel with the specified id
51234 * @param {String} panelId
51235 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51237 findPanel : function(panelId){
51238 var rs = this.regions;
51239 for(var target in rs){
51240 if(typeof rs[target] != "function"){
51241 var p = rs[target].getPanel(panelId);
51251 * Searches all regions for a panel with the specified id and activates (shows) it.
51252 * @param {String/ContentPanel} panelId The panels id or the panel itself
51253 * @return {Roo.ContentPanel} The shown panel or null
51255 showPanel : function(panelId) {
51256 var rs = this.regions;
51257 for(var target in rs){
51258 var r = rs[target];
51259 if(typeof r != "function"){
51260 if(r.hasPanel(panelId)){
51261 return r.showPanel(panelId);
51269 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51270 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51272 restoreState : function(provider){
51274 provider = Roo.state.Manager;
51276 var sm = new Roo.LayoutStateManager();
51277 sm.init(this, provider);
51281 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51282 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51283 * a valid ContentPanel config object. Example:
51285 // Create the main layout
51286 var layout = new Roo.BorderLayout('main-ct', {
51297 // Create and add multiple ContentPanels at once via configs
51300 id: 'source-files',
51302 title:'Ext Source Files',
51315 * @param {Object} regions An object containing ContentPanel configs by region name
51317 batchAdd : function(regions){
51318 this.beginUpdate();
51319 for(var rname in regions){
51320 var lr = this.regions[rname];
51322 this.addTypedPanels(lr, regions[rname]);
51329 addTypedPanels : function(lr, ps){
51330 if(typeof ps == 'string'){
51331 lr.add(new Roo.ContentPanel(ps));
51333 else if(ps instanceof Array){
51334 for(var i =0, len = ps.length; i < len; i++){
51335 this.addTypedPanels(lr, ps[i]);
51338 else if(!ps.events){ // raw config?
51340 delete ps.el; // prevent conflict
51341 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51343 else { // panel object assumed!
51348 * Adds a xtype elements to the layout.
51352 xtype : 'ContentPanel',
51359 xtype : 'NestedLayoutPanel',
51365 items : [ ... list of content panels or nested layout panels.. ]
51369 * @param {Object} cfg Xtype definition of item to add.
51371 addxtype : function(cfg)
51373 // basically accepts a pannel...
51374 // can accept a layout region..!?!?
51375 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51377 if (!cfg.xtype.match(/Panel$/)) {
51382 if (typeof(cfg.region) == 'undefined') {
51383 Roo.log("Failed to add Panel, region was not set");
51387 var region = cfg.region;
51393 xitems = cfg.items;
51400 case 'ContentPanel': // ContentPanel (el, cfg)
51401 case 'ScrollPanel': // ContentPanel (el, cfg)
51403 if(cfg.autoCreate) {
51404 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51406 var el = this.el.createChild();
51407 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51410 this.add(region, ret);
51414 case 'TreePanel': // our new panel!
51415 cfg.el = this.el.createChild();
51416 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51417 this.add(region, ret);
51420 case 'NestedLayoutPanel':
51421 // create a new Layout (which is a Border Layout...
51422 var el = this.el.createChild();
51423 var clayout = cfg.layout;
51425 clayout.items = clayout.items || [];
51426 // replace this exitems with the clayout ones..
51427 xitems = clayout.items;
51430 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51431 cfg.background = false;
51433 var layout = new Roo.BorderLayout(el, clayout);
51435 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51436 //console.log('adding nested layout panel ' + cfg.toSource());
51437 this.add(region, ret);
51438 nb = {}; /// find first...
51443 // needs grid and region
51445 //var el = this.getRegion(region).el.createChild();
51446 var el = this.el.createChild();
51447 // create the grid first...
51449 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51451 if (region == 'center' && this.active ) {
51452 cfg.background = false;
51454 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51456 this.add(region, ret);
51457 if (cfg.background) {
51458 ret.on('activate', function(gp) {
51459 if (!gp.grid.rendered) {
51474 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51476 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51477 this.add(region, ret);
51480 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51484 // GridPanel (grid, cfg)
51487 this.beginUpdate();
51491 Roo.each(xitems, function(i) {
51492 region = nb && i.region ? i.region : false;
51494 var add = ret.addxtype(i);
51497 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51498 if (!i.background) {
51499 abn[region] = nb[region] ;
51506 // make the last non-background panel active..
51507 //if (nb) { Roo.log(abn); }
51510 for(var r in abn) {
51511 region = this.getRegion(r);
51513 // tried using nb[r], but it does not work..
51515 region.showPanel(abn[r]);
51526 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51527 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51528 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51529 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51532 var CP = Roo.ContentPanel;
51534 var layout = Roo.BorderLayout.create({
51538 panels: [new CP("north", "North")]
51547 panels: [new CP("west", {title: "West"})]
51556 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51565 panels: [new CP("south", {title: "South", closable: true})]
51572 preferredTabWidth: 150,
51574 new CP("center1", {title: "Close Me", closable: true}),
51575 new CP("center2", {title: "Center Panel", closable: false})
51580 layout.getRegion("center").showPanel("center1");
51585 Roo.BorderLayout.create = function(config, targetEl){
51586 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51587 layout.beginUpdate();
51588 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51589 for(var j = 0, jlen = regions.length; j < jlen; j++){
51590 var lr = regions[j];
51591 if(layout.regions[lr] && config[lr].panels){
51592 var r = layout.regions[lr];
51593 var ps = config[lr].panels;
51594 layout.addTypedPanels(r, ps);
51597 layout.endUpdate();
51602 Roo.BorderLayout.RegionFactory = {
51604 validRegions : ["north","south","east","west","center"],
51607 create : function(target, mgr, config){
51608 target = target.toLowerCase();
51609 if(config.lightweight || config.basic){
51610 return new Roo.BasicLayoutRegion(mgr, config, target);
51614 return new Roo.NorthLayoutRegion(mgr, config);
51616 return new Roo.SouthLayoutRegion(mgr, config);
51618 return new Roo.EastLayoutRegion(mgr, config);
51620 return new Roo.WestLayoutRegion(mgr, config);
51622 return new Roo.CenterLayoutRegion(mgr, config);
51624 throw 'Layout region "'+target+'" not supported.';
51628 * Ext JS Library 1.1.1
51629 * Copyright(c) 2006-2007, Ext JS, LLC.
51631 * Originally Released Under LGPL - original licence link has changed is not relivant.
51634 * <script type="text/javascript">
51638 * @class Roo.BasicLayoutRegion
51639 * @extends Roo.util.Observable
51640 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51641 * and does not have a titlebar, tabs or any other features. All it does is size and position
51642 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51644 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51646 this.position = pos;
51649 * @scope Roo.BasicLayoutRegion
51653 * @event beforeremove
51654 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51655 * @param {Roo.LayoutRegion} this
51656 * @param {Roo.ContentPanel} panel The panel
51657 * @param {Object} e The cancel event object
51659 "beforeremove" : true,
51661 * @event invalidated
51662 * Fires when the layout for this region is changed.
51663 * @param {Roo.LayoutRegion} this
51665 "invalidated" : true,
51667 * @event visibilitychange
51668 * Fires when this region is shown or hidden
51669 * @param {Roo.LayoutRegion} this
51670 * @param {Boolean} visibility true or false
51672 "visibilitychange" : true,
51674 * @event paneladded
51675 * Fires when a panel is added.
51676 * @param {Roo.LayoutRegion} this
51677 * @param {Roo.ContentPanel} panel The panel
51679 "paneladded" : true,
51681 * @event panelremoved
51682 * Fires when a panel is removed.
51683 * @param {Roo.LayoutRegion} this
51684 * @param {Roo.ContentPanel} panel The panel
51686 "panelremoved" : true,
51688 * @event beforecollapse
51689 * Fires when this region before collapse.
51690 * @param {Roo.LayoutRegion} this
51692 "beforecollapse" : true,
51695 * Fires when this region is collapsed.
51696 * @param {Roo.LayoutRegion} this
51698 "collapsed" : true,
51701 * Fires when this region is expanded.
51702 * @param {Roo.LayoutRegion} this
51707 * Fires when this region is slid into view.
51708 * @param {Roo.LayoutRegion} this
51710 "slideshow" : true,
51713 * Fires when this region slides out of view.
51714 * @param {Roo.LayoutRegion} this
51716 "slidehide" : true,
51718 * @event panelactivated
51719 * Fires when a panel is activated.
51720 * @param {Roo.LayoutRegion} this
51721 * @param {Roo.ContentPanel} panel The activated panel
51723 "panelactivated" : true,
51726 * Fires when the user resizes this region.
51727 * @param {Roo.LayoutRegion} this
51728 * @param {Number} newSize The new size (width for east/west, height for north/south)
51732 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51733 this.panels = new Roo.util.MixedCollection();
51734 this.panels.getKey = this.getPanelId.createDelegate(this);
51736 this.activePanel = null;
51737 // ensure listeners are added...
51739 if (config.listeners || config.events) {
51740 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51741 listeners : config.listeners || {},
51742 events : config.events || {}
51746 if(skipConfig !== true){
51747 this.applyConfig(config);
51751 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51752 getPanelId : function(p){
51756 applyConfig : function(config){
51757 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51758 this.config = config;
51763 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51764 * the width, for horizontal (north, south) the height.
51765 * @param {Number} newSize The new width or height
51767 resizeTo : function(newSize){
51768 var el = this.el ? this.el :
51769 (this.activePanel ? this.activePanel.getEl() : null);
51771 switch(this.position){
51774 el.setWidth(newSize);
51775 this.fireEvent("resized", this, newSize);
51779 el.setHeight(newSize);
51780 this.fireEvent("resized", this, newSize);
51786 getBox : function(){
51787 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51790 getMargins : function(){
51791 return this.margins;
51794 updateBox : function(box){
51796 var el = this.activePanel.getEl();
51797 el.dom.style.left = box.x + "px";
51798 el.dom.style.top = box.y + "px";
51799 this.activePanel.setSize(box.width, box.height);
51803 * Returns the container element for this region.
51804 * @return {Roo.Element}
51806 getEl : function(){
51807 return this.activePanel;
51811 * Returns true if this region is currently visible.
51812 * @return {Boolean}
51814 isVisible : function(){
51815 return this.activePanel ? true : false;
51818 setActivePanel : function(panel){
51819 panel = this.getPanel(panel);
51820 if(this.activePanel && this.activePanel != panel){
51821 this.activePanel.setActiveState(false);
51822 this.activePanel.getEl().setLeftTop(-10000,-10000);
51824 this.activePanel = panel;
51825 panel.setActiveState(true);
51827 panel.setSize(this.box.width, this.box.height);
51829 this.fireEvent("panelactivated", this, panel);
51830 this.fireEvent("invalidated");
51834 * Show the specified panel.
51835 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51836 * @return {Roo.ContentPanel} The shown panel or null
51838 showPanel : function(panel){
51839 if(panel = this.getPanel(panel)){
51840 this.setActivePanel(panel);
51846 * Get the active panel for this region.
51847 * @return {Roo.ContentPanel} The active panel or null
51849 getActivePanel : function(){
51850 return this.activePanel;
51854 * Add the passed ContentPanel(s)
51855 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51856 * @return {Roo.ContentPanel} The panel added (if only one was added)
51858 add : function(panel){
51859 if(arguments.length > 1){
51860 for(var i = 0, len = arguments.length; i < len; i++) {
51861 this.add(arguments[i]);
51865 if(this.hasPanel(panel)){
51866 this.showPanel(panel);
51869 var el = panel.getEl();
51870 if(el.dom.parentNode != this.mgr.el.dom){
51871 this.mgr.el.dom.appendChild(el.dom);
51873 if(panel.setRegion){
51874 panel.setRegion(this);
51876 this.panels.add(panel);
51877 el.setStyle("position", "absolute");
51878 if(!panel.background){
51879 this.setActivePanel(panel);
51880 if(this.config.initialSize && this.panels.getCount()==1){
51881 this.resizeTo(this.config.initialSize);
51884 this.fireEvent("paneladded", this, panel);
51889 * Returns true if the panel is in this region.
51890 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51891 * @return {Boolean}
51893 hasPanel : function(panel){
51894 if(typeof panel == "object"){ // must be panel obj
51895 panel = panel.getId();
51897 return this.getPanel(panel) ? true : false;
51901 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51902 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51903 * @param {Boolean} preservePanel Overrides the config preservePanel option
51904 * @return {Roo.ContentPanel} The panel that was removed
51906 remove : function(panel, preservePanel){
51907 panel = this.getPanel(panel);
51912 this.fireEvent("beforeremove", this, panel, e);
51913 if(e.cancel === true){
51916 var panelId = panel.getId();
51917 this.panels.removeKey(panelId);
51922 * Returns the panel specified or null if it's not in this region.
51923 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51924 * @return {Roo.ContentPanel}
51926 getPanel : function(id){
51927 if(typeof id == "object"){ // must be panel obj
51930 return this.panels.get(id);
51934 * Returns this regions position (north/south/east/west/center).
51937 getPosition: function(){
51938 return this.position;
51942 * Ext JS Library 1.1.1
51943 * Copyright(c) 2006-2007, Ext JS, LLC.
51945 * Originally Released Under LGPL - original licence link has changed is not relivant.
51948 * <script type="text/javascript">
51952 * @class Roo.LayoutRegion
51953 * @extends Roo.BasicLayoutRegion
51954 * This class represents a region in a layout manager.
51955 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51956 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51957 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51958 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51959 * @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})
51960 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51961 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51962 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51963 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51964 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51965 * @cfg {String} title The title for the region (overrides panel titles)
51966 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51967 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51968 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51969 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51970 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51971 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51972 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51973 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51974 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51975 * @cfg {Boolean} showPin True to show a pin button
51976 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51977 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51978 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51979 * @cfg {Number} width For East/West panels
51980 * @cfg {Number} height For North/South panels
51981 * @cfg {Boolean} split To show the splitter
51982 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51984 Roo.LayoutRegion = function(mgr, config, pos){
51985 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51986 var dh = Roo.DomHelper;
51987 /** This region's container element
51988 * @type Roo.Element */
51989 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51990 /** This region's title element
51991 * @type Roo.Element */
51993 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51994 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51995 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51997 this.titleEl.enableDisplayMode();
51998 /** This region's title text element
51999 * @type HTMLElement */
52000 this.titleTextEl = this.titleEl.dom.firstChild;
52001 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
52002 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
52003 this.closeBtn.enableDisplayMode();
52004 this.closeBtn.on("click", this.closeClicked, this);
52005 this.closeBtn.hide();
52007 this.createBody(config);
52008 this.visible = true;
52009 this.collapsed = false;
52011 if(config.hideWhenEmpty){
52013 this.on("paneladded", this.validateVisibility, this);
52014 this.on("panelremoved", this.validateVisibility, this);
52016 this.applyConfig(config);
52019 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
52021 createBody : function(){
52022 /** This region's body element
52023 * @type Roo.Element */
52024 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
52027 applyConfig : function(c){
52028 if(c.collapsible && this.position != "center" && !this.collapsedEl){
52029 var dh = Roo.DomHelper;
52030 if(c.titlebar !== false){
52031 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
52032 this.collapseBtn.on("click", this.collapse, this);
52033 this.collapseBtn.enableDisplayMode();
52035 if(c.showPin === true || this.showPin){
52036 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
52037 this.stickBtn.enableDisplayMode();
52038 this.stickBtn.on("click", this.expand, this);
52039 this.stickBtn.hide();
52042 /** This region's collapsed element
52043 * @type Roo.Element */
52044 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
52045 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
52047 if(c.floatable !== false){
52048 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
52049 this.collapsedEl.on("click", this.collapseClick, this);
52052 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
52053 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
52054 id: "message", unselectable: "on", style:{"float":"left"}});
52055 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
52057 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
52058 this.expandBtn.on("click", this.expand, this);
52060 if(this.collapseBtn){
52061 this.collapseBtn.setVisible(c.collapsible == true);
52063 this.cmargins = c.cmargins || this.cmargins ||
52064 (this.position == "west" || this.position == "east" ?
52065 {top: 0, left: 2, right:2, bottom: 0} :
52066 {top: 2, left: 0, right:0, bottom: 2});
52067 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52068 this.bottomTabs = c.tabPosition != "top";
52069 this.autoScroll = c.autoScroll || false;
52070 if(this.autoScroll){
52071 this.bodyEl.setStyle("overflow", "auto");
52073 this.bodyEl.setStyle("overflow", "hidden");
52075 //if(c.titlebar !== false){
52076 if((!c.titlebar && !c.title) || c.titlebar === false){
52077 this.titleEl.hide();
52079 this.titleEl.show();
52081 this.titleTextEl.innerHTML = c.title;
52085 this.duration = c.duration || .30;
52086 this.slideDuration = c.slideDuration || .45;
52089 this.collapse(true);
52096 * Returns true if this region is currently visible.
52097 * @return {Boolean}
52099 isVisible : function(){
52100 return this.visible;
52104 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52105 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52107 setCollapsedTitle : function(title){
52108 title = title || " ";
52109 if(this.collapsedTitleTextEl){
52110 this.collapsedTitleTextEl.innerHTML = title;
52114 getBox : function(){
52116 if(!this.collapsed){
52117 b = this.el.getBox(false, true);
52119 b = this.collapsedEl.getBox(false, true);
52124 getMargins : function(){
52125 return this.collapsed ? this.cmargins : this.margins;
52128 highlight : function(){
52129 this.el.addClass("x-layout-panel-dragover");
52132 unhighlight : function(){
52133 this.el.removeClass("x-layout-panel-dragover");
52136 updateBox : function(box){
52138 if(!this.collapsed){
52139 this.el.dom.style.left = box.x + "px";
52140 this.el.dom.style.top = box.y + "px";
52141 this.updateBody(box.width, box.height);
52143 this.collapsedEl.dom.style.left = box.x + "px";
52144 this.collapsedEl.dom.style.top = box.y + "px";
52145 this.collapsedEl.setSize(box.width, box.height);
52148 this.tabs.autoSizeTabs();
52152 updateBody : function(w, h){
52154 this.el.setWidth(w);
52155 w -= this.el.getBorderWidth("rl");
52156 if(this.config.adjustments){
52157 w += this.config.adjustments[0];
52161 this.el.setHeight(h);
52162 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52163 h -= this.el.getBorderWidth("tb");
52164 if(this.config.adjustments){
52165 h += this.config.adjustments[1];
52167 this.bodyEl.setHeight(h);
52169 h = this.tabs.syncHeight(h);
52172 if(this.panelSize){
52173 w = w !== null ? w : this.panelSize.width;
52174 h = h !== null ? h : this.panelSize.height;
52176 if(this.activePanel){
52177 var el = this.activePanel.getEl();
52178 w = w !== null ? w : el.getWidth();
52179 h = h !== null ? h : el.getHeight();
52180 this.panelSize = {width: w, height: h};
52181 this.activePanel.setSize(w, h);
52183 if(Roo.isIE && this.tabs){
52184 this.tabs.el.repaint();
52189 * Returns the container element for this region.
52190 * @return {Roo.Element}
52192 getEl : function(){
52197 * Hides this region.
52200 if(!this.collapsed){
52201 this.el.dom.style.left = "-2000px";
52204 this.collapsedEl.dom.style.left = "-2000px";
52205 this.collapsedEl.hide();
52207 this.visible = false;
52208 this.fireEvent("visibilitychange", this, false);
52212 * Shows this region if it was previously hidden.
52215 if(!this.collapsed){
52218 this.collapsedEl.show();
52220 this.visible = true;
52221 this.fireEvent("visibilitychange", this, true);
52224 closeClicked : function(){
52225 if(this.activePanel){
52226 this.remove(this.activePanel);
52230 collapseClick : function(e){
52232 e.stopPropagation();
52235 e.stopPropagation();
52241 * Collapses this region.
52242 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52244 collapse : function(skipAnim, skipCheck = false){
52245 if(this.collapsed) {
52249 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52251 this.collapsed = true;
52253 this.split.el.hide();
52255 if(this.config.animate && skipAnim !== true){
52256 this.fireEvent("invalidated", this);
52257 this.animateCollapse();
52259 this.el.setLocation(-20000,-20000);
52261 this.collapsedEl.show();
52262 this.fireEvent("collapsed", this);
52263 this.fireEvent("invalidated", this);
52269 animateCollapse : function(){
52274 * Expands this region if it was previously collapsed.
52275 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52276 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52278 expand : function(e, skipAnim){
52280 e.stopPropagation();
52282 if(!this.collapsed || this.el.hasActiveFx()) {
52286 this.afterSlideIn();
52289 this.collapsed = false;
52290 if(this.config.animate && skipAnim !== true){
52291 this.animateExpand();
52295 this.split.el.show();
52297 this.collapsedEl.setLocation(-2000,-2000);
52298 this.collapsedEl.hide();
52299 this.fireEvent("invalidated", this);
52300 this.fireEvent("expanded", this);
52304 animateExpand : function(){
52308 initTabs : function()
52310 this.bodyEl.setStyle("overflow", "hidden");
52311 var ts = new Roo.TabPanel(
52314 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52315 disableTooltips: this.config.disableTabTips,
52316 toolbar : this.config.toolbar
52319 if(this.config.hideTabs){
52320 ts.stripWrap.setDisplayed(false);
52323 ts.resizeTabs = this.config.resizeTabs === true;
52324 ts.minTabWidth = this.config.minTabWidth || 40;
52325 ts.maxTabWidth = this.config.maxTabWidth || 250;
52326 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52327 ts.monitorResize = false;
52328 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52329 ts.bodyEl.addClass('x-layout-tabs-body');
52330 this.panels.each(this.initPanelAsTab, this);
52333 initPanelAsTab : function(panel){
52334 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52335 this.config.closeOnTab && panel.isClosable());
52336 if(panel.tabTip !== undefined){
52337 ti.setTooltip(panel.tabTip);
52339 ti.on("activate", function(){
52340 this.setActivePanel(panel);
52342 if(this.config.closeOnTab){
52343 ti.on("beforeclose", function(t, e){
52345 this.remove(panel);
52351 updatePanelTitle : function(panel, title){
52352 if(this.activePanel == panel){
52353 this.updateTitle(title);
52356 var ti = this.tabs.getTab(panel.getEl().id);
52358 if(panel.tabTip !== undefined){
52359 ti.setTooltip(panel.tabTip);
52364 updateTitle : function(title){
52365 if(this.titleTextEl && !this.config.title){
52366 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52370 setActivePanel : function(panel){
52371 panel = this.getPanel(panel);
52372 if(this.activePanel && this.activePanel != panel){
52373 this.activePanel.setActiveState(false);
52375 this.activePanel = panel;
52376 panel.setActiveState(true);
52377 if(this.panelSize){
52378 panel.setSize(this.panelSize.width, this.panelSize.height);
52381 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52383 this.updateTitle(panel.getTitle());
52385 this.fireEvent("invalidated", this);
52387 this.fireEvent("panelactivated", this, panel);
52391 * Shows the specified panel.
52392 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52393 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52395 showPanel : function(panel)
52397 panel = this.getPanel(panel);
52400 var tab = this.tabs.getTab(panel.getEl().id);
52401 if(tab.isHidden()){
52402 this.tabs.unhideTab(tab.id);
52406 this.setActivePanel(panel);
52413 * Get the active panel for this region.
52414 * @return {Roo.ContentPanel} The active panel or null
52416 getActivePanel : function(){
52417 return this.activePanel;
52420 validateVisibility : function(){
52421 if(this.panels.getCount() < 1){
52422 this.updateTitle(" ");
52423 this.closeBtn.hide();
52426 if(!this.isVisible()){
52433 * Adds the passed ContentPanel(s) to this region.
52434 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52435 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52437 add : function(panel){
52438 if(arguments.length > 1){
52439 for(var i = 0, len = arguments.length; i < len; i++) {
52440 this.add(arguments[i]);
52444 if(this.hasPanel(panel)){
52445 this.showPanel(panel);
52448 panel.setRegion(this);
52449 this.panels.add(panel);
52450 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52451 this.bodyEl.dom.appendChild(panel.getEl().dom);
52452 if(panel.background !== true){
52453 this.setActivePanel(panel);
52455 this.fireEvent("paneladded", this, panel);
52461 this.initPanelAsTab(panel);
52463 if(panel.background !== true){
52464 this.tabs.activate(panel.getEl().id);
52466 this.fireEvent("paneladded", this, panel);
52471 * Hides the tab for the specified panel.
52472 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52474 hidePanel : function(panel){
52475 if(this.tabs && (panel = this.getPanel(panel))){
52476 this.tabs.hideTab(panel.getEl().id);
52481 * Unhides the tab for a previously hidden panel.
52482 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52484 unhidePanel : function(panel){
52485 if(this.tabs && (panel = this.getPanel(panel))){
52486 this.tabs.unhideTab(panel.getEl().id);
52490 clearPanels : function(){
52491 while(this.panels.getCount() > 0){
52492 this.remove(this.panels.first());
52497 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52498 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52499 * @param {Boolean} preservePanel Overrides the config preservePanel option
52500 * @return {Roo.ContentPanel} The panel that was removed
52502 remove : function(panel, preservePanel){
52503 panel = this.getPanel(panel);
52508 this.fireEvent("beforeremove", this, panel, e);
52509 if(e.cancel === true){
52512 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52513 var panelId = panel.getId();
52514 this.panels.removeKey(panelId);
52516 document.body.appendChild(panel.getEl().dom);
52519 this.tabs.removeTab(panel.getEl().id);
52520 }else if (!preservePanel){
52521 this.bodyEl.dom.removeChild(panel.getEl().dom);
52523 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52524 var p = this.panels.first();
52525 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52526 tempEl.appendChild(p.getEl().dom);
52527 this.bodyEl.update("");
52528 this.bodyEl.dom.appendChild(p.getEl().dom);
52530 this.updateTitle(p.getTitle());
52532 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52533 this.setActivePanel(p);
52535 panel.setRegion(null);
52536 if(this.activePanel == panel){
52537 this.activePanel = null;
52539 if(this.config.autoDestroy !== false && preservePanel !== true){
52540 try{panel.destroy();}catch(e){}
52542 this.fireEvent("panelremoved", this, panel);
52547 * Returns the TabPanel component used by this region
52548 * @return {Roo.TabPanel}
52550 getTabs : function(){
52554 createTool : function(parentEl, className){
52555 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52556 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52557 btn.addClassOnOver("x-layout-tools-button-over");
52562 * Ext JS Library 1.1.1
52563 * Copyright(c) 2006-2007, Ext JS, LLC.
52565 * Originally Released Under LGPL - original licence link has changed is not relivant.
52568 * <script type="text/javascript">
52574 * @class Roo.SplitLayoutRegion
52575 * @extends Roo.LayoutRegion
52576 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52578 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52579 this.cursor = cursor;
52580 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52583 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52584 splitTip : "Drag to resize.",
52585 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52586 useSplitTips : false,
52588 applyConfig : function(config){
52589 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52592 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52593 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52594 /** The SplitBar for this region
52595 * @type Roo.SplitBar */
52596 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52597 this.split.on("moved", this.onSplitMove, this);
52598 this.split.useShim = config.useShim === true;
52599 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52600 if(this.useSplitTips){
52601 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52603 if(config.collapsible){
52604 this.split.el.on("dblclick", this.collapse, this);
52607 if(typeof config.minSize != "undefined"){
52608 this.split.minSize = config.minSize;
52610 if(typeof config.maxSize != "undefined"){
52611 this.split.maxSize = config.maxSize;
52613 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52614 this.hideSplitter();
52619 getHMaxSize : function(){
52620 var cmax = this.config.maxSize || 10000;
52621 var center = this.mgr.getRegion("center");
52622 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52625 getVMaxSize : function(){
52626 var cmax = this.config.maxSize || 10000;
52627 var center = this.mgr.getRegion("center");
52628 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52631 onSplitMove : function(split, newSize){
52632 this.fireEvent("resized", this, newSize);
52636 * Returns the {@link Roo.SplitBar} for this region.
52637 * @return {Roo.SplitBar}
52639 getSplitBar : function(){
52644 this.hideSplitter();
52645 Roo.SplitLayoutRegion.superclass.hide.call(this);
52648 hideSplitter : function(){
52650 this.split.el.setLocation(-2000,-2000);
52651 this.split.el.hide();
52657 this.split.el.show();
52659 Roo.SplitLayoutRegion.superclass.show.call(this);
52662 beforeSlide: function(){
52663 if(Roo.isGecko){// firefox overflow auto bug workaround
52664 this.bodyEl.clip();
52666 this.tabs.bodyEl.clip();
52668 if(this.activePanel){
52669 this.activePanel.getEl().clip();
52671 if(this.activePanel.beforeSlide){
52672 this.activePanel.beforeSlide();
52678 afterSlide : function(){
52679 if(Roo.isGecko){// firefox overflow auto bug workaround
52680 this.bodyEl.unclip();
52682 this.tabs.bodyEl.unclip();
52684 if(this.activePanel){
52685 this.activePanel.getEl().unclip();
52686 if(this.activePanel.afterSlide){
52687 this.activePanel.afterSlide();
52693 initAutoHide : function(){
52694 if(this.autoHide !== false){
52695 if(!this.autoHideHd){
52696 var st = new Roo.util.DelayedTask(this.slideIn, this);
52697 this.autoHideHd = {
52698 "mouseout": function(e){
52699 if(!e.within(this.el, true)){
52703 "mouseover" : function(e){
52709 this.el.on(this.autoHideHd);
52713 clearAutoHide : function(){
52714 if(this.autoHide !== false){
52715 this.el.un("mouseout", this.autoHideHd.mouseout);
52716 this.el.un("mouseover", this.autoHideHd.mouseover);
52720 clearMonitor : function(){
52721 Roo.get(document).un("click", this.slideInIf, this);
52724 // these names are backwards but not changed for compat
52725 slideOut : function(){
52726 if(this.isSlid || this.el.hasActiveFx()){
52729 this.isSlid = true;
52730 if(this.collapseBtn){
52731 this.collapseBtn.hide();
52733 this.closeBtnState = this.closeBtn.getStyle('display');
52734 this.closeBtn.hide();
52736 this.stickBtn.show();
52739 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52740 this.beforeSlide();
52741 this.el.setStyle("z-index", 10001);
52742 this.el.slideIn(this.getSlideAnchor(), {
52743 callback: function(){
52745 this.initAutoHide();
52746 Roo.get(document).on("click", this.slideInIf, this);
52747 this.fireEvent("slideshow", this);
52754 afterSlideIn : function(){
52755 this.clearAutoHide();
52756 this.isSlid = false;
52757 this.clearMonitor();
52758 this.el.setStyle("z-index", "");
52759 if(this.collapseBtn){
52760 this.collapseBtn.show();
52762 this.closeBtn.setStyle('display', this.closeBtnState);
52764 this.stickBtn.hide();
52766 this.fireEvent("slidehide", this);
52769 slideIn : function(cb){
52770 if(!this.isSlid || this.el.hasActiveFx()){
52774 this.isSlid = false;
52775 this.beforeSlide();
52776 this.el.slideOut(this.getSlideAnchor(), {
52777 callback: function(){
52778 this.el.setLeftTop(-10000, -10000);
52780 this.afterSlideIn();
52788 slideInIf : function(e){
52789 if(!e.within(this.el)){
52794 animateCollapse : function(){
52795 this.beforeSlide();
52796 this.el.setStyle("z-index", 20000);
52797 var anchor = this.getSlideAnchor();
52798 this.el.slideOut(anchor, {
52799 callback : function(){
52800 this.el.setStyle("z-index", "");
52801 this.collapsedEl.slideIn(anchor, {duration:.3});
52803 this.el.setLocation(-10000,-10000);
52805 this.fireEvent("collapsed", this);
52812 animateExpand : function(){
52813 this.beforeSlide();
52814 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52815 this.el.setStyle("z-index", 20000);
52816 this.collapsedEl.hide({
52819 this.el.slideIn(this.getSlideAnchor(), {
52820 callback : function(){
52821 this.el.setStyle("z-index", "");
52824 this.split.el.show();
52826 this.fireEvent("invalidated", this);
52827 this.fireEvent("expanded", this);
52855 getAnchor : function(){
52856 return this.anchors[this.position];
52859 getCollapseAnchor : function(){
52860 return this.canchors[this.position];
52863 getSlideAnchor : function(){
52864 return this.sanchors[this.position];
52867 getAlignAdj : function(){
52868 var cm = this.cmargins;
52869 switch(this.position){
52885 getExpandAdj : function(){
52886 var c = this.collapsedEl, cm = this.cmargins;
52887 switch(this.position){
52889 return [-(cm.right+c.getWidth()+cm.left), 0];
52892 return [cm.right+c.getWidth()+cm.left, 0];
52895 return [0, -(cm.top+cm.bottom+c.getHeight())];
52898 return [0, cm.top+cm.bottom+c.getHeight()];
52904 * Ext JS Library 1.1.1
52905 * Copyright(c) 2006-2007, Ext JS, LLC.
52907 * Originally Released Under LGPL - original licence link has changed is not relivant.
52910 * <script type="text/javascript">
52913 * These classes are private internal classes
52915 Roo.CenterLayoutRegion = function(mgr, config){
52916 Roo.LayoutRegion.call(this, mgr, config, "center");
52917 this.visible = true;
52918 this.minWidth = config.minWidth || 20;
52919 this.minHeight = config.minHeight || 20;
52922 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52924 // center panel can't be hidden
52928 // center panel can't be hidden
52931 getMinWidth: function(){
52932 return this.minWidth;
52935 getMinHeight: function(){
52936 return this.minHeight;
52941 Roo.NorthLayoutRegion = function(mgr, config){
52942 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52944 this.split.placement = Roo.SplitBar.TOP;
52945 this.split.orientation = Roo.SplitBar.VERTICAL;
52946 this.split.el.addClass("x-layout-split-v");
52948 var size = config.initialSize || config.height;
52949 if(typeof size != "undefined"){
52950 this.el.setHeight(size);
52953 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52954 orientation: Roo.SplitBar.VERTICAL,
52955 getBox : function(){
52956 if(this.collapsed){
52957 return this.collapsedEl.getBox();
52959 var box = this.el.getBox();
52961 box.height += this.split.el.getHeight();
52966 updateBox : function(box){
52967 if(this.split && !this.collapsed){
52968 box.height -= this.split.el.getHeight();
52969 this.split.el.setLeft(box.x);
52970 this.split.el.setTop(box.y+box.height);
52971 this.split.el.setWidth(box.width);
52973 if(this.collapsed){
52974 this.updateBody(box.width, null);
52976 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52980 Roo.SouthLayoutRegion = function(mgr, config){
52981 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52983 this.split.placement = Roo.SplitBar.BOTTOM;
52984 this.split.orientation = Roo.SplitBar.VERTICAL;
52985 this.split.el.addClass("x-layout-split-v");
52987 var size = config.initialSize || config.height;
52988 if(typeof size != "undefined"){
52989 this.el.setHeight(size);
52992 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52993 orientation: Roo.SplitBar.VERTICAL,
52994 getBox : function(){
52995 if(this.collapsed){
52996 return this.collapsedEl.getBox();
52998 var box = this.el.getBox();
53000 var sh = this.split.el.getHeight();
53007 updateBox : function(box){
53008 if(this.split && !this.collapsed){
53009 var sh = this.split.el.getHeight();
53012 this.split.el.setLeft(box.x);
53013 this.split.el.setTop(box.y-sh);
53014 this.split.el.setWidth(box.width);
53016 if(this.collapsed){
53017 this.updateBody(box.width, null);
53019 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53023 Roo.EastLayoutRegion = function(mgr, config){
53024 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
53026 this.split.placement = Roo.SplitBar.RIGHT;
53027 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53028 this.split.el.addClass("x-layout-split-h");
53030 var size = config.initialSize || config.width;
53031 if(typeof size != "undefined"){
53032 this.el.setWidth(size);
53035 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
53036 orientation: Roo.SplitBar.HORIZONTAL,
53037 getBox : function(){
53038 if(this.collapsed){
53039 return this.collapsedEl.getBox();
53041 var box = this.el.getBox();
53043 var sw = this.split.el.getWidth();
53050 updateBox : function(box){
53051 if(this.split && !this.collapsed){
53052 var sw = this.split.el.getWidth();
53054 this.split.el.setLeft(box.x);
53055 this.split.el.setTop(box.y);
53056 this.split.el.setHeight(box.height);
53059 if(this.collapsed){
53060 this.updateBody(null, box.height);
53062 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53066 Roo.WestLayoutRegion = function(mgr, config){
53067 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
53069 this.split.placement = Roo.SplitBar.LEFT;
53070 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53071 this.split.el.addClass("x-layout-split-h");
53073 var size = config.initialSize || config.width;
53074 if(typeof size != "undefined"){
53075 this.el.setWidth(size);
53078 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
53079 orientation: Roo.SplitBar.HORIZONTAL,
53080 getBox : function(){
53081 if(this.collapsed){
53082 return this.collapsedEl.getBox();
53084 var box = this.el.getBox();
53086 box.width += this.split.el.getWidth();
53091 updateBox : function(box){
53092 if(this.split && !this.collapsed){
53093 var sw = this.split.el.getWidth();
53095 this.split.el.setLeft(box.x+box.width);
53096 this.split.el.setTop(box.y);
53097 this.split.el.setHeight(box.height);
53099 if(this.collapsed){
53100 this.updateBody(null, box.height);
53102 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53107 * Ext JS Library 1.1.1
53108 * Copyright(c) 2006-2007, Ext JS, LLC.
53110 * Originally Released Under LGPL - original licence link has changed is not relivant.
53113 * <script type="text/javascript">
53118 * Private internal class for reading and applying state
53120 Roo.LayoutStateManager = function(layout){
53121 // default empty state
53130 Roo.LayoutStateManager.prototype = {
53131 init : function(layout, provider){
53132 this.provider = provider;
53133 var state = provider.get(layout.id+"-layout-state");
53135 var wasUpdating = layout.isUpdating();
53137 layout.beginUpdate();
53139 for(var key in state){
53140 if(typeof state[key] != "function"){
53141 var rstate = state[key];
53142 var r = layout.getRegion(key);
53145 r.resizeTo(rstate.size);
53147 if(rstate.collapsed == true){
53150 r.expand(null, true);
53156 layout.endUpdate();
53158 this.state = state;
53160 this.layout = layout;
53161 layout.on("regionresized", this.onRegionResized, this);
53162 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53163 layout.on("regionexpanded", this.onRegionExpanded, this);
53166 storeState : function(){
53167 this.provider.set(this.layout.id+"-layout-state", this.state);
53170 onRegionResized : function(region, newSize){
53171 this.state[region.getPosition()].size = newSize;
53175 onRegionCollapsed : function(region){
53176 this.state[region.getPosition()].collapsed = true;
53180 onRegionExpanded : function(region){
53181 this.state[region.getPosition()].collapsed = false;
53186 * Ext JS Library 1.1.1
53187 * Copyright(c) 2006-2007, Ext JS, LLC.
53189 * Originally Released Under LGPL - original licence link has changed is not relivant.
53192 * <script type="text/javascript">
53195 * @class Roo.ContentPanel
53196 * @extends Roo.util.Observable
53197 * A basic ContentPanel element.
53198 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53199 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53200 * @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
53201 * @cfg {Boolean} closable True if the panel can be closed/removed
53202 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53203 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53204 * @cfg {Toolbar} toolbar A toolbar for this panel
53205 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53206 * @cfg {String} title The title for this panel
53207 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53208 * @cfg {String} url Calls {@link #setUrl} with this value
53209 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53210 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53211 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53212 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53215 * Create a new ContentPanel.
53216 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53217 * @param {String/Object} config A string to set only the title or a config object
53218 * @param {String} content (optional) Set the HTML content for this panel
53219 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53221 Roo.ContentPanel = function(el, config, content){
53225 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53229 if (config && config.parentLayout) {
53230 el = config.parentLayout.el.createChild();
53233 if(el.autoCreate){ // xtype is available if this is called from factory
53237 this.el = Roo.get(el);
53238 if(!this.el && config && config.autoCreate){
53239 if(typeof config.autoCreate == "object"){
53240 if(!config.autoCreate.id){
53241 config.autoCreate.id = config.id||el;
53243 this.el = Roo.DomHelper.append(document.body,
53244 config.autoCreate, true);
53246 this.el = Roo.DomHelper.append(document.body,
53247 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53250 this.closable = false;
53251 this.loaded = false;
53252 this.active = false;
53253 if(typeof config == "string"){
53254 this.title = config;
53256 Roo.apply(this, config);
53259 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53260 this.wrapEl = this.el.wrap();
53261 this.toolbar.container = this.el.insertSibling(false, 'before');
53262 this.toolbar = new Roo.Toolbar(this.toolbar);
53265 // xtype created footer. - not sure if will work as we normally have to render first..
53266 if (this.footer && !this.footer.el && this.footer.xtype) {
53267 if (!this.wrapEl) {
53268 this.wrapEl = this.el.wrap();
53271 this.footer.container = this.wrapEl.createChild();
53273 this.footer = Roo.factory(this.footer, Roo);
53278 this.resizeEl = Roo.get(this.resizeEl, true);
53280 this.resizeEl = this.el;
53282 // handle view.xtype
53290 * Fires when this panel is activated.
53291 * @param {Roo.ContentPanel} this
53295 * @event deactivate
53296 * Fires when this panel is activated.
53297 * @param {Roo.ContentPanel} this
53299 "deactivate" : true,
53303 * Fires when this panel is resized if fitToFrame is true.
53304 * @param {Roo.ContentPanel} this
53305 * @param {Number} width The width after any component adjustments
53306 * @param {Number} height The height after any component adjustments
53312 * Fires when this tab is created
53313 * @param {Roo.ContentPanel} this
53324 if(this.autoScroll){
53325 this.resizeEl.setStyle("overflow", "auto");
53327 // fix randome scrolling
53328 this.el.on('scroll', function() {
53329 Roo.log('fix random scolling');
53330 this.scrollTo('top',0);
53333 content = content || this.content;
53335 this.setContent(content);
53337 if(config && config.url){
53338 this.setUrl(this.url, this.params, this.loadOnce);
53343 Roo.ContentPanel.superclass.constructor.call(this);
53345 if (this.view && typeof(this.view.xtype) != 'undefined') {
53346 this.view.el = this.el.appendChild(document.createElement("div"));
53347 this.view = Roo.factory(this.view);
53348 this.view.render && this.view.render(false, '');
53352 this.fireEvent('render', this);
53355 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53357 setRegion : function(region){
53358 this.region = region;
53360 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53362 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53367 * Returns the toolbar for this Panel if one was configured.
53368 * @return {Roo.Toolbar}
53370 getToolbar : function(){
53371 return this.toolbar;
53374 setActiveState : function(active){
53375 this.active = active;
53377 this.fireEvent("deactivate", this);
53379 this.fireEvent("activate", this);
53383 * Updates this panel's element
53384 * @param {String} content The new content
53385 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53387 setContent : function(content, loadScripts){
53388 this.el.update(content, loadScripts);
53391 ignoreResize : function(w, h){
53392 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53395 this.lastSize = {width: w, height: h};
53400 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53401 * @return {Roo.UpdateManager} The UpdateManager
53403 getUpdateManager : function(){
53404 return this.el.getUpdateManager();
53407 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53408 * @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:
53411 url: "your-url.php",
53412 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53413 callback: yourFunction,
53414 scope: yourObject, //(optional scope)
53417 text: "Loading...",
53422 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53423 * 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.
53424 * @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}
53425 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53426 * @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.
53427 * @return {Roo.ContentPanel} this
53430 var um = this.el.getUpdateManager();
53431 um.update.apply(um, arguments);
53437 * 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.
53438 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53439 * @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)
53440 * @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)
53441 * @return {Roo.UpdateManager} The UpdateManager
53443 setUrl : function(url, params, loadOnce){
53444 if(this.refreshDelegate){
53445 this.removeListener("activate", this.refreshDelegate);
53447 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53448 this.on("activate", this.refreshDelegate);
53449 return this.el.getUpdateManager();
53452 _handleRefresh : function(url, params, loadOnce){
53453 if(!loadOnce || !this.loaded){
53454 var updater = this.el.getUpdateManager();
53455 updater.update(url, params, this._setLoaded.createDelegate(this));
53459 _setLoaded : function(){
53460 this.loaded = true;
53464 * Returns this panel's id
53467 getId : function(){
53472 * Returns this panel's element - used by regiosn to add.
53473 * @return {Roo.Element}
53475 getEl : function(){
53476 return this.wrapEl || this.el;
53479 adjustForComponents : function(width, height)
53481 //Roo.log('adjustForComponents ');
53482 if(this.resizeEl != this.el){
53483 width -= this.el.getFrameWidth('lr');
53484 height -= this.el.getFrameWidth('tb');
53487 var te = this.toolbar.getEl();
53488 height -= te.getHeight();
53489 te.setWidth(width);
53492 var te = this.footer.getEl();
53493 Roo.log("footer:" + te.getHeight());
53495 height -= te.getHeight();
53496 te.setWidth(width);
53500 if(this.adjustments){
53501 width += this.adjustments[0];
53502 height += this.adjustments[1];
53504 return {"width": width, "height": height};
53507 setSize : function(width, height){
53508 if(this.fitToFrame && !this.ignoreResize(width, height)){
53509 if(this.fitContainer && this.resizeEl != this.el){
53510 this.el.setSize(width, height);
53512 var size = this.adjustForComponents(width, height);
53513 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53514 this.fireEvent('resize', this, size.width, size.height);
53519 * Returns this panel's title
53522 getTitle : function(){
53527 * Set this panel's title
53528 * @param {String} title
53530 setTitle : function(title){
53531 this.title = title;
53533 this.region.updatePanelTitle(this, title);
53538 * Returns true is this panel was configured to be closable
53539 * @return {Boolean}
53541 isClosable : function(){
53542 return this.closable;
53545 beforeSlide : function(){
53547 this.resizeEl.clip();
53550 afterSlide : function(){
53552 this.resizeEl.unclip();
53556 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53557 * Will fail silently if the {@link #setUrl} method has not been called.
53558 * This does not activate the panel, just updates its content.
53560 refresh : function(){
53561 if(this.refreshDelegate){
53562 this.loaded = false;
53563 this.refreshDelegate();
53568 * Destroys this panel
53570 destroy : function(){
53571 this.el.removeAllListeners();
53572 var tempEl = document.createElement("span");
53573 tempEl.appendChild(this.el.dom);
53574 tempEl.innerHTML = "";
53580 * form - if the content panel contains a form - this is a reference to it.
53581 * @type {Roo.form.Form}
53585 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53586 * This contains a reference to it.
53592 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53602 * @param {Object} cfg Xtype definition of item to add.
53605 addxtype : function(cfg) {
53607 if (cfg.xtype.match(/^Form$/)) {
53610 //if (this.footer) {
53611 // el = this.footer.container.insertSibling(false, 'before');
53613 el = this.el.createChild();
53616 this.form = new Roo.form.Form(cfg);
53619 if ( this.form.allItems.length) {
53620 this.form.render(el.dom);
53624 // should only have one of theses..
53625 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53626 // views.. should not be just added - used named prop 'view''
53628 cfg.el = this.el.appendChild(document.createElement("div"));
53631 var ret = new Roo.factory(cfg);
53633 ret.render && ret.render(false, ''); // render blank..
53642 * @class Roo.GridPanel
53643 * @extends Roo.ContentPanel
53645 * Create a new GridPanel.
53646 * @param {Roo.grid.Grid} grid The grid for this panel
53647 * @param {String/Object} config A string to set only the panel's title, or a config object
53649 Roo.GridPanel = function(grid, config){
53652 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53653 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53655 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53657 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53660 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53662 // xtype created footer. - not sure if will work as we normally have to render first..
53663 if (this.footer && !this.footer.el && this.footer.xtype) {
53665 this.footer.container = this.grid.getView().getFooterPanel(true);
53666 this.footer.dataSource = this.grid.dataSource;
53667 this.footer = Roo.factory(this.footer, Roo);
53671 grid.monitorWindowResize = false; // turn off autosizing
53672 grid.autoHeight = false;
53673 grid.autoWidth = false;
53675 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53678 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53679 getId : function(){
53680 return this.grid.id;
53684 * Returns the grid for this panel
53685 * @return {Roo.grid.Grid}
53687 getGrid : function(){
53691 setSize : function(width, height){
53692 if(!this.ignoreResize(width, height)){
53693 var grid = this.grid;
53694 var size = this.adjustForComponents(width, height);
53695 grid.getGridEl().setSize(size.width, size.height);
53700 beforeSlide : function(){
53701 this.grid.getView().scroller.clip();
53704 afterSlide : function(){
53705 this.grid.getView().scroller.unclip();
53708 destroy : function(){
53709 this.grid.destroy();
53711 Roo.GridPanel.superclass.destroy.call(this);
53717 * @class Roo.NestedLayoutPanel
53718 * @extends Roo.ContentPanel
53720 * Create a new NestedLayoutPanel.
53723 * @param {Roo.BorderLayout} layout The layout for this panel
53724 * @param {String/Object} config A string to set only the title or a config object
53726 Roo.NestedLayoutPanel = function(layout, config)
53728 // construct with only one argument..
53729 /* FIXME - implement nicer consturctors
53730 if (layout.layout) {
53732 layout = config.layout;
53733 delete config.layout;
53735 if (layout.xtype && !layout.getEl) {
53736 // then layout needs constructing..
53737 layout = Roo.factory(layout, Roo);
53742 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53744 layout.monitorWindowResize = false; // turn off autosizing
53745 this.layout = layout;
53746 this.layout.getEl().addClass("x-layout-nested-layout");
53753 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53755 setSize : function(width, height){
53756 if(!this.ignoreResize(width, height)){
53757 var size = this.adjustForComponents(width, height);
53758 var el = this.layout.getEl();
53759 el.setSize(size.width, size.height);
53760 var touch = el.dom.offsetWidth;
53761 this.layout.layout();
53762 // ie requires a double layout on the first pass
53763 if(Roo.isIE && !this.initialized){
53764 this.initialized = true;
53765 this.layout.layout();
53770 // activate all subpanels if not currently active..
53772 setActiveState : function(active){
53773 this.active = active;
53775 this.fireEvent("deactivate", this);
53779 this.fireEvent("activate", this);
53780 // not sure if this should happen before or after..
53781 if (!this.layout) {
53782 return; // should not happen..
53785 for (var r in this.layout.regions) {
53786 reg = this.layout.getRegion(r);
53787 if (reg.getActivePanel()) {
53788 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53789 reg.setActivePanel(reg.getActivePanel());
53792 if (!reg.panels.length) {
53795 reg.showPanel(reg.getPanel(0));
53804 * Returns the nested BorderLayout for this panel
53805 * @return {Roo.BorderLayout}
53807 getLayout : function(){
53808 return this.layout;
53812 * Adds a xtype elements to the layout of the nested panel
53816 xtype : 'ContentPanel',
53823 xtype : 'NestedLayoutPanel',
53829 items : [ ... list of content panels or nested layout panels.. ]
53833 * @param {Object} cfg Xtype definition of item to add.
53835 addxtype : function(cfg) {
53836 return this.layout.addxtype(cfg);
53841 Roo.ScrollPanel = function(el, config, content){
53842 config = config || {};
53843 config.fitToFrame = true;
53844 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53846 this.el.dom.style.overflow = "hidden";
53847 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53848 this.el.removeClass("x-layout-inactive-content");
53849 this.el.on("mousewheel", this.onWheel, this);
53851 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53852 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53853 up.unselectable(); down.unselectable();
53854 up.on("click", this.scrollUp, this);
53855 down.on("click", this.scrollDown, this);
53856 up.addClassOnOver("x-scroller-btn-over");
53857 down.addClassOnOver("x-scroller-btn-over");
53858 up.addClassOnClick("x-scroller-btn-click");
53859 down.addClassOnClick("x-scroller-btn-click");
53860 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53862 this.resizeEl = this.el;
53863 this.el = wrap; this.up = up; this.down = down;
53866 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53868 wheelIncrement : 5,
53869 scrollUp : function(){
53870 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53873 scrollDown : function(){
53874 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53877 afterScroll : function(){
53878 var el = this.resizeEl;
53879 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53880 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53881 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53884 setSize : function(){
53885 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53886 this.afterScroll();
53889 onWheel : function(e){
53890 var d = e.getWheelDelta();
53891 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53892 this.afterScroll();
53896 setContent : function(content, loadScripts){
53897 this.resizeEl.update(content, loadScripts);
53911 * @class Roo.TreePanel
53912 * @extends Roo.ContentPanel
53914 * Create a new TreePanel. - defaults to fit/scoll contents.
53915 * @param {String/Object} config A string to set only the panel's title, or a config object
53916 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53918 Roo.TreePanel = function(config){
53919 var el = config.el;
53920 var tree = config.tree;
53921 delete config.tree;
53922 delete config.el; // hopefull!
53924 // wrapper for IE7 strict & safari scroll issue
53926 var treeEl = el.createChild();
53927 config.resizeEl = treeEl;
53931 Roo.TreePanel.superclass.constructor.call(this, el, config);
53934 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53935 //console.log(tree);
53936 this.on('activate', function()
53938 if (this.tree.rendered) {
53941 //console.log('render tree');
53942 this.tree.render();
53944 // this should not be needed.. - it's actually the 'el' that resizes?
53945 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53947 //this.on('resize', function (cp, w, h) {
53948 // this.tree.innerCt.setWidth(w);
53949 // this.tree.innerCt.setHeight(h);
53950 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53957 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53974 * Ext JS Library 1.1.1
53975 * Copyright(c) 2006-2007, Ext JS, LLC.
53977 * Originally Released Under LGPL - original licence link has changed is not relivant.
53980 * <script type="text/javascript">
53985 * @class Roo.ReaderLayout
53986 * @extends Roo.BorderLayout
53987 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53988 * center region containing two nested regions (a top one for a list view and one for item preview below),
53989 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53990 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53991 * expedites the setup of the overall layout and regions for this common application style.
53994 var reader = new Roo.ReaderLayout();
53995 var CP = Roo.ContentPanel; // shortcut for adding
53997 reader.beginUpdate();
53998 reader.add("north", new CP("north", "North"));
53999 reader.add("west", new CP("west", {title: "West"}));
54000 reader.add("east", new CP("east", {title: "East"}));
54002 reader.regions.listView.add(new CP("listView", "List"));
54003 reader.regions.preview.add(new CP("preview", "Preview"));
54004 reader.endUpdate();
54007 * Create a new ReaderLayout
54008 * @param {Object} config Configuration options
54009 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
54010 * document.body if omitted)
54012 Roo.ReaderLayout = function(config, renderTo){
54013 var c = config || {size:{}};
54014 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
54015 north: c.north !== false ? Roo.apply({
54019 }, c.north) : false,
54020 west: c.west !== false ? Roo.apply({
54028 margins:{left:5,right:0,bottom:5,top:5},
54029 cmargins:{left:5,right:5,bottom:5,top:5}
54030 }, c.west) : false,
54031 east: c.east !== false ? Roo.apply({
54039 margins:{left:0,right:5,bottom:5,top:5},
54040 cmargins:{left:5,right:5,bottom:5,top:5}
54041 }, c.east) : false,
54042 center: Roo.apply({
54043 tabPosition: 'top',
54047 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
54051 this.el.addClass('x-reader');
54053 this.beginUpdate();
54055 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
54056 south: c.preview !== false ? Roo.apply({
54063 cmargins:{top:5,left:0, right:0, bottom:0}
54064 }, c.preview) : false,
54065 center: Roo.apply({
54071 this.add('center', new Roo.NestedLayoutPanel(inner,
54072 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
54076 this.regions.preview = inner.getRegion('south');
54077 this.regions.listView = inner.getRegion('center');
54080 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
54082 * Ext JS Library 1.1.1
54083 * Copyright(c) 2006-2007, Ext JS, LLC.
54085 * Originally Released Under LGPL - original licence link has changed is not relivant.
54088 * <script type="text/javascript">
54092 * @class Roo.grid.Grid
54093 * @extends Roo.util.Observable
54094 * This class represents the primary interface of a component based grid control.
54095 * <br><br>Usage:<pre><code>
54096 var grid = new Roo.grid.Grid("my-container-id", {
54099 selModel: mySelectionModel,
54100 autoSizeColumns: true,
54101 monitorWindowResize: false,
54102 trackMouseOver: true
54107 * <b>Common Problems:</b><br/>
54108 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54109 * element will correct this<br/>
54110 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54111 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54112 * are unpredictable.<br/>
54113 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54114 * grid to calculate dimensions/offsets.<br/>
54116 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54117 * The container MUST have some type of size defined for the grid to fill. The container will be
54118 * automatically set to position relative if it isn't already.
54119 * @param {Object} config A config object that sets properties on this grid.
54121 Roo.grid.Grid = function(container, config){
54122 // initialize the container
54123 this.container = Roo.get(container);
54124 this.container.update("");
54125 this.container.setStyle("overflow", "hidden");
54126 this.container.addClass('x-grid-container');
54128 this.id = this.container.id;
54130 Roo.apply(this, config);
54131 // check and correct shorthanded configs
54133 this.dataSource = this.ds;
54137 this.colModel = this.cm;
54141 this.selModel = this.sm;
54145 if (this.selModel) {
54146 this.selModel = Roo.factory(this.selModel, Roo.grid);
54147 this.sm = this.selModel;
54148 this.sm.xmodule = this.xmodule || false;
54150 if (typeof(this.colModel.config) == 'undefined') {
54151 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54152 this.cm = this.colModel;
54153 this.cm.xmodule = this.xmodule || false;
54155 if (this.dataSource) {
54156 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54157 this.ds = this.dataSource;
54158 this.ds.xmodule = this.xmodule || false;
54165 this.container.setWidth(this.width);
54169 this.container.setHeight(this.height);
54176 * The raw click event for the entire grid.
54177 * @param {Roo.EventObject} e
54182 * The raw dblclick event for the entire grid.
54183 * @param {Roo.EventObject} e
54187 * @event contextmenu
54188 * The raw contextmenu event for the entire grid.
54189 * @param {Roo.EventObject} e
54191 "contextmenu" : true,
54194 * The raw mousedown event for the entire grid.
54195 * @param {Roo.EventObject} e
54197 "mousedown" : true,
54200 * The raw mouseup event for the entire grid.
54201 * @param {Roo.EventObject} e
54206 * The raw mouseover event for the entire grid.
54207 * @param {Roo.EventObject} e
54209 "mouseover" : true,
54212 * The raw mouseout event for the entire grid.
54213 * @param {Roo.EventObject} e
54218 * The raw keypress event for the entire grid.
54219 * @param {Roo.EventObject} e
54224 * The raw keydown event for the entire grid.
54225 * @param {Roo.EventObject} e
54233 * Fires when a cell is clicked
54234 * @param {Grid} this
54235 * @param {Number} rowIndex
54236 * @param {Number} columnIndex
54237 * @param {Roo.EventObject} e
54239 "cellclick" : true,
54241 * @event celldblclick
54242 * Fires when a cell is double clicked
54243 * @param {Grid} this
54244 * @param {Number} rowIndex
54245 * @param {Number} columnIndex
54246 * @param {Roo.EventObject} e
54248 "celldblclick" : true,
54251 * Fires when a row is clicked
54252 * @param {Grid} this
54253 * @param {Number} rowIndex
54254 * @param {Roo.EventObject} e
54258 * @event rowdblclick
54259 * Fires when a row is double clicked
54260 * @param {Grid} this
54261 * @param {Number} rowIndex
54262 * @param {Roo.EventObject} e
54264 "rowdblclick" : true,
54266 * @event headerclick
54267 * Fires when a header is clicked
54268 * @param {Grid} this
54269 * @param {Number} columnIndex
54270 * @param {Roo.EventObject} e
54272 "headerclick" : true,
54274 * @event headerdblclick
54275 * Fires when a header cell is double clicked
54276 * @param {Grid} this
54277 * @param {Number} columnIndex
54278 * @param {Roo.EventObject} e
54280 "headerdblclick" : true,
54282 * @event rowcontextmenu
54283 * Fires when a row is right clicked
54284 * @param {Grid} this
54285 * @param {Number} rowIndex
54286 * @param {Roo.EventObject} e
54288 "rowcontextmenu" : true,
54290 * @event cellcontextmenu
54291 * Fires when a cell is right clicked
54292 * @param {Grid} this
54293 * @param {Number} rowIndex
54294 * @param {Number} cellIndex
54295 * @param {Roo.EventObject} e
54297 "cellcontextmenu" : true,
54299 * @event headercontextmenu
54300 * Fires when a header is right clicked
54301 * @param {Grid} this
54302 * @param {Number} columnIndex
54303 * @param {Roo.EventObject} e
54305 "headercontextmenu" : true,
54307 * @event bodyscroll
54308 * Fires when the body element is scrolled
54309 * @param {Number} scrollLeft
54310 * @param {Number} scrollTop
54312 "bodyscroll" : true,
54314 * @event columnresize
54315 * Fires when the user resizes a column
54316 * @param {Number} columnIndex
54317 * @param {Number} newSize
54319 "columnresize" : true,
54321 * @event columnmove
54322 * Fires when the user moves a column
54323 * @param {Number} oldIndex
54324 * @param {Number} newIndex
54326 "columnmove" : true,
54329 * Fires when row(s) start being dragged
54330 * @param {Grid} this
54331 * @param {Roo.GridDD} dd The drag drop object
54332 * @param {event} e The raw browser event
54334 "startdrag" : true,
54337 * Fires when a drag operation is complete
54338 * @param {Grid} this
54339 * @param {Roo.GridDD} dd The drag drop object
54340 * @param {event} e The raw browser event
54345 * Fires when dragged row(s) are dropped on a valid DD target
54346 * @param {Grid} this
54347 * @param {Roo.GridDD} dd The drag drop object
54348 * @param {String} targetId The target drag drop object
54349 * @param {event} e The raw browser event
54354 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54355 * @param {Grid} this
54356 * @param {Roo.GridDD} dd The drag drop object
54357 * @param {String} targetId The target drag drop object
54358 * @param {event} e The raw browser event
54363 * Fires when the dragged row(s) first cross another DD target while being dragged
54364 * @param {Grid} this
54365 * @param {Roo.GridDD} dd The drag drop object
54366 * @param {String} targetId The target drag drop object
54367 * @param {event} e The raw browser event
54369 "dragenter" : true,
54372 * Fires when the dragged row(s) leave another DD target while being dragged
54373 * @param {Grid} this
54374 * @param {Roo.GridDD} dd The drag drop object
54375 * @param {String} targetId The target drag drop object
54376 * @param {event} e The raw browser event
54381 * Fires when a row is rendered, so you can change add a style to it.
54382 * @param {GridView} gridview The grid view
54383 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54389 * Fires when the grid is rendered
54390 * @param {Grid} grid
54395 Roo.grid.Grid.superclass.constructor.call(this);
54397 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54400 * @cfg {String} ddGroup - drag drop group.
54404 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54406 minColumnWidth : 25,
54409 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54410 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54411 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54413 autoSizeColumns : false,
54416 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54418 autoSizeHeaders : true,
54421 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54423 monitorWindowResize : true,
54426 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54427 * rows measured to get a columns size. Default is 0 (all rows).
54429 maxRowsToMeasure : 0,
54432 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54434 trackMouseOver : true,
54437 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54441 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54443 enableDragDrop : false,
54446 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54448 enableColumnMove : true,
54451 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54453 enableColumnHide : true,
54456 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54458 enableRowHeightSync : false,
54461 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54466 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54468 autoHeight : false,
54471 * @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.
54473 autoExpandColumn : false,
54476 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54479 autoExpandMin : 50,
54482 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54484 autoExpandMax : 1000,
54487 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54492 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54496 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54506 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54507 * of a fixed width. Default is false.
54510 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54513 * Called once after all setup has been completed and the grid is ready to be rendered.
54514 * @return {Roo.grid.Grid} this
54516 render : function()
54518 var c = this.container;
54519 // try to detect autoHeight/width mode
54520 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54521 this.autoHeight = true;
54523 var view = this.getView();
54526 c.on("click", this.onClick, this);
54527 c.on("dblclick", this.onDblClick, this);
54528 c.on("contextmenu", this.onContextMenu, this);
54529 c.on("keydown", this.onKeyDown, this);
54531 c.on("touchstart", this.onTouchStart, this);
54534 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54536 this.getSelectionModel().init(this);
54541 this.loadMask = new Roo.LoadMask(this.container,
54542 Roo.apply({store:this.dataSource}, this.loadMask));
54546 if (this.toolbar && this.toolbar.xtype) {
54547 this.toolbar.container = this.getView().getHeaderPanel(true);
54548 this.toolbar = new Roo.Toolbar(this.toolbar);
54550 if (this.footer && this.footer.xtype) {
54551 this.footer.dataSource = this.getDataSource();
54552 this.footer.container = this.getView().getFooterPanel(true);
54553 this.footer = Roo.factory(this.footer, Roo);
54555 if (this.dropTarget && this.dropTarget.xtype) {
54556 delete this.dropTarget.xtype;
54557 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54561 this.rendered = true;
54562 this.fireEvent('render', this);
54567 * Reconfigures the grid to use a different Store and Column Model.
54568 * The View will be bound to the new objects and refreshed.
54569 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54570 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54572 reconfigure : function(dataSource, colModel){
54574 this.loadMask.destroy();
54575 this.loadMask = new Roo.LoadMask(this.container,
54576 Roo.apply({store:dataSource}, this.loadMask));
54578 this.view.bind(dataSource, colModel);
54579 this.dataSource = dataSource;
54580 this.colModel = colModel;
54581 this.view.refresh(true);
54585 onKeyDown : function(e){
54586 this.fireEvent("keydown", e);
54590 * Destroy this grid.
54591 * @param {Boolean} removeEl True to remove the element
54593 destroy : function(removeEl, keepListeners){
54595 this.loadMask.destroy();
54597 var c = this.container;
54598 c.removeAllListeners();
54599 this.view.destroy();
54600 this.colModel.purgeListeners();
54601 if(!keepListeners){
54602 this.purgeListeners();
54605 if(removeEl === true){
54611 processEvent : function(name, e){
54612 // does this fire select???
54613 //Roo.log('grid:processEvent ' + name);
54615 if (name != 'touchstart' ) {
54616 this.fireEvent(name, e);
54619 var t = e.getTarget();
54621 var header = v.findHeaderIndex(t);
54622 if(header !== false){
54623 var ename = name == 'touchstart' ? 'click' : name;
54625 this.fireEvent("header" + ename, this, header, e);
54627 var row = v.findRowIndex(t);
54628 var cell = v.findCellIndex(t);
54629 if (name == 'touchstart') {
54630 // first touch is always a click.
54631 // hopefull this happens after selection is updated.?
54634 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54635 var cs = this.selModel.getSelectedCell();
54636 if (row == cs[0] && cell == cs[1]){
54640 if (typeof(this.selModel.getSelections) != 'undefined') {
54641 var cs = this.selModel.getSelections();
54642 var ds = this.dataSource;
54643 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54654 this.fireEvent("row" + name, this, row, e);
54655 if(cell !== false){
54656 this.fireEvent("cell" + name, this, row, cell, e);
54663 onClick : function(e){
54664 this.processEvent("click", e);
54667 onTouchStart : function(e){
54668 this.processEvent("touchstart", e);
54672 onContextMenu : function(e, t){
54673 this.processEvent("contextmenu", e);
54677 onDblClick : function(e){
54678 this.processEvent("dblclick", e);
54682 walkCells : function(row, col, step, fn, scope){
54683 var cm = this.colModel, clen = cm.getColumnCount();
54684 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54696 if(fn.call(scope || this, row, col, cm) === true){
54714 if(fn.call(scope || this, row, col, cm) === true){
54726 getSelections : function(){
54727 return this.selModel.getSelections();
54731 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54732 * but if manual update is required this method will initiate it.
54734 autoSize : function(){
54736 this.view.layout();
54737 if(this.view.adjustForScroll){
54738 this.view.adjustForScroll();
54744 * Returns the grid's underlying element.
54745 * @return {Element} The element
54747 getGridEl : function(){
54748 return this.container;
54751 // private for compatibility, overridden by editor grid
54752 stopEditing : function(){},
54755 * Returns the grid's SelectionModel.
54756 * @return {SelectionModel}
54758 getSelectionModel : function(){
54759 if(!this.selModel){
54760 this.selModel = new Roo.grid.RowSelectionModel();
54762 return this.selModel;
54766 * Returns the grid's DataSource.
54767 * @return {DataSource}
54769 getDataSource : function(){
54770 return this.dataSource;
54774 * Returns the grid's ColumnModel.
54775 * @return {ColumnModel}
54777 getColumnModel : function(){
54778 return this.colModel;
54782 * Returns the grid's GridView object.
54783 * @return {GridView}
54785 getView : function(){
54787 this.view = new Roo.grid.GridView(this.viewConfig);
54792 * Called to get grid's drag proxy text, by default returns this.ddText.
54795 getDragDropText : function(){
54796 var count = this.selModel.getCount();
54797 return String.format(this.ddText, count, count == 1 ? '' : 's');
54801 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54802 * %0 is replaced with the number of selected rows.
54805 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54807 * Ext JS Library 1.1.1
54808 * Copyright(c) 2006-2007, Ext JS, LLC.
54810 * Originally Released Under LGPL - original licence link has changed is not relivant.
54813 * <script type="text/javascript">
54816 Roo.grid.AbstractGridView = function(){
54820 "beforerowremoved" : true,
54821 "beforerowsinserted" : true,
54822 "beforerefresh" : true,
54823 "rowremoved" : true,
54824 "rowsinserted" : true,
54825 "rowupdated" : true,
54828 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54831 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54832 rowClass : "x-grid-row",
54833 cellClass : "x-grid-cell",
54834 tdClass : "x-grid-td",
54835 hdClass : "x-grid-hd",
54836 splitClass : "x-grid-hd-split",
54838 init: function(grid){
54840 var cid = this.grid.getGridEl().id;
54841 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54842 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54843 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54844 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54847 getColumnRenderers : function(){
54848 var renderers = [];
54849 var cm = this.grid.colModel;
54850 var colCount = cm.getColumnCount();
54851 for(var i = 0; i < colCount; i++){
54852 renderers[i] = cm.getRenderer(i);
54857 getColumnIds : function(){
54859 var cm = this.grid.colModel;
54860 var colCount = cm.getColumnCount();
54861 for(var i = 0; i < colCount; i++){
54862 ids[i] = cm.getColumnId(i);
54867 getDataIndexes : function(){
54868 if(!this.indexMap){
54869 this.indexMap = this.buildIndexMap();
54871 return this.indexMap.colToData;
54874 getColumnIndexByDataIndex : function(dataIndex){
54875 if(!this.indexMap){
54876 this.indexMap = this.buildIndexMap();
54878 return this.indexMap.dataToCol[dataIndex];
54882 * Set a css style for a column dynamically.
54883 * @param {Number} colIndex The index of the column
54884 * @param {String} name The css property name
54885 * @param {String} value The css value
54887 setCSSStyle : function(colIndex, name, value){
54888 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54889 Roo.util.CSS.updateRule(selector, name, value);
54892 generateRules : function(cm){
54893 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54894 Roo.util.CSS.removeStyleSheet(rulesId);
54895 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54896 var cid = cm.getColumnId(i);
54897 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54898 this.tdSelector, cid, " {\n}\n",
54899 this.hdSelector, cid, " {\n}\n",
54900 this.splitSelector, cid, " {\n}\n");
54902 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54906 * Ext JS Library 1.1.1
54907 * Copyright(c) 2006-2007, Ext JS, LLC.
54909 * Originally Released Under LGPL - original licence link has changed is not relivant.
54912 * <script type="text/javascript">
54916 // This is a support class used internally by the Grid components
54917 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54919 this.view = grid.getView();
54920 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54921 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54923 this.setHandleElId(Roo.id(hd));
54924 this.setOuterHandleElId(Roo.id(hd2));
54926 this.scroll = false;
54928 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54930 getDragData : function(e){
54931 var t = Roo.lib.Event.getTarget(e);
54932 var h = this.view.findHeaderCell(t);
54934 return {ddel: h.firstChild, header:h};
54939 onInitDrag : function(e){
54940 this.view.headersDisabled = true;
54941 var clone = this.dragData.ddel.cloneNode(true);
54942 clone.id = Roo.id();
54943 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54944 this.proxy.update(clone);
54948 afterValidDrop : function(){
54950 setTimeout(function(){
54951 v.headersDisabled = false;
54955 afterInvalidDrop : function(){
54957 setTimeout(function(){
54958 v.headersDisabled = false;
54964 * Ext JS Library 1.1.1
54965 * Copyright(c) 2006-2007, Ext JS, LLC.
54967 * Originally Released Under LGPL - original licence link has changed is not relivant.
54970 * <script type="text/javascript">
54973 // This is a support class used internally by the Grid components
54974 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54976 this.view = grid.getView();
54977 // split the proxies so they don't interfere with mouse events
54978 this.proxyTop = Roo.DomHelper.append(document.body, {
54979 cls:"col-move-top", html:" "
54981 this.proxyBottom = Roo.DomHelper.append(document.body, {
54982 cls:"col-move-bottom", html:" "
54984 this.proxyTop.hide = this.proxyBottom.hide = function(){
54985 this.setLeftTop(-100,-100);
54986 this.setStyle("visibility", "hidden");
54988 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54989 // temporarily disabled
54990 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54991 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54993 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54994 proxyOffsets : [-4, -9],
54995 fly: Roo.Element.fly,
54997 getTargetFromEvent : function(e){
54998 var t = Roo.lib.Event.getTarget(e);
54999 var cindex = this.view.findCellIndex(t);
55000 if(cindex !== false){
55001 return this.view.getHeaderCell(cindex);
55006 nextVisible : function(h){
55007 var v = this.view, cm = this.grid.colModel;
55010 if(!cm.isHidden(v.getCellIndex(h))){
55018 prevVisible : function(h){
55019 var v = this.view, cm = this.grid.colModel;
55022 if(!cm.isHidden(v.getCellIndex(h))){
55030 positionIndicator : function(h, n, e){
55031 var x = Roo.lib.Event.getPageX(e);
55032 var r = Roo.lib.Dom.getRegion(n.firstChild);
55033 var px, pt, py = r.top + this.proxyOffsets[1];
55034 if((r.right - x) <= (r.right-r.left)/2){
55035 px = r.right+this.view.borderWidth;
55041 var oldIndex = this.view.getCellIndex(h);
55042 var newIndex = this.view.getCellIndex(n);
55044 if(this.grid.colModel.isFixed(newIndex)){
55048 var locked = this.grid.colModel.isLocked(newIndex);
55053 if(oldIndex < newIndex){
55056 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
55059 px += this.proxyOffsets[0];
55060 this.proxyTop.setLeftTop(px, py);
55061 this.proxyTop.show();
55062 if(!this.bottomOffset){
55063 this.bottomOffset = this.view.mainHd.getHeight();
55065 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
55066 this.proxyBottom.show();
55070 onNodeEnter : function(n, dd, e, data){
55071 if(data.header != n){
55072 this.positionIndicator(data.header, n, e);
55076 onNodeOver : function(n, dd, e, data){
55077 var result = false;
55078 if(data.header != n){
55079 result = this.positionIndicator(data.header, n, e);
55082 this.proxyTop.hide();
55083 this.proxyBottom.hide();
55085 return result ? this.dropAllowed : this.dropNotAllowed;
55088 onNodeOut : function(n, dd, e, data){
55089 this.proxyTop.hide();
55090 this.proxyBottom.hide();
55093 onNodeDrop : function(n, dd, e, data){
55094 var h = data.header;
55096 var cm = this.grid.colModel;
55097 var x = Roo.lib.Event.getPageX(e);
55098 var r = Roo.lib.Dom.getRegion(n.firstChild);
55099 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55100 var oldIndex = this.view.getCellIndex(h);
55101 var newIndex = this.view.getCellIndex(n);
55102 var locked = cm.isLocked(newIndex);
55106 if(oldIndex < newIndex){
55109 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55112 cm.setLocked(oldIndex, locked, true);
55113 cm.moveColumn(oldIndex, newIndex);
55114 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55122 * Ext JS Library 1.1.1
55123 * Copyright(c) 2006-2007, Ext JS, LLC.
55125 * Originally Released Under LGPL - original licence link has changed is not relivant.
55128 * <script type="text/javascript">
55132 * @class Roo.grid.GridView
55133 * @extends Roo.util.Observable
55136 * @param {Object} config
55138 Roo.grid.GridView = function(config){
55139 Roo.grid.GridView.superclass.constructor.call(this);
55142 Roo.apply(this, config);
55145 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55147 unselectable : 'unselectable="on"',
55148 unselectableCls : 'x-unselectable',
55151 rowClass : "x-grid-row",
55153 cellClass : "x-grid-col",
55155 tdClass : "x-grid-td",
55157 hdClass : "x-grid-hd",
55159 splitClass : "x-grid-split",
55161 sortClasses : ["sort-asc", "sort-desc"],
55163 enableMoveAnim : false,
55167 dh : Roo.DomHelper,
55169 fly : Roo.Element.fly,
55171 css : Roo.util.CSS,
55177 scrollIncrement : 22,
55179 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55181 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55183 bind : function(ds, cm){
55185 this.ds.un("load", this.onLoad, this);
55186 this.ds.un("datachanged", this.onDataChange, this);
55187 this.ds.un("add", this.onAdd, this);
55188 this.ds.un("remove", this.onRemove, this);
55189 this.ds.un("update", this.onUpdate, this);
55190 this.ds.un("clear", this.onClear, this);
55193 ds.on("load", this.onLoad, this);
55194 ds.on("datachanged", this.onDataChange, this);
55195 ds.on("add", this.onAdd, this);
55196 ds.on("remove", this.onRemove, this);
55197 ds.on("update", this.onUpdate, this);
55198 ds.on("clear", this.onClear, this);
55203 this.cm.un("widthchange", this.onColWidthChange, this);
55204 this.cm.un("headerchange", this.onHeaderChange, this);
55205 this.cm.un("hiddenchange", this.onHiddenChange, this);
55206 this.cm.un("columnmoved", this.onColumnMove, this);
55207 this.cm.un("columnlockchange", this.onColumnLock, this);
55210 this.generateRules(cm);
55211 cm.on("widthchange", this.onColWidthChange, this);
55212 cm.on("headerchange", this.onHeaderChange, this);
55213 cm.on("hiddenchange", this.onHiddenChange, this);
55214 cm.on("columnmoved", this.onColumnMove, this);
55215 cm.on("columnlockchange", this.onColumnLock, this);
55220 init: function(grid){
55221 Roo.grid.GridView.superclass.init.call(this, grid);
55223 this.bind(grid.dataSource, grid.colModel);
55225 grid.on("headerclick", this.handleHeaderClick, this);
55227 if(grid.trackMouseOver){
55228 grid.on("mouseover", this.onRowOver, this);
55229 grid.on("mouseout", this.onRowOut, this);
55231 grid.cancelTextSelection = function(){};
55232 this.gridId = grid.id;
55234 var tpls = this.templates || {};
55237 tpls.master = new Roo.Template(
55238 '<div class="x-grid" hidefocus="true">',
55239 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55240 '<div class="x-grid-topbar"></div>',
55241 '<div class="x-grid-scroller"><div></div></div>',
55242 '<div class="x-grid-locked">',
55243 '<div class="x-grid-header">{lockedHeader}</div>',
55244 '<div class="x-grid-body">{lockedBody}</div>',
55246 '<div class="x-grid-viewport">',
55247 '<div class="x-grid-header">{header}</div>',
55248 '<div class="x-grid-body">{body}</div>',
55250 '<div class="x-grid-bottombar"></div>',
55252 '<div class="x-grid-resize-proxy"> </div>',
55255 tpls.master.disableformats = true;
55259 tpls.header = new Roo.Template(
55260 '<table border="0" cellspacing="0" cellpadding="0">',
55261 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55264 tpls.header.disableformats = true;
55266 tpls.header.compile();
55269 tpls.hcell = new Roo.Template(
55270 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55271 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55274 tpls.hcell.disableFormats = true;
55276 tpls.hcell.compile();
55279 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55280 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55281 tpls.hsplit.disableFormats = true;
55283 tpls.hsplit.compile();
55286 tpls.body = new Roo.Template(
55287 '<table border="0" cellspacing="0" cellpadding="0">',
55288 "<tbody>{rows}</tbody>",
55291 tpls.body.disableFormats = true;
55293 tpls.body.compile();
55296 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55297 tpls.row.disableFormats = true;
55299 tpls.row.compile();
55302 tpls.cell = new Roo.Template(
55303 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55304 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55305 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55308 tpls.cell.disableFormats = true;
55310 tpls.cell.compile();
55312 this.templates = tpls;
55315 // remap these for backwards compat
55316 onColWidthChange : function(){
55317 this.updateColumns.apply(this, arguments);
55319 onHeaderChange : function(){
55320 this.updateHeaders.apply(this, arguments);
55322 onHiddenChange : function(){
55323 this.handleHiddenChange.apply(this, arguments);
55325 onColumnMove : function(){
55326 this.handleColumnMove.apply(this, arguments);
55328 onColumnLock : function(){
55329 this.handleLockChange.apply(this, arguments);
55332 onDataChange : function(){
55334 this.updateHeaderSortState();
55337 onClear : function(){
55341 onUpdate : function(ds, record){
55342 this.refreshRow(record);
55345 refreshRow : function(record){
55346 var ds = this.ds, index;
55347 if(typeof record == 'number'){
55349 record = ds.getAt(index);
55351 index = ds.indexOf(record);
55353 this.insertRows(ds, index, index, true);
55354 this.onRemove(ds, record, index+1, true);
55355 this.syncRowHeights(index, index);
55357 this.fireEvent("rowupdated", this, index, record);
55360 onAdd : function(ds, records, index){
55361 this.insertRows(ds, index, index + (records.length-1));
55364 onRemove : function(ds, record, index, isUpdate){
55365 if(isUpdate !== true){
55366 this.fireEvent("beforerowremoved", this, index, record);
55368 var bt = this.getBodyTable(), lt = this.getLockedTable();
55369 if(bt.rows[index]){
55370 bt.firstChild.removeChild(bt.rows[index]);
55372 if(lt.rows[index]){
55373 lt.firstChild.removeChild(lt.rows[index]);
55375 if(isUpdate !== true){
55376 this.stripeRows(index);
55377 this.syncRowHeights(index, index);
55379 this.fireEvent("rowremoved", this, index, record);
55383 onLoad : function(){
55384 this.scrollToTop();
55388 * Scrolls the grid to the top
55390 scrollToTop : function(){
55392 this.scroller.dom.scrollTop = 0;
55398 * Gets a panel in the header of the grid that can be used for toolbars etc.
55399 * After modifying the contents of this panel a call to grid.autoSize() may be
55400 * required to register any changes in size.
55401 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55402 * @return Roo.Element
55404 getHeaderPanel : function(doShow){
55406 this.headerPanel.show();
55408 return this.headerPanel;
55412 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55413 * After modifying the contents of this panel a call to grid.autoSize() may be
55414 * required to register any changes in size.
55415 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55416 * @return Roo.Element
55418 getFooterPanel : function(doShow){
55420 this.footerPanel.show();
55422 return this.footerPanel;
55425 initElements : function(){
55426 var E = Roo.Element;
55427 var el = this.grid.getGridEl().dom.firstChild;
55428 var cs = el.childNodes;
55430 this.el = new E(el);
55432 this.focusEl = new E(el.firstChild);
55433 this.focusEl.swallowEvent("click", true);
55435 this.headerPanel = new E(cs[1]);
55436 this.headerPanel.enableDisplayMode("block");
55438 this.scroller = new E(cs[2]);
55439 this.scrollSizer = new E(this.scroller.dom.firstChild);
55441 this.lockedWrap = new E(cs[3]);
55442 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55443 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55445 this.mainWrap = new E(cs[4]);
55446 this.mainHd = new E(this.mainWrap.dom.firstChild);
55447 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55449 this.footerPanel = new E(cs[5]);
55450 this.footerPanel.enableDisplayMode("block");
55452 this.resizeProxy = new E(cs[6]);
55454 this.headerSelector = String.format(
55455 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55456 this.lockedHd.id, this.mainHd.id
55459 this.splitterSelector = String.format(
55460 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55461 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55464 idToCssName : function(s)
55466 return s.replace(/[^a-z0-9]+/ig, '-');
55469 getHeaderCell : function(index){
55470 return Roo.DomQuery.select(this.headerSelector)[index];
55473 getHeaderCellMeasure : function(index){
55474 return this.getHeaderCell(index).firstChild;
55477 getHeaderCellText : function(index){
55478 return this.getHeaderCell(index).firstChild.firstChild;
55481 getLockedTable : function(){
55482 return this.lockedBody.dom.firstChild;
55485 getBodyTable : function(){
55486 return this.mainBody.dom.firstChild;
55489 getLockedRow : function(index){
55490 return this.getLockedTable().rows[index];
55493 getRow : function(index){
55494 return this.getBodyTable().rows[index];
55497 getRowComposite : function(index){
55499 this.rowEl = new Roo.CompositeElementLite();
55501 var els = [], lrow, mrow;
55502 if(lrow = this.getLockedRow(index)){
55505 if(mrow = this.getRow(index)){
55508 this.rowEl.elements = els;
55512 * Gets the 'td' of the cell
55514 * @param {Integer} rowIndex row to select
55515 * @param {Integer} colIndex column to select
55519 getCell : function(rowIndex, colIndex){
55520 var locked = this.cm.getLockedCount();
55522 if(colIndex < locked){
55523 source = this.lockedBody.dom.firstChild;
55525 source = this.mainBody.dom.firstChild;
55526 colIndex -= locked;
55528 return source.rows[rowIndex].childNodes[colIndex];
55531 getCellText : function(rowIndex, colIndex){
55532 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55535 getCellBox : function(cell){
55536 var b = this.fly(cell).getBox();
55537 if(Roo.isOpera){ // opera fails to report the Y
55538 b.y = cell.offsetTop + this.mainBody.getY();
55543 getCellIndex : function(cell){
55544 var id = String(cell.className).match(this.cellRE);
55546 return parseInt(id[1], 10);
55551 findHeaderIndex : function(n){
55552 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55553 return r ? this.getCellIndex(r) : false;
55556 findHeaderCell : function(n){
55557 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55558 return r ? r : false;
55561 findRowIndex : function(n){
55565 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55566 return r ? r.rowIndex : false;
55569 findCellIndex : function(node){
55570 var stop = this.el.dom;
55571 while(node && node != stop){
55572 if(this.findRE.test(node.className)){
55573 return this.getCellIndex(node);
55575 node = node.parentNode;
55580 getColumnId : function(index){
55581 return this.cm.getColumnId(index);
55584 getSplitters : function()
55586 if(this.splitterSelector){
55587 return Roo.DomQuery.select(this.splitterSelector);
55593 getSplitter : function(index){
55594 return this.getSplitters()[index];
55597 onRowOver : function(e, t){
55599 if((row = this.findRowIndex(t)) !== false){
55600 this.getRowComposite(row).addClass("x-grid-row-over");
55604 onRowOut : function(e, t){
55606 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55607 this.getRowComposite(row).removeClass("x-grid-row-over");
55611 renderHeaders : function(){
55613 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55614 var cb = [], lb = [], sb = [], lsb = [], p = {};
55615 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55616 p.cellId = "x-grid-hd-0-" + i;
55617 p.splitId = "x-grid-csplit-0-" + i;
55618 p.id = cm.getColumnId(i);
55619 p.value = cm.getColumnHeader(i) || "";
55620 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55621 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55622 if(!cm.isLocked(i)){
55623 cb[cb.length] = ct.apply(p);
55624 sb[sb.length] = st.apply(p);
55626 lb[lb.length] = ct.apply(p);
55627 lsb[lsb.length] = st.apply(p);
55630 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55631 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55634 updateHeaders : function(){
55635 var html = this.renderHeaders();
55636 this.lockedHd.update(html[0]);
55637 this.mainHd.update(html[1]);
55641 * Focuses the specified row.
55642 * @param {Number} row The row index
55644 focusRow : function(row)
55646 //Roo.log('GridView.focusRow');
55647 var x = this.scroller.dom.scrollLeft;
55648 this.focusCell(row, 0, false);
55649 this.scroller.dom.scrollLeft = x;
55653 * Focuses the specified cell.
55654 * @param {Number} row The row index
55655 * @param {Number} col The column index
55656 * @param {Boolean} hscroll false to disable horizontal scrolling
55658 focusCell : function(row, col, hscroll)
55660 //Roo.log('GridView.focusCell');
55661 var el = this.ensureVisible(row, col, hscroll);
55662 this.focusEl.alignTo(el, "tl-tl");
55664 this.focusEl.focus();
55666 this.focusEl.focus.defer(1, this.focusEl);
55671 * Scrolls the specified cell into view
55672 * @param {Number} row The row index
55673 * @param {Number} col The column index
55674 * @param {Boolean} hscroll false to disable horizontal scrolling
55676 ensureVisible : function(row, col, hscroll)
55678 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55679 //return null; //disable for testing.
55680 if(typeof row != "number"){
55681 row = row.rowIndex;
55683 if(row < 0 && row >= this.ds.getCount()){
55686 col = (col !== undefined ? col : 0);
55687 var cm = this.grid.colModel;
55688 while(cm.isHidden(col)){
55692 var el = this.getCell(row, col);
55696 var c = this.scroller.dom;
55698 var ctop = parseInt(el.offsetTop, 10);
55699 var cleft = parseInt(el.offsetLeft, 10);
55700 var cbot = ctop + el.offsetHeight;
55701 var cright = cleft + el.offsetWidth;
55703 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55704 var stop = parseInt(c.scrollTop, 10);
55705 var sleft = parseInt(c.scrollLeft, 10);
55706 var sbot = stop + ch;
55707 var sright = sleft + c.clientWidth;
55709 Roo.log('GridView.ensureVisible:' +
55711 ' c.clientHeight:' + c.clientHeight +
55712 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55720 c.scrollTop = ctop;
55721 //Roo.log("set scrolltop to ctop DISABLE?");
55722 }else if(cbot > sbot){
55723 //Roo.log("set scrolltop to cbot-ch");
55724 c.scrollTop = cbot-ch;
55727 if(hscroll !== false){
55729 c.scrollLeft = cleft;
55730 }else if(cright > sright){
55731 c.scrollLeft = cright-c.clientWidth;
55738 updateColumns : function(){
55739 this.grid.stopEditing();
55740 var cm = this.grid.colModel, colIds = this.getColumnIds();
55741 //var totalWidth = cm.getTotalWidth();
55743 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55744 //if(cm.isHidden(i)) continue;
55745 var w = cm.getColumnWidth(i);
55746 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55747 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55749 this.updateSplitters();
55752 generateRules : function(cm){
55753 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55754 Roo.util.CSS.removeStyleSheet(rulesId);
55755 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55756 var cid = cm.getColumnId(i);
55758 if(cm.config[i].align){
55759 align = 'text-align:'+cm.config[i].align+';';
55762 if(cm.isHidden(i)){
55763 hidden = 'display:none;';
55765 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55767 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55768 this.hdSelector, cid, " {\n", align, width, "}\n",
55769 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55770 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55772 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55775 updateSplitters : function(){
55776 var cm = this.cm, s = this.getSplitters();
55777 if(s){ // splitters not created yet
55778 var pos = 0, locked = true;
55779 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55780 if(cm.isHidden(i)) {
55783 var w = cm.getColumnWidth(i); // make sure it's a number
55784 if(!cm.isLocked(i) && locked){
55789 s[i].style.left = (pos-this.splitOffset) + "px";
55794 handleHiddenChange : function(colModel, colIndex, hidden){
55796 this.hideColumn(colIndex);
55798 this.unhideColumn(colIndex);
55802 hideColumn : function(colIndex){
55803 var cid = this.getColumnId(colIndex);
55804 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55805 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55807 this.updateHeaders();
55809 this.updateSplitters();
55813 unhideColumn : function(colIndex){
55814 var cid = this.getColumnId(colIndex);
55815 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55816 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55819 this.updateHeaders();
55821 this.updateSplitters();
55825 insertRows : function(dm, firstRow, lastRow, isUpdate){
55826 if(firstRow == 0 && lastRow == dm.getCount()-1){
55830 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55832 var s = this.getScrollState();
55833 var markup = this.renderRows(firstRow, lastRow);
55834 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55835 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55836 this.restoreScroll(s);
55838 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55839 this.syncRowHeights(firstRow, lastRow);
55840 this.stripeRows(firstRow);
55846 bufferRows : function(markup, target, index){
55847 var before = null, trows = target.rows, tbody = target.tBodies[0];
55848 if(index < trows.length){
55849 before = trows[index];
55851 var b = document.createElement("div");
55852 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55853 var rows = b.firstChild.rows;
55854 for(var i = 0, len = rows.length; i < len; i++){
55856 tbody.insertBefore(rows[0], before);
55858 tbody.appendChild(rows[0]);
55865 deleteRows : function(dm, firstRow, lastRow){
55866 if(dm.getRowCount()<1){
55867 this.fireEvent("beforerefresh", this);
55868 this.mainBody.update("");
55869 this.lockedBody.update("");
55870 this.fireEvent("refresh", this);
55872 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55873 var bt = this.getBodyTable();
55874 var tbody = bt.firstChild;
55875 var rows = bt.rows;
55876 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55877 tbody.removeChild(rows[firstRow]);
55879 this.stripeRows(firstRow);
55880 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55884 updateRows : function(dataSource, firstRow, lastRow){
55885 var s = this.getScrollState();
55887 this.restoreScroll(s);
55890 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55894 this.updateHeaderSortState();
55897 getScrollState : function(){
55899 var sb = this.scroller.dom;
55900 return {left: sb.scrollLeft, top: sb.scrollTop};
55903 stripeRows : function(startRow){
55904 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55907 startRow = startRow || 0;
55908 var rows = this.getBodyTable().rows;
55909 var lrows = this.getLockedTable().rows;
55910 var cls = ' x-grid-row-alt ';
55911 for(var i = startRow, len = rows.length; i < len; i++){
55912 var row = rows[i], lrow = lrows[i];
55913 var isAlt = ((i+1) % 2 == 0);
55914 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55915 if(isAlt == hasAlt){
55919 row.className += " x-grid-row-alt";
55921 row.className = row.className.replace("x-grid-row-alt", "");
55924 lrow.className = row.className;
55929 restoreScroll : function(state){
55930 //Roo.log('GridView.restoreScroll');
55931 var sb = this.scroller.dom;
55932 sb.scrollLeft = state.left;
55933 sb.scrollTop = state.top;
55937 syncScroll : function(){
55938 //Roo.log('GridView.syncScroll');
55939 var sb = this.scroller.dom;
55940 var sh = this.mainHd.dom;
55941 var bs = this.mainBody.dom;
55942 var lv = this.lockedBody.dom;
55943 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55944 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55947 handleScroll : function(e){
55949 var sb = this.scroller.dom;
55950 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55954 handleWheel : function(e){
55955 var d = e.getWheelDelta();
55956 this.scroller.dom.scrollTop -= d*22;
55957 // set this here to prevent jumpy scrolling on large tables
55958 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55962 renderRows : function(startRow, endRow){
55963 // pull in all the crap needed to render rows
55964 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55965 var colCount = cm.getColumnCount();
55967 if(ds.getCount() < 1){
55971 // build a map for all the columns
55973 for(var i = 0; i < colCount; i++){
55974 var name = cm.getDataIndex(i);
55976 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55977 renderer : cm.getRenderer(i),
55978 id : cm.getColumnId(i),
55979 locked : cm.isLocked(i),
55980 has_editor : cm.isCellEditable(i)
55984 startRow = startRow || 0;
55985 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55987 // records to render
55988 var rs = ds.getRange(startRow, endRow);
55990 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55993 // As much as I hate to duplicate code, this was branched because FireFox really hates
55994 // [].join("") on strings. The performance difference was substantial enough to
55995 // branch this function
55996 doRender : Roo.isGecko ?
55997 function(cs, rs, ds, startRow, colCount, stripe){
55998 var ts = this.templates, ct = ts.cell, rt = ts.row;
56000 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56002 var hasListener = this.grid.hasListener('rowclass');
56004 for(var j = 0, len = rs.length; j < len; j++){
56005 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
56006 for(var i = 0; i < colCount; i++){
56008 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56010 p.css = p.attr = "";
56011 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56012 if(p.value == undefined || p.value === "") {
56013 p.value = " ";
56016 p.css += ' x-grid-editable-cell';
56018 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
56019 p.css += ' x-grid-dirty-cell';
56021 var markup = ct.apply(p);
56029 if(stripe && ((rowIndex+1) % 2 == 0)){
56030 alt.push("x-grid-row-alt")
56033 alt.push( " x-grid-dirty-row");
56036 if(this.getRowClass){
56037 alt.push(this.getRowClass(r, rowIndex));
56043 rowIndex : rowIndex,
56046 this.grid.fireEvent('rowclass', this, rowcfg);
56047 alt.push(rowcfg.rowClass);
56049 rp.alt = alt.join(" ");
56050 lbuf+= rt.apply(rp);
56052 buf+= rt.apply(rp);
56054 return [lbuf, buf];
56056 function(cs, rs, ds, startRow, colCount, stripe){
56057 var ts = this.templates, ct = ts.cell, rt = ts.row;
56059 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56060 var hasListener = this.grid.hasListener('rowclass');
56063 for(var j = 0, len = rs.length; j < len; j++){
56064 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
56065 for(var i = 0; i < colCount; i++){
56067 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56069 p.css = p.attr = "";
56070 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56071 if(p.value == undefined || p.value === "") {
56072 p.value = " ";
56076 p.css += ' x-grid-editable-cell';
56078 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
56079 p.css += ' x-grid-dirty-cell'
56082 var markup = ct.apply(p);
56084 cb[cb.length] = markup;
56086 lcb[lcb.length] = markup;
56090 if(stripe && ((rowIndex+1) % 2 == 0)){
56091 alt.push( "x-grid-row-alt");
56094 alt.push(" x-grid-dirty-row");
56097 if(this.getRowClass){
56098 alt.push( this.getRowClass(r, rowIndex));
56104 rowIndex : rowIndex,
56107 this.grid.fireEvent('rowclass', this, rowcfg);
56108 alt.push(rowcfg.rowClass);
56111 rp.alt = alt.join(" ");
56112 rp.cells = lcb.join("");
56113 lbuf[lbuf.length] = rt.apply(rp);
56114 rp.cells = cb.join("");
56115 buf[buf.length] = rt.apply(rp);
56117 return [lbuf.join(""), buf.join("")];
56120 renderBody : function(){
56121 var markup = this.renderRows();
56122 var bt = this.templates.body;
56123 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56127 * Refreshes the grid
56128 * @param {Boolean} headersToo
56130 refresh : function(headersToo){
56131 this.fireEvent("beforerefresh", this);
56132 this.grid.stopEditing();
56133 var result = this.renderBody();
56134 this.lockedBody.update(result[0]);
56135 this.mainBody.update(result[1]);
56136 if(headersToo === true){
56137 this.updateHeaders();
56138 this.updateColumns();
56139 this.updateSplitters();
56140 this.updateHeaderSortState();
56142 this.syncRowHeights();
56144 this.fireEvent("refresh", this);
56147 handleColumnMove : function(cm, oldIndex, newIndex){
56148 this.indexMap = null;
56149 var s = this.getScrollState();
56150 this.refresh(true);
56151 this.restoreScroll(s);
56152 this.afterMove(newIndex);
56155 afterMove : function(colIndex){
56156 if(this.enableMoveAnim && Roo.enableFx){
56157 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56159 // if multisort - fix sortOrder, and reload..
56160 if (this.grid.dataSource.multiSort) {
56161 // the we can call sort again..
56162 var dm = this.grid.dataSource;
56163 var cm = this.grid.colModel;
56165 for(var i = 0; i < cm.config.length; i++ ) {
56167 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56168 continue; // dont' bother, it's not in sort list or being set.
56171 so.push(cm.config[i].dataIndex);
56174 dm.load(dm.lastOptions);
56181 updateCell : function(dm, rowIndex, dataIndex){
56182 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56183 if(typeof colIndex == "undefined"){ // not present in grid
56186 var cm = this.grid.colModel;
56187 var cell = this.getCell(rowIndex, colIndex);
56188 var cellText = this.getCellText(rowIndex, colIndex);
56191 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56192 id : cm.getColumnId(colIndex),
56193 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56195 var renderer = cm.getRenderer(colIndex);
56196 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56197 if(typeof val == "undefined" || val === "") {
56200 cellText.innerHTML = val;
56201 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56202 this.syncRowHeights(rowIndex, rowIndex);
56205 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56207 if(this.grid.autoSizeHeaders){
56208 var h = this.getHeaderCellMeasure(colIndex);
56209 maxWidth = Math.max(maxWidth, h.scrollWidth);
56212 if(this.cm.isLocked(colIndex)){
56213 tb = this.getLockedTable();
56216 tb = this.getBodyTable();
56217 index = colIndex - this.cm.getLockedCount();
56220 var rows = tb.rows;
56221 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56222 for(var i = 0; i < stopIndex; i++){
56223 var cell = rows[i].childNodes[index].firstChild;
56224 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56227 return maxWidth + /*margin for error in IE*/ 5;
56230 * Autofit a column to its content.
56231 * @param {Number} colIndex
56232 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56234 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56235 if(this.cm.isHidden(colIndex)){
56236 return; // can't calc a hidden column
56239 var cid = this.cm.getColumnId(colIndex);
56240 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56241 if(this.grid.autoSizeHeaders){
56242 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56245 var newWidth = this.calcColumnWidth(colIndex);
56246 this.cm.setColumnWidth(colIndex,
56247 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56248 if(!suppressEvent){
56249 this.grid.fireEvent("columnresize", colIndex, newWidth);
56254 * Autofits all columns to their content and then expands to fit any extra space in the grid
56256 autoSizeColumns : function(){
56257 var cm = this.grid.colModel;
56258 var colCount = cm.getColumnCount();
56259 for(var i = 0; i < colCount; i++){
56260 this.autoSizeColumn(i, true, true);
56262 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56265 this.updateColumns();
56271 * Autofits all columns to the grid's width proportionate with their current size
56272 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56274 fitColumns : function(reserveScrollSpace){
56275 var cm = this.grid.colModel;
56276 var colCount = cm.getColumnCount();
56280 for (i = 0; i < colCount; i++){
56281 if(!cm.isHidden(i) && !cm.isFixed(i)){
56282 w = cm.getColumnWidth(i);
56288 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56289 if(reserveScrollSpace){
56292 var frac = (avail - cm.getTotalWidth())/width;
56293 while (cols.length){
56296 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56298 this.updateColumns();
56302 onRowSelect : function(rowIndex){
56303 var row = this.getRowComposite(rowIndex);
56304 row.addClass("x-grid-row-selected");
56307 onRowDeselect : function(rowIndex){
56308 var row = this.getRowComposite(rowIndex);
56309 row.removeClass("x-grid-row-selected");
56312 onCellSelect : function(row, col){
56313 var cell = this.getCell(row, col);
56315 Roo.fly(cell).addClass("x-grid-cell-selected");
56319 onCellDeselect : function(row, col){
56320 var cell = this.getCell(row, col);
56322 Roo.fly(cell).removeClass("x-grid-cell-selected");
56326 updateHeaderSortState : function(){
56328 // sort state can be single { field: xxx, direction : yyy}
56329 // or { xxx=>ASC , yyy : DESC ..... }
56332 if (!this.ds.multiSort) {
56333 var state = this.ds.getSortState();
56337 mstate[state.field] = state.direction;
56338 // FIXME... - this is not used here.. but might be elsewhere..
56339 this.sortState = state;
56342 mstate = this.ds.sortToggle;
56344 //remove existing sort classes..
56346 var sc = this.sortClasses;
56347 var hds = this.el.select(this.headerSelector).removeClass(sc);
56349 for(var f in mstate) {
56351 var sortColumn = this.cm.findColumnIndex(f);
56353 if(sortColumn != -1){
56354 var sortDir = mstate[f];
56355 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56364 handleHeaderClick : function(g, index,e){
56366 Roo.log("header click");
56369 // touch events on header are handled by context
56370 this.handleHdCtx(g,index,e);
56375 if(this.headersDisabled){
56378 var dm = g.dataSource, cm = g.colModel;
56379 if(!cm.isSortable(index)){
56384 if (dm.multiSort) {
56385 // update the sortOrder
56387 for(var i = 0; i < cm.config.length; i++ ) {
56389 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56390 continue; // dont' bother, it's not in sort list or being set.
56393 so.push(cm.config[i].dataIndex);
56399 dm.sort(cm.getDataIndex(index));
56403 destroy : function(){
56405 this.colMenu.removeAll();
56406 Roo.menu.MenuMgr.unregister(this.colMenu);
56407 this.colMenu.getEl().remove();
56408 delete this.colMenu;
56411 this.hmenu.removeAll();
56412 Roo.menu.MenuMgr.unregister(this.hmenu);
56413 this.hmenu.getEl().remove();
56416 if(this.grid.enableColumnMove){
56417 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56419 for(var dd in dds){
56420 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56421 var elid = dds[dd].dragElId;
56423 Roo.get(elid).remove();
56424 } else if(dds[dd].config.isTarget){
56425 dds[dd].proxyTop.remove();
56426 dds[dd].proxyBottom.remove();
56429 if(Roo.dd.DDM.locationCache[dd]){
56430 delete Roo.dd.DDM.locationCache[dd];
56433 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56436 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56437 this.bind(null, null);
56438 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56441 handleLockChange : function(){
56442 this.refresh(true);
56445 onDenyColumnLock : function(){
56449 onDenyColumnHide : function(){
56453 handleHdMenuClick : function(item){
56454 var index = this.hdCtxIndex;
56455 var cm = this.cm, ds = this.ds;
56458 ds.sort(cm.getDataIndex(index), "ASC");
56461 ds.sort(cm.getDataIndex(index), "DESC");
56464 var lc = cm.getLockedCount();
56465 if(cm.getColumnCount(true) <= lc+1){
56466 this.onDenyColumnLock();
56470 cm.setLocked(index, true, true);
56471 cm.moveColumn(index, lc);
56472 this.grid.fireEvent("columnmove", index, lc);
56474 cm.setLocked(index, true);
56478 var lc = cm.getLockedCount();
56479 if((lc-1) != index){
56480 cm.setLocked(index, false, true);
56481 cm.moveColumn(index, lc-1);
56482 this.grid.fireEvent("columnmove", index, lc-1);
56484 cm.setLocked(index, false);
56487 case 'wider': // used to expand cols on touch..
56489 var cw = cm.getColumnWidth(index);
56490 cw += (item.id == 'wider' ? 1 : -1) * 50;
56491 cw = Math.max(0, cw);
56492 cw = Math.min(cw,4000);
56493 cm.setColumnWidth(index, cw);
56497 index = cm.getIndexById(item.id.substr(4));
56499 if(item.checked && cm.getColumnCount(true) <= 1){
56500 this.onDenyColumnHide();
56503 cm.setHidden(index, item.checked);
56509 beforeColMenuShow : function(){
56510 var cm = this.cm, colCount = cm.getColumnCount();
56511 this.colMenu.removeAll();
56512 for(var i = 0; i < colCount; i++){
56513 this.colMenu.add(new Roo.menu.CheckItem({
56514 id: "col-"+cm.getColumnId(i),
56515 text: cm.getColumnHeader(i),
56516 checked: !cm.isHidden(i),
56522 handleHdCtx : function(g, index, e){
56524 var hd = this.getHeaderCell(index);
56525 this.hdCtxIndex = index;
56526 var ms = this.hmenu.items, cm = this.cm;
56527 ms.get("asc").setDisabled(!cm.isSortable(index));
56528 ms.get("desc").setDisabled(!cm.isSortable(index));
56529 if(this.grid.enableColLock !== false){
56530 ms.get("lock").setDisabled(cm.isLocked(index));
56531 ms.get("unlock").setDisabled(!cm.isLocked(index));
56533 this.hmenu.show(hd, "tl-bl");
56536 handleHdOver : function(e){
56537 var hd = this.findHeaderCell(e.getTarget());
56538 if(hd && !this.headersDisabled){
56539 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56540 this.fly(hd).addClass("x-grid-hd-over");
56545 handleHdOut : function(e){
56546 var hd = this.findHeaderCell(e.getTarget());
56548 this.fly(hd).removeClass("x-grid-hd-over");
56552 handleSplitDblClick : function(e, t){
56553 var i = this.getCellIndex(t);
56554 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56555 this.autoSizeColumn(i, true);
56560 render : function(){
56563 var colCount = cm.getColumnCount();
56565 if(this.grid.monitorWindowResize === true){
56566 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56568 var header = this.renderHeaders();
56569 var body = this.templates.body.apply({rows:""});
56570 var html = this.templates.master.apply({
56573 lockedHeader: header[0],
56577 //this.updateColumns();
56579 this.grid.getGridEl().dom.innerHTML = html;
56581 this.initElements();
56583 // a kludge to fix the random scolling effect in webkit
56584 this.el.on("scroll", function() {
56585 this.el.dom.scrollTop=0; // hopefully not recursive..
56588 this.scroller.on("scroll", this.handleScroll, this);
56589 this.lockedBody.on("mousewheel", this.handleWheel, this);
56590 this.mainBody.on("mousewheel", this.handleWheel, this);
56592 this.mainHd.on("mouseover", this.handleHdOver, this);
56593 this.mainHd.on("mouseout", this.handleHdOut, this);
56594 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56595 {delegate: "."+this.splitClass});
56597 this.lockedHd.on("mouseover", this.handleHdOver, this);
56598 this.lockedHd.on("mouseout", this.handleHdOut, this);
56599 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56600 {delegate: "."+this.splitClass});
56602 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56603 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56606 this.updateSplitters();
56608 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56609 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56610 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56613 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56614 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56616 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56617 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56619 if(this.grid.enableColLock !== false){
56620 this.hmenu.add('-',
56621 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56622 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56626 this.hmenu.add('-',
56627 {id:"wider", text: this.columnsWiderText},
56628 {id:"narrow", text: this.columnsNarrowText }
56634 if(this.grid.enableColumnHide !== false){
56636 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56637 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56638 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56640 this.hmenu.add('-',
56641 {id:"columns", text: this.columnsText, menu: this.colMenu}
56644 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56646 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56649 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56650 this.dd = new Roo.grid.GridDragZone(this.grid, {
56651 ddGroup : this.grid.ddGroup || 'GridDD'
56657 for(var i = 0; i < colCount; i++){
56658 if(cm.isHidden(i)){
56659 this.hideColumn(i);
56661 if(cm.config[i].align){
56662 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56663 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56667 this.updateHeaderSortState();
56669 this.beforeInitialResize();
56672 // two part rendering gives faster view to the user
56673 this.renderPhase2.defer(1, this);
56676 renderPhase2 : function(){
56677 // render the rows now
56679 if(this.grid.autoSizeColumns){
56680 this.autoSizeColumns();
56684 beforeInitialResize : function(){
56688 onColumnSplitterMoved : function(i, w){
56689 this.userResized = true;
56690 var cm = this.grid.colModel;
56691 cm.setColumnWidth(i, w, true);
56692 var cid = cm.getColumnId(i);
56693 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56694 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56695 this.updateSplitters();
56697 this.grid.fireEvent("columnresize", i, w);
56700 syncRowHeights : function(startIndex, endIndex){
56701 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56702 startIndex = startIndex || 0;
56703 var mrows = this.getBodyTable().rows;
56704 var lrows = this.getLockedTable().rows;
56705 var len = mrows.length-1;
56706 endIndex = Math.min(endIndex || len, len);
56707 for(var i = startIndex; i <= endIndex; i++){
56708 var m = mrows[i], l = lrows[i];
56709 var h = Math.max(m.offsetHeight, l.offsetHeight);
56710 m.style.height = l.style.height = h + "px";
56715 layout : function(initialRender, is2ndPass){
56717 var auto = g.autoHeight;
56718 var scrollOffset = 16;
56719 var c = g.getGridEl(), cm = this.cm,
56720 expandCol = g.autoExpandColumn,
56722 //c.beginMeasure();
56724 if(!c.dom.offsetWidth){ // display:none?
56726 this.lockedWrap.show();
56727 this.mainWrap.show();
56732 var hasLock = this.cm.isLocked(0);
56734 var tbh = this.headerPanel.getHeight();
56735 var bbh = this.footerPanel.getHeight();
56738 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56739 var newHeight = ch + c.getBorderWidth("tb");
56741 newHeight = Math.min(g.maxHeight, newHeight);
56743 c.setHeight(newHeight);
56747 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56750 var s = this.scroller;
56752 var csize = c.getSize(true);
56754 this.el.setSize(csize.width, csize.height);
56756 this.headerPanel.setWidth(csize.width);
56757 this.footerPanel.setWidth(csize.width);
56759 var hdHeight = this.mainHd.getHeight();
56760 var vw = csize.width;
56761 var vh = csize.height - (tbh + bbh);
56765 var bt = this.getBodyTable();
56767 if(cm.getLockedCount() == cm.config.length){
56768 bt = this.getLockedTable();
56771 var ltWidth = hasLock ?
56772 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56774 var scrollHeight = bt.offsetHeight;
56775 var scrollWidth = ltWidth + bt.offsetWidth;
56776 var vscroll = false, hscroll = false;
56778 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56780 var lw = this.lockedWrap, mw = this.mainWrap;
56781 var lb = this.lockedBody, mb = this.mainBody;
56783 setTimeout(function(){
56784 var t = s.dom.offsetTop;
56785 var w = s.dom.clientWidth,
56786 h = s.dom.clientHeight;
56789 lw.setSize(ltWidth, h);
56791 mw.setLeftTop(ltWidth, t);
56792 mw.setSize(w-ltWidth, h);
56794 lb.setHeight(h-hdHeight);
56795 mb.setHeight(h-hdHeight);
56797 if(is2ndPass !== true && !gv.userResized && expandCol){
56798 // high speed resize without full column calculation
56800 var ci = cm.getIndexById(expandCol);
56802 ci = cm.findColumnIndex(expandCol);
56804 ci = Math.max(0, ci); // make sure it's got at least the first col.
56805 var expandId = cm.getColumnId(ci);
56806 var tw = cm.getTotalWidth(false);
56807 var currentWidth = cm.getColumnWidth(ci);
56808 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56809 if(currentWidth != cw){
56810 cm.setColumnWidth(ci, cw, true);
56811 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56812 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56813 gv.updateSplitters();
56814 gv.layout(false, true);
56826 onWindowResize : function(){
56827 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56833 appendFooter : function(parentEl){
56837 sortAscText : "Sort Ascending",
56838 sortDescText : "Sort Descending",
56839 lockText : "Lock Column",
56840 unlockText : "Unlock Column",
56841 columnsText : "Columns",
56843 columnsWiderText : "Wider",
56844 columnsNarrowText : "Thinner"
56848 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56849 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56850 this.proxy.el.addClass('x-grid3-col-dd');
56853 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56854 handleMouseDown : function(e){
56858 callHandleMouseDown : function(e){
56859 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56864 * Ext JS Library 1.1.1
56865 * Copyright(c) 2006-2007, Ext JS, LLC.
56867 * Originally Released Under LGPL - original licence link has changed is not relivant.
56870 * <script type="text/javascript">
56874 // This is a support class used internally by the Grid components
56875 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56877 this.view = grid.getView();
56878 this.proxy = this.view.resizeProxy;
56879 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56880 "gridSplitters" + this.grid.getGridEl().id, {
56881 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56883 this.setHandleElId(Roo.id(hd));
56884 this.setOuterHandleElId(Roo.id(hd2));
56885 this.scroll = false;
56887 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56888 fly: Roo.Element.fly,
56890 b4StartDrag : function(x, y){
56891 this.view.headersDisabled = true;
56892 this.proxy.setHeight(this.view.mainWrap.getHeight());
56893 var w = this.cm.getColumnWidth(this.cellIndex);
56894 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56895 this.resetConstraints();
56896 this.setXConstraint(minw, 1000);
56897 this.setYConstraint(0, 0);
56898 this.minX = x - minw;
56899 this.maxX = x + 1000;
56901 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56905 handleMouseDown : function(e){
56906 ev = Roo.EventObject.setEvent(e);
56907 var t = this.fly(ev.getTarget());
56908 if(t.hasClass("x-grid-split")){
56909 this.cellIndex = this.view.getCellIndex(t.dom);
56910 this.split = t.dom;
56911 this.cm = this.grid.colModel;
56912 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56913 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56918 endDrag : function(e){
56919 this.view.headersDisabled = false;
56920 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56921 var diff = endX - this.startPos;
56922 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56925 autoOffset : function(){
56926 this.setDelta(0,0);
56930 * Ext JS Library 1.1.1
56931 * Copyright(c) 2006-2007, Ext JS, LLC.
56933 * Originally Released Under LGPL - original licence link has changed is not relivant.
56936 * <script type="text/javascript">
56940 // This is a support class used internally by the Grid components
56941 Roo.grid.GridDragZone = function(grid, config){
56942 this.view = grid.getView();
56943 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56944 if(this.view.lockedBody){
56945 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56946 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56948 this.scroll = false;
56950 this.ddel = document.createElement('div');
56951 this.ddel.className = 'x-grid-dd-wrap';
56954 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56955 ddGroup : "GridDD",
56957 getDragData : function(e){
56958 var t = Roo.lib.Event.getTarget(e);
56959 var rowIndex = this.view.findRowIndex(t);
56960 var sm = this.grid.selModel;
56962 //Roo.log(rowIndex);
56964 if (sm.getSelectedCell) {
56965 // cell selection..
56966 if (!sm.getSelectedCell()) {
56969 if (rowIndex != sm.getSelectedCell()[0]) {
56975 if(rowIndex !== false){
56980 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56982 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56985 if (e.hasModifier()){
56986 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56989 Roo.log("getDragData");
56994 rowIndex: rowIndex,
56995 selections:sm.getSelections ? sm.getSelections() : (
56996 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
57003 onInitDrag : function(e){
57004 var data = this.dragData;
57005 this.ddel.innerHTML = this.grid.getDragDropText();
57006 this.proxy.update(this.ddel);
57007 // fire start drag?
57010 afterRepair : function(){
57011 this.dragging = false;
57014 getRepairXY : function(e, data){
57018 onEndDrag : function(data, e){
57022 onValidDrop : function(dd, e, id){
57027 beforeInvalidDrop : function(e, id){
57032 * Ext JS Library 1.1.1
57033 * Copyright(c) 2006-2007, Ext JS, LLC.
57035 * Originally Released Under LGPL - original licence link has changed is not relivant.
57038 * <script type="text/javascript">
57043 * @class Roo.grid.ColumnModel
57044 * @extends Roo.util.Observable
57045 * This is the default implementation of a ColumnModel used by the Grid. It defines
57046 * the columns in the grid.
57049 var colModel = new Roo.grid.ColumnModel([
57050 {header: "Ticker", width: 60, sortable: true, locked: true},
57051 {header: "Company Name", width: 150, sortable: true},
57052 {header: "Market Cap.", width: 100, sortable: true},
57053 {header: "$ Sales", width: 100, sortable: true, renderer: money},
57054 {header: "Employees", width: 100, sortable: true, resizable: false}
57059 * The config options listed for this class are options which may appear in each
57060 * individual column definition.
57061 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
57063 * @param {Object} config An Array of column config objects. See this class's
57064 * config objects for details.
57066 Roo.grid.ColumnModel = function(config){
57068 * The config passed into the constructor
57070 this.config = config;
57073 // if no id, create one
57074 // if the column does not have a dataIndex mapping,
57075 // map it to the order it is in the config
57076 for(var i = 0, len = config.length; i < len; i++){
57078 if(typeof c.dataIndex == "undefined"){
57081 if(typeof c.renderer == "string"){
57082 c.renderer = Roo.util.Format[c.renderer];
57084 if(typeof c.id == "undefined"){
57087 if(c.editor && c.editor.xtype){
57088 c.editor = Roo.factory(c.editor, Roo.grid);
57090 if(c.editor && c.editor.isFormField){
57091 c.editor = new Roo.grid.GridEditor(c.editor);
57093 this.lookup[c.id] = c;
57097 * The width of columns which have no width specified (defaults to 100)
57100 this.defaultWidth = 100;
57103 * Default sortable of columns which have no sortable specified (defaults to false)
57106 this.defaultSortable = false;
57110 * @event widthchange
57111 * Fires when the width of a column changes.
57112 * @param {ColumnModel} this
57113 * @param {Number} columnIndex The column index
57114 * @param {Number} newWidth The new width
57116 "widthchange": true,
57118 * @event headerchange
57119 * Fires when the text of a header changes.
57120 * @param {ColumnModel} this
57121 * @param {Number} columnIndex The column index
57122 * @param {Number} newText The new header text
57124 "headerchange": true,
57126 * @event hiddenchange
57127 * Fires when a column is hidden or "unhidden".
57128 * @param {ColumnModel} this
57129 * @param {Number} columnIndex The column index
57130 * @param {Boolean} hidden true if hidden, false otherwise
57132 "hiddenchange": true,
57134 * @event columnmoved
57135 * Fires when a column is moved.
57136 * @param {ColumnModel} this
57137 * @param {Number} oldIndex
57138 * @param {Number} newIndex
57140 "columnmoved" : true,
57142 * @event columlockchange
57143 * Fires when a column's locked state is changed
57144 * @param {ColumnModel} this
57145 * @param {Number} colIndex
57146 * @param {Boolean} locked true if locked
57148 "columnlockchange" : true
57150 Roo.grid.ColumnModel.superclass.constructor.call(this);
57152 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57154 * @cfg {String} header The header text to display in the Grid view.
57157 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57158 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57159 * specified, the column's index is used as an index into the Record's data Array.
57162 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57163 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57166 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57167 * Defaults to the value of the {@link #defaultSortable} property.
57168 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57171 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57174 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57177 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57180 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57183 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57184 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57185 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57186 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57189 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57192 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57195 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
57198 * @cfg {String} cursor (Optional)
57201 * @cfg {String} tooltip (Optional)
57204 * @cfg {Number} xs (Optional)
57207 * @cfg {Number} sm (Optional)
57210 * @cfg {Number} md (Optional)
57213 * @cfg {Number} lg (Optional)
57216 * Returns the id of the column at the specified index.
57217 * @param {Number} index The column index
57218 * @return {String} the id
57220 getColumnId : function(index){
57221 return this.config[index].id;
57225 * Returns the column for a specified id.
57226 * @param {String} id The column id
57227 * @return {Object} the column
57229 getColumnById : function(id){
57230 return this.lookup[id];
57235 * Returns the column for a specified dataIndex.
57236 * @param {String} dataIndex The column dataIndex
57237 * @return {Object|Boolean} the column or false if not found
57239 getColumnByDataIndex: function(dataIndex){
57240 var index = this.findColumnIndex(dataIndex);
57241 return index > -1 ? this.config[index] : false;
57245 * Returns the index for a specified column id.
57246 * @param {String} id The column id
57247 * @return {Number} the index, or -1 if not found
57249 getIndexById : function(id){
57250 for(var i = 0, len = this.config.length; i < len; i++){
57251 if(this.config[i].id == id){
57259 * Returns the index for a specified column dataIndex.
57260 * @param {String} dataIndex The column dataIndex
57261 * @return {Number} the index, or -1 if not found
57264 findColumnIndex : function(dataIndex){
57265 for(var i = 0, len = this.config.length; i < len; i++){
57266 if(this.config[i].dataIndex == dataIndex){
57274 moveColumn : function(oldIndex, newIndex){
57275 var c = this.config[oldIndex];
57276 this.config.splice(oldIndex, 1);
57277 this.config.splice(newIndex, 0, c);
57278 this.dataMap = null;
57279 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57282 isLocked : function(colIndex){
57283 return this.config[colIndex].locked === true;
57286 setLocked : function(colIndex, value, suppressEvent){
57287 if(this.isLocked(colIndex) == value){
57290 this.config[colIndex].locked = value;
57291 if(!suppressEvent){
57292 this.fireEvent("columnlockchange", this, colIndex, value);
57296 getTotalLockedWidth : function(){
57297 var totalWidth = 0;
57298 for(var i = 0; i < this.config.length; i++){
57299 if(this.isLocked(i) && !this.isHidden(i)){
57300 this.totalWidth += this.getColumnWidth(i);
57306 getLockedCount : function(){
57307 for(var i = 0, len = this.config.length; i < len; i++){
57308 if(!this.isLocked(i)){
57313 return this.config.length;
57317 * Returns the number of columns.
57320 getColumnCount : function(visibleOnly){
57321 if(visibleOnly === true){
57323 for(var i = 0, len = this.config.length; i < len; i++){
57324 if(!this.isHidden(i)){
57330 return this.config.length;
57334 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57335 * @param {Function} fn
57336 * @param {Object} scope (optional)
57337 * @return {Array} result
57339 getColumnsBy : function(fn, scope){
57341 for(var i = 0, len = this.config.length; i < len; i++){
57342 var c = this.config[i];
57343 if(fn.call(scope||this, c, i) === true){
57351 * Returns true if the specified column is sortable.
57352 * @param {Number} col The column index
57353 * @return {Boolean}
57355 isSortable : function(col){
57356 if(typeof this.config[col].sortable == "undefined"){
57357 return this.defaultSortable;
57359 return this.config[col].sortable;
57363 * Returns the rendering (formatting) function defined for the column.
57364 * @param {Number} col The column index.
57365 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57367 getRenderer : function(col){
57368 if(!this.config[col].renderer){
57369 return Roo.grid.ColumnModel.defaultRenderer;
57371 return this.config[col].renderer;
57375 * Sets the rendering (formatting) function for a column.
57376 * @param {Number} col The column index
57377 * @param {Function} fn The function to use to process the cell's raw data
57378 * to return HTML markup for the grid view. The render function is called with
57379 * the following parameters:<ul>
57380 * <li>Data value.</li>
57381 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57382 * <li>css A CSS style string to apply to the table cell.</li>
57383 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57384 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57385 * <li>Row index</li>
57386 * <li>Column index</li>
57387 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57389 setRenderer : function(col, fn){
57390 this.config[col].renderer = fn;
57394 * Returns the width for the specified column.
57395 * @param {Number} col The column index
57398 getColumnWidth : function(col){
57399 return this.config[col].width * 1 || this.defaultWidth;
57403 * Sets the width for a column.
57404 * @param {Number} col The column index
57405 * @param {Number} width The new width
57407 setColumnWidth : function(col, width, suppressEvent){
57408 this.config[col].width = width;
57409 this.totalWidth = null;
57410 if(!suppressEvent){
57411 this.fireEvent("widthchange", this, col, width);
57416 * Returns the total width of all columns.
57417 * @param {Boolean} includeHidden True to include hidden column widths
57420 getTotalWidth : function(includeHidden){
57421 if(!this.totalWidth){
57422 this.totalWidth = 0;
57423 for(var i = 0, len = this.config.length; i < len; i++){
57424 if(includeHidden || !this.isHidden(i)){
57425 this.totalWidth += this.getColumnWidth(i);
57429 return this.totalWidth;
57433 * Returns the header for the specified column.
57434 * @param {Number} col The column index
57437 getColumnHeader : function(col){
57438 return this.config[col].header;
57442 * Sets the header for a column.
57443 * @param {Number} col The column index
57444 * @param {String} header The new header
57446 setColumnHeader : function(col, header){
57447 this.config[col].header = header;
57448 this.fireEvent("headerchange", this, col, header);
57452 * Returns the tooltip for the specified column.
57453 * @param {Number} col The column index
57456 getColumnTooltip : function(col){
57457 return this.config[col].tooltip;
57460 * Sets the tooltip for a column.
57461 * @param {Number} col The column index
57462 * @param {String} tooltip The new tooltip
57464 setColumnTooltip : function(col, tooltip){
57465 this.config[col].tooltip = tooltip;
57469 * Returns the dataIndex for the specified column.
57470 * @param {Number} col The column index
57473 getDataIndex : function(col){
57474 return this.config[col].dataIndex;
57478 * Sets the dataIndex for a column.
57479 * @param {Number} col The column index
57480 * @param {Number} dataIndex The new dataIndex
57482 setDataIndex : function(col, dataIndex){
57483 this.config[col].dataIndex = dataIndex;
57489 * Returns true if the cell is editable.
57490 * @param {Number} colIndex The column index
57491 * @param {Number} rowIndex The row index - this is nto actually used..?
57492 * @return {Boolean}
57494 isCellEditable : function(colIndex, rowIndex){
57495 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57499 * Returns the editor defined for the cell/column.
57500 * return false or null to disable editing.
57501 * @param {Number} colIndex The column index
57502 * @param {Number} rowIndex The row index
57505 getCellEditor : function(colIndex, rowIndex){
57506 return this.config[colIndex].editor;
57510 * Sets if a column is editable.
57511 * @param {Number} col The column index
57512 * @param {Boolean} editable True if the column is editable
57514 setEditable : function(col, editable){
57515 this.config[col].editable = editable;
57520 * Returns true if the column is hidden.
57521 * @param {Number} colIndex The column index
57522 * @return {Boolean}
57524 isHidden : function(colIndex){
57525 return this.config[colIndex].hidden;
57530 * Returns true if the column width cannot be changed
57532 isFixed : function(colIndex){
57533 return this.config[colIndex].fixed;
57537 * Returns true if the column can be resized
57538 * @return {Boolean}
57540 isResizable : function(colIndex){
57541 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57544 * Sets if a column is hidden.
57545 * @param {Number} colIndex The column index
57546 * @param {Boolean} hidden True if the column is hidden
57548 setHidden : function(colIndex, hidden){
57549 this.config[colIndex].hidden = hidden;
57550 this.totalWidth = null;
57551 this.fireEvent("hiddenchange", this, colIndex, hidden);
57555 * Sets the editor for a column.
57556 * @param {Number} col The column index
57557 * @param {Object} editor The editor object
57559 setEditor : function(col, editor){
57560 this.config[col].editor = editor;
57564 Roo.grid.ColumnModel.defaultRenderer = function(value)
57566 if(typeof value == "object") {
57569 if(typeof value == "string" && value.length < 1){
57573 return String.format("{0}", value);
57576 // Alias for backwards compatibility
57577 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57580 * Ext JS Library 1.1.1
57581 * Copyright(c) 2006-2007, Ext JS, LLC.
57583 * Originally Released Under LGPL - original licence link has changed is not relivant.
57586 * <script type="text/javascript">
57590 * @class Roo.grid.AbstractSelectionModel
57591 * @extends Roo.util.Observable
57592 * Abstract base class for grid SelectionModels. It provides the interface that should be
57593 * implemented by descendant classes. This class should not be directly instantiated.
57596 Roo.grid.AbstractSelectionModel = function(){
57597 this.locked = false;
57598 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57601 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57602 /** @ignore Called by the grid automatically. Do not call directly. */
57603 init : function(grid){
57609 * Locks the selections.
57612 this.locked = true;
57616 * Unlocks the selections.
57618 unlock : function(){
57619 this.locked = false;
57623 * Returns true if the selections are locked.
57624 * @return {Boolean}
57626 isLocked : function(){
57627 return this.locked;
57631 * Ext JS Library 1.1.1
57632 * Copyright(c) 2006-2007, Ext JS, LLC.
57634 * Originally Released Under LGPL - original licence link has changed is not relivant.
57637 * <script type="text/javascript">
57640 * @extends Roo.grid.AbstractSelectionModel
57641 * @class Roo.grid.RowSelectionModel
57642 * The default SelectionModel used by {@link Roo.grid.Grid}.
57643 * It supports multiple selections and keyboard selection/navigation.
57645 * @param {Object} config
57647 Roo.grid.RowSelectionModel = function(config){
57648 Roo.apply(this, config);
57649 this.selections = new Roo.util.MixedCollection(false, function(o){
57654 this.lastActive = false;
57658 * @event selectionchange
57659 * Fires when the selection changes
57660 * @param {SelectionModel} this
57662 "selectionchange" : true,
57664 * @event afterselectionchange
57665 * Fires after the selection changes (eg. by key press or clicking)
57666 * @param {SelectionModel} this
57668 "afterselectionchange" : true,
57670 * @event beforerowselect
57671 * Fires when a row is selected being selected, return false to cancel.
57672 * @param {SelectionModel} this
57673 * @param {Number} rowIndex The selected index
57674 * @param {Boolean} keepExisting False if other selections will be cleared
57676 "beforerowselect" : true,
57679 * Fires when a row is selected.
57680 * @param {SelectionModel} this
57681 * @param {Number} rowIndex The selected index
57682 * @param {Roo.data.Record} r The record
57684 "rowselect" : true,
57686 * @event rowdeselect
57687 * Fires when a row is deselected.
57688 * @param {SelectionModel} this
57689 * @param {Number} rowIndex The selected index
57691 "rowdeselect" : true
57693 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57694 this.locked = false;
57697 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57699 * @cfg {Boolean} singleSelect
57700 * True to allow selection of only one row at a time (defaults to false)
57702 singleSelect : false,
57705 initEvents : function(){
57707 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57708 this.grid.on("mousedown", this.handleMouseDown, this);
57709 }else{ // allow click to work like normal
57710 this.grid.on("rowclick", this.handleDragableRowClick, this);
57713 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57714 "up" : function(e){
57716 this.selectPrevious(e.shiftKey);
57717 }else if(this.last !== false && this.lastActive !== false){
57718 var last = this.last;
57719 this.selectRange(this.last, this.lastActive-1);
57720 this.grid.getView().focusRow(this.lastActive);
57721 if(last !== false){
57725 this.selectFirstRow();
57727 this.fireEvent("afterselectionchange", this);
57729 "down" : function(e){
57731 this.selectNext(e.shiftKey);
57732 }else if(this.last !== false && this.lastActive !== false){
57733 var last = this.last;
57734 this.selectRange(this.last, this.lastActive+1);
57735 this.grid.getView().focusRow(this.lastActive);
57736 if(last !== false){
57740 this.selectFirstRow();
57742 this.fireEvent("afterselectionchange", this);
57747 var view = this.grid.view;
57748 view.on("refresh", this.onRefresh, this);
57749 view.on("rowupdated", this.onRowUpdated, this);
57750 view.on("rowremoved", this.onRemove, this);
57754 onRefresh : function(){
57755 var ds = this.grid.dataSource, i, v = this.grid.view;
57756 var s = this.selections;
57757 s.each(function(r){
57758 if((i = ds.indexOfId(r.id)) != -1){
57760 s.add(ds.getAt(i)); // updating the selection relate data
57768 onRemove : function(v, index, r){
57769 this.selections.remove(r);
57773 onRowUpdated : function(v, index, r){
57774 if(this.isSelected(r)){
57775 v.onRowSelect(index);
57781 * @param {Array} records The records to select
57782 * @param {Boolean} keepExisting (optional) True to keep existing selections
57784 selectRecords : function(records, keepExisting){
57786 this.clearSelections();
57788 var ds = this.grid.dataSource;
57789 for(var i = 0, len = records.length; i < len; i++){
57790 this.selectRow(ds.indexOf(records[i]), true);
57795 * Gets the number of selected rows.
57798 getCount : function(){
57799 return this.selections.length;
57803 * Selects the first row in the grid.
57805 selectFirstRow : function(){
57810 * Select the last row.
57811 * @param {Boolean} keepExisting (optional) True to keep existing selections
57813 selectLastRow : function(keepExisting){
57814 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57818 * Selects the row immediately following the last selected row.
57819 * @param {Boolean} keepExisting (optional) True to keep existing selections
57821 selectNext : function(keepExisting){
57822 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57823 this.selectRow(this.last+1, keepExisting);
57824 this.grid.getView().focusRow(this.last);
57829 * Selects the row that precedes the last selected row.
57830 * @param {Boolean} keepExisting (optional) True to keep existing selections
57832 selectPrevious : function(keepExisting){
57834 this.selectRow(this.last-1, keepExisting);
57835 this.grid.getView().focusRow(this.last);
57840 * Returns the selected records
57841 * @return {Array} Array of selected records
57843 getSelections : function(){
57844 return [].concat(this.selections.items);
57848 * Returns the first selected record.
57851 getSelected : function(){
57852 return this.selections.itemAt(0);
57857 * Clears all selections.
57859 clearSelections : function(fast){
57864 var ds = this.grid.dataSource;
57865 var s = this.selections;
57866 s.each(function(r){
57867 this.deselectRow(ds.indexOfId(r.id));
57871 this.selections.clear();
57878 * Selects all rows.
57880 selectAll : function(){
57884 this.selections.clear();
57885 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57886 this.selectRow(i, true);
57891 * Returns True if there is a selection.
57892 * @return {Boolean}
57894 hasSelection : function(){
57895 return this.selections.length > 0;
57899 * Returns True if the specified row is selected.
57900 * @param {Number/Record} record The record or index of the record to check
57901 * @return {Boolean}
57903 isSelected : function(index){
57904 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57905 return (r && this.selections.key(r.id) ? true : false);
57909 * Returns True if the specified record id is selected.
57910 * @param {String} id The id of record to check
57911 * @return {Boolean}
57913 isIdSelected : function(id){
57914 return (this.selections.key(id) ? true : false);
57918 handleMouseDown : function(e, t){
57919 var view = this.grid.getView(), rowIndex;
57920 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57923 if(e.shiftKey && this.last !== false){
57924 var last = this.last;
57925 this.selectRange(last, rowIndex, e.ctrlKey);
57926 this.last = last; // reset the last
57927 view.focusRow(rowIndex);
57929 var isSelected = this.isSelected(rowIndex);
57930 if(e.button !== 0 && isSelected){
57931 view.focusRow(rowIndex);
57932 }else if(e.ctrlKey && isSelected){
57933 this.deselectRow(rowIndex);
57934 }else if(!isSelected){
57935 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57936 view.focusRow(rowIndex);
57939 this.fireEvent("afterselectionchange", this);
57942 handleDragableRowClick : function(grid, rowIndex, e)
57944 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57945 this.selectRow(rowIndex, false);
57946 grid.view.focusRow(rowIndex);
57947 this.fireEvent("afterselectionchange", this);
57952 * Selects multiple rows.
57953 * @param {Array} rows Array of the indexes of the row to select
57954 * @param {Boolean} keepExisting (optional) True to keep existing selections
57956 selectRows : function(rows, keepExisting){
57958 this.clearSelections();
57960 for(var i = 0, len = rows.length; i < len; i++){
57961 this.selectRow(rows[i], true);
57966 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57967 * @param {Number} startRow The index of the first row in the range
57968 * @param {Number} endRow The index of the last row in the range
57969 * @param {Boolean} keepExisting (optional) True to retain existing selections
57971 selectRange : function(startRow, endRow, keepExisting){
57976 this.clearSelections();
57978 if(startRow <= endRow){
57979 for(var i = startRow; i <= endRow; i++){
57980 this.selectRow(i, true);
57983 for(var i = startRow; i >= endRow; i--){
57984 this.selectRow(i, true);
57990 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57991 * @param {Number} startRow The index of the first row in the range
57992 * @param {Number} endRow The index of the last row in the range
57994 deselectRange : function(startRow, endRow, preventViewNotify){
57998 for(var i = startRow; i <= endRow; i++){
57999 this.deselectRow(i, preventViewNotify);
58005 * @param {Number} row The index of the row to select
58006 * @param {Boolean} keepExisting (optional) True to keep existing selections
58008 selectRow : function(index, keepExisting, preventViewNotify){
58009 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
58012 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
58013 if(!keepExisting || this.singleSelect){
58014 this.clearSelections();
58016 var r = this.grid.dataSource.getAt(index);
58017 this.selections.add(r);
58018 this.last = this.lastActive = index;
58019 if(!preventViewNotify){
58020 this.grid.getView().onRowSelect(index);
58022 this.fireEvent("rowselect", this, index, r);
58023 this.fireEvent("selectionchange", this);
58029 * @param {Number} row The index of the row to deselect
58031 deselectRow : function(index, preventViewNotify){
58035 if(this.last == index){
58038 if(this.lastActive == index){
58039 this.lastActive = false;
58041 var r = this.grid.dataSource.getAt(index);
58042 this.selections.remove(r);
58043 if(!preventViewNotify){
58044 this.grid.getView().onRowDeselect(index);
58046 this.fireEvent("rowdeselect", this, index);
58047 this.fireEvent("selectionchange", this);
58051 restoreLast : function(){
58053 this.last = this._last;
58058 acceptsNav : function(row, col, cm){
58059 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58063 onEditorKey : function(field, e){
58064 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
58069 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58071 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58073 }else if(k == e.ENTER && !e.ctrlKey){
58077 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
58079 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
58081 }else if(k == e.ESC){
58085 g.startEditing(newCell[0], newCell[1]);
58090 * Ext JS Library 1.1.1
58091 * Copyright(c) 2006-2007, Ext JS, LLC.
58093 * Originally Released Under LGPL - original licence link has changed is not relivant.
58096 * <script type="text/javascript">
58099 * @class Roo.grid.CellSelectionModel
58100 * @extends Roo.grid.AbstractSelectionModel
58101 * This class provides the basic implementation for cell selection in a grid.
58103 * @param {Object} config The object containing the configuration of this model.
58104 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58106 Roo.grid.CellSelectionModel = function(config){
58107 Roo.apply(this, config);
58109 this.selection = null;
58113 * @event beforerowselect
58114 * Fires before a cell is selected.
58115 * @param {SelectionModel} this
58116 * @param {Number} rowIndex The selected row index
58117 * @param {Number} colIndex The selected cell index
58119 "beforecellselect" : true,
58121 * @event cellselect
58122 * Fires when a cell is selected.
58123 * @param {SelectionModel} this
58124 * @param {Number} rowIndex The selected row index
58125 * @param {Number} colIndex The selected cell index
58127 "cellselect" : true,
58129 * @event selectionchange
58130 * Fires when the active selection changes.
58131 * @param {SelectionModel} this
58132 * @param {Object} selection null for no selection or an object (o) with two properties
58134 <li>o.record: the record object for the row the selection is in</li>
58135 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58138 "selectionchange" : true,
58141 * Fires when the tab (or enter) was pressed on the last editable cell
58142 * You can use this to trigger add new row.
58143 * @param {SelectionModel} this
58147 * @event beforeeditnext
58148 * Fires before the next editable sell is made active
58149 * You can use this to skip to another cell or fire the tabend
58150 * if you set cell to false
58151 * @param {Object} eventdata object : { cell : [ row, col ] }
58153 "beforeeditnext" : true
58155 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58158 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58160 enter_is_tab: false,
58163 initEvents : function(){
58164 this.grid.on("mousedown", this.handleMouseDown, this);
58165 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58166 var view = this.grid.view;
58167 view.on("refresh", this.onViewChange, this);
58168 view.on("rowupdated", this.onRowUpdated, this);
58169 view.on("beforerowremoved", this.clearSelections, this);
58170 view.on("beforerowsinserted", this.clearSelections, this);
58171 if(this.grid.isEditor){
58172 this.grid.on("beforeedit", this.beforeEdit, this);
58177 beforeEdit : function(e){
58178 this.select(e.row, e.column, false, true, e.record);
58182 onRowUpdated : function(v, index, r){
58183 if(this.selection && this.selection.record == r){
58184 v.onCellSelect(index, this.selection.cell[1]);
58189 onViewChange : function(){
58190 this.clearSelections(true);
58194 * Returns the currently selected cell,.
58195 * @return {Array} The selected cell (row, column) or null if none selected.
58197 getSelectedCell : function(){
58198 return this.selection ? this.selection.cell : null;
58202 * Clears all selections.
58203 * @param {Boolean} true to prevent the gridview from being notified about the change.
58205 clearSelections : function(preventNotify){
58206 var s = this.selection;
58208 if(preventNotify !== true){
58209 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58211 this.selection = null;
58212 this.fireEvent("selectionchange", this, null);
58217 * Returns true if there is a selection.
58218 * @return {Boolean}
58220 hasSelection : function(){
58221 return this.selection ? true : false;
58225 handleMouseDown : function(e, t){
58226 var v = this.grid.getView();
58227 if(this.isLocked()){
58230 var row = v.findRowIndex(t);
58231 var cell = v.findCellIndex(t);
58232 if(row !== false && cell !== false){
58233 this.select(row, cell);
58239 * @param {Number} rowIndex
58240 * @param {Number} collIndex
58242 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58243 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58244 this.clearSelections();
58245 r = r || this.grid.dataSource.getAt(rowIndex);
58248 cell : [rowIndex, colIndex]
58250 if(!preventViewNotify){
58251 var v = this.grid.getView();
58252 v.onCellSelect(rowIndex, colIndex);
58253 if(preventFocus !== true){
58254 v.focusCell(rowIndex, colIndex);
58257 this.fireEvent("cellselect", this, rowIndex, colIndex);
58258 this.fireEvent("selectionchange", this, this.selection);
58263 isSelectable : function(rowIndex, colIndex, cm){
58264 return !cm.isHidden(colIndex);
58268 handleKeyDown : function(e){
58269 //Roo.log('Cell Sel Model handleKeyDown');
58270 if(!e.isNavKeyPress()){
58273 var g = this.grid, s = this.selection;
58276 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58278 this.select(cell[0], cell[1]);
58283 var walk = function(row, col, step){
58284 return g.walkCells(row, col, step, sm.isSelectable, sm);
58286 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58293 // handled by onEditorKey
58294 if (g.isEditor && g.editing) {
58298 newCell = walk(r, c-1, -1);
58300 newCell = walk(r, c+1, 1);
58305 newCell = walk(r+1, c, 1);
58309 newCell = walk(r-1, c, -1);
58313 newCell = walk(r, c+1, 1);
58317 newCell = walk(r, c-1, -1);
58322 if(g.isEditor && !g.editing){
58323 g.startEditing(r, c);
58332 this.select(newCell[0], newCell[1]);
58338 acceptsNav : function(row, col, cm){
58339 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58343 * @param {Number} field (not used) - as it's normally used as a listener
58344 * @param {Number} e - event - fake it by using
58346 * var e = Roo.EventObjectImpl.prototype;
58347 * e.keyCode = e.TAB
58351 onEditorKey : function(field, e){
58353 var k = e.getKey(),
58356 ed = g.activeEditor,
58358 ///Roo.log('onEditorKey' + k);
58361 if (this.enter_is_tab && k == e.ENTER) {
58367 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58369 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58375 } else if(k == e.ENTER && !e.ctrlKey){
58378 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58380 } else if(k == e.ESC){
58385 var ecall = { cell : newCell, forward : forward };
58386 this.fireEvent('beforeeditnext', ecall );
58387 newCell = ecall.cell;
58388 forward = ecall.forward;
58392 //Roo.log('next cell after edit');
58393 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58394 } else if (forward) {
58395 // tabbed past last
58396 this.fireEvent.defer(100, this, ['tabend',this]);
58401 * Ext JS Library 1.1.1
58402 * Copyright(c) 2006-2007, Ext JS, LLC.
58404 * Originally Released Under LGPL - original licence link has changed is not relivant.
58407 * <script type="text/javascript">
58411 * @class Roo.grid.EditorGrid
58412 * @extends Roo.grid.Grid
58413 * Class for creating and editable grid.
58414 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58415 * The container MUST have some type of size defined for the grid to fill. The container will be
58416 * automatically set to position relative if it isn't already.
58417 * @param {Object} dataSource The data model to bind to
58418 * @param {Object} colModel The column model with info about this grid's columns
58420 Roo.grid.EditorGrid = function(container, config){
58421 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58422 this.getGridEl().addClass("xedit-grid");
58424 if(!this.selModel){
58425 this.selModel = new Roo.grid.CellSelectionModel();
58428 this.activeEditor = null;
58432 * @event beforeedit
58433 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58434 * <ul style="padding:5px;padding-left:16px;">
58435 * <li>grid - This grid</li>
58436 * <li>record - The record being edited</li>
58437 * <li>field - The field name being edited</li>
58438 * <li>value - The value for the field being edited.</li>
58439 * <li>row - The grid row index</li>
58440 * <li>column - The grid column index</li>
58441 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58443 * @param {Object} e An edit event (see above for description)
58445 "beforeedit" : true,
58448 * Fires after a cell is edited. <br />
58449 * <ul style="padding:5px;padding-left:16px;">
58450 * <li>grid - This grid</li>
58451 * <li>record - The record being edited</li>
58452 * <li>field - The field name being edited</li>
58453 * <li>value - The value being set</li>
58454 * <li>originalValue - The original value for the field, before the edit.</li>
58455 * <li>row - The grid row index</li>
58456 * <li>column - The grid column index</li>
58458 * @param {Object} e An edit event (see above for description)
58460 "afteredit" : true,
58462 * @event validateedit
58463 * Fires after a cell is edited, but before the value is set in the record.
58464 * You can use this to modify the value being set in the field, Return false
58465 * to cancel the change. The edit event object has the following properties <br />
58466 * <ul style="padding:5px;padding-left:16px;">
58467 * <li>editor - This editor</li>
58468 * <li>grid - This grid</li>
58469 * <li>record - The record being edited</li>
58470 * <li>field - The field name being edited</li>
58471 * <li>value - The value being set</li>
58472 * <li>originalValue - The original value for the field, before the edit.</li>
58473 * <li>row - The grid row index</li>
58474 * <li>column - The grid column index</li>
58475 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58477 * @param {Object} e An edit event (see above for description)
58479 "validateedit" : true
58481 this.on("bodyscroll", this.stopEditing, this);
58482 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58485 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58487 * @cfg {Number} clicksToEdit
58488 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58495 trackMouseOver: false, // causes very odd FF errors
58497 onCellDblClick : function(g, row, col){
58498 this.startEditing(row, col);
58501 onEditComplete : function(ed, value, startValue){
58502 this.editing = false;
58503 this.activeEditor = null;
58504 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58506 var field = this.colModel.getDataIndex(ed.col);
58511 originalValue: startValue,
58518 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58521 if(String(value) !== String(startValue)){
58523 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58524 r.set(field, e.value);
58525 // if we are dealing with a combo box..
58526 // then we also set the 'name' colum to be the displayField
58527 if (ed.field.displayField && ed.field.name) {
58528 r.set(ed.field.name, ed.field.el.dom.value);
58531 delete e.cancel; //?? why!!!
58532 this.fireEvent("afteredit", e);
58535 this.fireEvent("afteredit", e); // always fire it!
58537 this.view.focusCell(ed.row, ed.col);
58541 * Starts editing the specified for the specified row/column
58542 * @param {Number} rowIndex
58543 * @param {Number} colIndex
58545 startEditing : function(row, col){
58546 this.stopEditing();
58547 if(this.colModel.isCellEditable(col, row)){
58548 this.view.ensureVisible(row, col, true);
58550 var r = this.dataSource.getAt(row);
58551 var field = this.colModel.getDataIndex(col);
58552 var cell = Roo.get(this.view.getCell(row,col));
58557 value: r.data[field],
58562 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58563 this.editing = true;
58564 var ed = this.colModel.getCellEditor(col, row);
58570 ed.render(ed.parentEl || document.body);
58576 (function(){ // complex but required for focus issues in safari, ie and opera
58580 ed.on("complete", this.onEditComplete, this, {single: true});
58581 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58582 this.activeEditor = ed;
58583 var v = r.data[field];
58584 ed.startEdit(this.view.getCell(row, col), v);
58585 // combo's with 'displayField and name set
58586 if (ed.field.displayField && ed.field.name) {
58587 ed.field.el.dom.value = r.data[ed.field.name];
58591 }).defer(50, this);
58597 * Stops any active editing
58599 stopEditing : function(){
58600 if(this.activeEditor){
58601 this.activeEditor.completeEdit();
58603 this.activeEditor = null;
58607 * Called to get grid's drag proxy text, by default returns this.ddText.
58610 getDragDropText : function(){
58611 var count = this.selModel.getSelectedCell() ? 1 : 0;
58612 return String.format(this.ddText, count, count == 1 ? '' : 's');
58617 * Ext JS Library 1.1.1
58618 * Copyright(c) 2006-2007, Ext JS, LLC.
58620 * Originally Released Under LGPL - original licence link has changed is not relivant.
58623 * <script type="text/javascript">
58626 // private - not really -- you end up using it !
58627 // This is a support class used internally by the Grid components
58630 * @class Roo.grid.GridEditor
58631 * @extends Roo.Editor
58632 * Class for creating and editable grid elements.
58633 * @param {Object} config any settings (must include field)
58635 Roo.grid.GridEditor = function(field, config){
58636 if (!config && field.field) {
58638 field = Roo.factory(config.field, Roo.form);
58640 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58641 field.monitorTab = false;
58644 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58647 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58650 alignment: "tl-tl",
58653 cls: "x-small-editor x-grid-editor",
58658 * Ext JS Library 1.1.1
58659 * Copyright(c) 2006-2007, Ext JS, LLC.
58661 * Originally Released Under LGPL - original licence link has changed is not relivant.
58664 * <script type="text/javascript">
58669 Roo.grid.PropertyRecord = Roo.data.Record.create([
58670 {name:'name',type:'string'}, 'value'
58674 Roo.grid.PropertyStore = function(grid, source){
58676 this.store = new Roo.data.Store({
58677 recordType : Roo.grid.PropertyRecord
58679 this.store.on('update', this.onUpdate, this);
58681 this.setSource(source);
58683 Roo.grid.PropertyStore.superclass.constructor.call(this);
58688 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58689 setSource : function(o){
58691 this.store.removeAll();
58694 if(this.isEditableValue(o[k])){
58695 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58698 this.store.loadRecords({records: data}, {}, true);
58701 onUpdate : function(ds, record, type){
58702 if(type == Roo.data.Record.EDIT){
58703 var v = record.data['value'];
58704 var oldValue = record.modified['value'];
58705 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58706 this.source[record.id] = v;
58708 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58715 getProperty : function(row){
58716 return this.store.getAt(row);
58719 isEditableValue: function(val){
58720 if(val && val instanceof Date){
58722 }else if(typeof val == 'object' || typeof val == 'function'){
58728 setValue : function(prop, value){
58729 this.source[prop] = value;
58730 this.store.getById(prop).set('value', value);
58733 getSource : function(){
58734 return this.source;
58738 Roo.grid.PropertyColumnModel = function(grid, store){
58741 g.PropertyColumnModel.superclass.constructor.call(this, [
58742 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58743 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58745 this.store = store;
58746 this.bselect = Roo.DomHelper.append(document.body, {
58747 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58748 {tag: 'option', value: 'true', html: 'true'},
58749 {tag: 'option', value: 'false', html: 'false'}
58752 Roo.id(this.bselect);
58755 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58756 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58757 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58758 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58759 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58761 this.renderCellDelegate = this.renderCell.createDelegate(this);
58762 this.renderPropDelegate = this.renderProp.createDelegate(this);
58765 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58769 valueText : 'Value',
58771 dateFormat : 'm/j/Y',
58774 renderDate : function(dateVal){
58775 return dateVal.dateFormat(this.dateFormat);
58778 renderBool : function(bVal){
58779 return bVal ? 'true' : 'false';
58782 isCellEditable : function(colIndex, rowIndex){
58783 return colIndex == 1;
58786 getRenderer : function(col){
58788 this.renderCellDelegate : this.renderPropDelegate;
58791 renderProp : function(v){
58792 return this.getPropertyName(v);
58795 renderCell : function(val){
58797 if(val instanceof Date){
58798 rv = this.renderDate(val);
58799 }else if(typeof val == 'boolean'){
58800 rv = this.renderBool(val);
58802 return Roo.util.Format.htmlEncode(rv);
58805 getPropertyName : function(name){
58806 var pn = this.grid.propertyNames;
58807 return pn && pn[name] ? pn[name] : name;
58810 getCellEditor : function(colIndex, rowIndex){
58811 var p = this.store.getProperty(rowIndex);
58812 var n = p.data['name'], val = p.data['value'];
58814 if(typeof(this.grid.customEditors[n]) == 'string'){
58815 return this.editors[this.grid.customEditors[n]];
58817 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58818 return this.grid.customEditors[n];
58820 if(val instanceof Date){
58821 return this.editors['date'];
58822 }else if(typeof val == 'number'){
58823 return this.editors['number'];
58824 }else if(typeof val == 'boolean'){
58825 return this.editors['boolean'];
58827 return this.editors['string'];
58833 * @class Roo.grid.PropertyGrid
58834 * @extends Roo.grid.EditorGrid
58835 * This class represents the interface of a component based property grid control.
58836 * <br><br>Usage:<pre><code>
58837 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58845 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58846 * The container MUST have some type of size defined for the grid to fill. The container will be
58847 * automatically set to position relative if it isn't already.
58848 * @param {Object} config A config object that sets properties on this grid.
58850 Roo.grid.PropertyGrid = function(container, config){
58851 config = config || {};
58852 var store = new Roo.grid.PropertyStore(this);
58853 this.store = store;
58854 var cm = new Roo.grid.PropertyColumnModel(this, store);
58855 store.store.sort('name', 'ASC');
58856 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58859 enableColLock:false,
58860 enableColumnMove:false,
58862 trackMouseOver: false,
58865 this.getGridEl().addClass('x-props-grid');
58866 this.lastEditRow = null;
58867 this.on('columnresize', this.onColumnResize, this);
58870 * @event beforepropertychange
58871 * Fires before a property changes (return false to stop?)
58872 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58873 * @param {String} id Record Id
58874 * @param {String} newval New Value
58875 * @param {String} oldval Old Value
58877 "beforepropertychange": true,
58879 * @event propertychange
58880 * Fires after a property changes
58881 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58882 * @param {String} id Record Id
58883 * @param {String} newval New Value
58884 * @param {String} oldval Old Value
58886 "propertychange": true
58888 this.customEditors = this.customEditors || {};
58890 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58893 * @cfg {Object} customEditors map of colnames=> custom editors.
58894 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58895 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58896 * false disables editing of the field.
58900 * @cfg {Object} propertyNames map of property Names to their displayed value
58903 render : function(){
58904 Roo.grid.PropertyGrid.superclass.render.call(this);
58905 this.autoSize.defer(100, this);
58908 autoSize : function(){
58909 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58911 this.view.fitColumns();
58915 onColumnResize : function(){
58916 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58920 * Sets the data for the Grid
58921 * accepts a Key => Value object of all the elements avaiable.
58922 * @param {Object} data to appear in grid.
58924 setSource : function(source){
58925 this.store.setSource(source);
58929 * Gets all the data from the grid.
58930 * @return {Object} data data stored in grid
58932 getSource : function(){
58933 return this.store.getSource();
58942 * @class Roo.grid.Calendar
58943 * @extends Roo.util.Grid
58944 * This class extends the Grid to provide a calendar widget
58945 * <br><br>Usage:<pre><code>
58946 var grid = new Roo.grid.Calendar("my-container-id", {
58949 selModel: mySelectionModel,
58950 autoSizeColumns: true,
58951 monitorWindowResize: false,
58952 trackMouseOver: true
58953 eventstore : real data store..
58959 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58960 * The container MUST have some type of size defined for the grid to fill. The container will be
58961 * automatically set to position relative if it isn't already.
58962 * @param {Object} config A config object that sets properties on this grid.
58964 Roo.grid.Calendar = function(container, config){
58965 // initialize the container
58966 this.container = Roo.get(container);
58967 this.container.update("");
58968 this.container.setStyle("overflow", "hidden");
58969 this.container.addClass('x-grid-container');
58971 this.id = this.container.id;
58973 Roo.apply(this, config);
58974 // check and correct shorthanded configs
58978 for (var r = 0;r < 6;r++) {
58981 for (var c =0;c < 7;c++) {
58985 if (this.eventStore) {
58986 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58987 this.eventStore.on('load',this.onLoad, this);
58988 this.eventStore.on('beforeload',this.clearEvents, this);
58992 this.dataSource = new Roo.data.Store({
58993 proxy: new Roo.data.MemoryProxy(rows),
58994 reader: new Roo.data.ArrayReader({}, [
58995 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58998 this.dataSource.load();
58999 this.ds = this.dataSource;
59000 this.ds.xmodule = this.xmodule || false;
59003 var cellRender = function(v,x,r)
59005 return String.format(
59006 '<div class="fc-day fc-widget-content"><div>' +
59007 '<div class="fc-event-container"></div>' +
59008 '<div class="fc-day-number">{0}</div>'+
59010 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
59011 '</div></div>', v);
59016 this.colModel = new Roo.grid.ColumnModel( [
59018 xtype: 'ColumnModel',
59020 dataIndex : 'weekday0',
59022 renderer : cellRender
59025 xtype: 'ColumnModel',
59027 dataIndex : 'weekday1',
59029 renderer : cellRender
59032 xtype: 'ColumnModel',
59034 dataIndex : 'weekday2',
59035 header : 'Tuesday',
59036 renderer : cellRender
59039 xtype: 'ColumnModel',
59041 dataIndex : 'weekday3',
59042 header : 'Wednesday',
59043 renderer : cellRender
59046 xtype: 'ColumnModel',
59048 dataIndex : 'weekday4',
59049 header : 'Thursday',
59050 renderer : cellRender
59053 xtype: 'ColumnModel',
59055 dataIndex : 'weekday5',
59057 renderer : cellRender
59060 xtype: 'ColumnModel',
59062 dataIndex : 'weekday6',
59063 header : 'Saturday',
59064 renderer : cellRender
59067 this.cm = this.colModel;
59068 this.cm.xmodule = this.xmodule || false;
59072 //this.selModel = new Roo.grid.CellSelectionModel();
59073 //this.sm = this.selModel;
59074 //this.selModel.init(this);
59078 this.container.setWidth(this.width);
59082 this.container.setHeight(this.height);
59089 * The raw click event for the entire grid.
59090 * @param {Roo.EventObject} e
59095 * The raw dblclick event for the entire grid.
59096 * @param {Roo.EventObject} e
59100 * @event contextmenu
59101 * The raw contextmenu event for the entire grid.
59102 * @param {Roo.EventObject} e
59104 "contextmenu" : true,
59107 * The raw mousedown event for the entire grid.
59108 * @param {Roo.EventObject} e
59110 "mousedown" : true,
59113 * The raw mouseup event for the entire grid.
59114 * @param {Roo.EventObject} e
59119 * The raw mouseover event for the entire grid.
59120 * @param {Roo.EventObject} e
59122 "mouseover" : true,
59125 * The raw mouseout event for the entire grid.
59126 * @param {Roo.EventObject} e
59131 * The raw keypress event for the entire grid.
59132 * @param {Roo.EventObject} e
59137 * The raw keydown event for the entire grid.
59138 * @param {Roo.EventObject} e
59146 * Fires when a cell is clicked
59147 * @param {Grid} this
59148 * @param {Number} rowIndex
59149 * @param {Number} columnIndex
59150 * @param {Roo.EventObject} e
59152 "cellclick" : true,
59154 * @event celldblclick
59155 * Fires when a cell is double clicked
59156 * @param {Grid} this
59157 * @param {Number} rowIndex
59158 * @param {Number} columnIndex
59159 * @param {Roo.EventObject} e
59161 "celldblclick" : true,
59164 * Fires when a row is clicked
59165 * @param {Grid} this
59166 * @param {Number} rowIndex
59167 * @param {Roo.EventObject} e
59171 * @event rowdblclick
59172 * Fires when a row is double clicked
59173 * @param {Grid} this
59174 * @param {Number} rowIndex
59175 * @param {Roo.EventObject} e
59177 "rowdblclick" : true,
59179 * @event headerclick
59180 * Fires when a header is clicked
59181 * @param {Grid} this
59182 * @param {Number} columnIndex
59183 * @param {Roo.EventObject} e
59185 "headerclick" : true,
59187 * @event headerdblclick
59188 * Fires when a header cell is double clicked
59189 * @param {Grid} this
59190 * @param {Number} columnIndex
59191 * @param {Roo.EventObject} e
59193 "headerdblclick" : true,
59195 * @event rowcontextmenu
59196 * Fires when a row is right clicked
59197 * @param {Grid} this
59198 * @param {Number} rowIndex
59199 * @param {Roo.EventObject} e
59201 "rowcontextmenu" : true,
59203 * @event cellcontextmenu
59204 * Fires when a cell is right clicked
59205 * @param {Grid} this
59206 * @param {Number} rowIndex
59207 * @param {Number} cellIndex
59208 * @param {Roo.EventObject} e
59210 "cellcontextmenu" : true,
59212 * @event headercontextmenu
59213 * Fires when a header is right clicked
59214 * @param {Grid} this
59215 * @param {Number} columnIndex
59216 * @param {Roo.EventObject} e
59218 "headercontextmenu" : true,
59220 * @event bodyscroll
59221 * Fires when the body element is scrolled
59222 * @param {Number} scrollLeft
59223 * @param {Number} scrollTop
59225 "bodyscroll" : true,
59227 * @event columnresize
59228 * Fires when the user resizes a column
59229 * @param {Number} columnIndex
59230 * @param {Number} newSize
59232 "columnresize" : true,
59234 * @event columnmove
59235 * Fires when the user moves a column
59236 * @param {Number} oldIndex
59237 * @param {Number} newIndex
59239 "columnmove" : true,
59242 * Fires when row(s) start being dragged
59243 * @param {Grid} this
59244 * @param {Roo.GridDD} dd The drag drop object
59245 * @param {event} e The raw browser event
59247 "startdrag" : true,
59250 * Fires when a drag operation is complete
59251 * @param {Grid} this
59252 * @param {Roo.GridDD} dd The drag drop object
59253 * @param {event} e The raw browser event
59258 * Fires when dragged row(s) are dropped on a valid DD target
59259 * @param {Grid} this
59260 * @param {Roo.GridDD} dd The drag drop object
59261 * @param {String} targetId The target drag drop object
59262 * @param {event} e The raw browser event
59267 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59268 * @param {Grid} this
59269 * @param {Roo.GridDD} dd The drag drop object
59270 * @param {String} targetId The target drag drop object
59271 * @param {event} e The raw browser event
59276 * Fires when the dragged row(s) first cross another DD target while being dragged
59277 * @param {Grid} this
59278 * @param {Roo.GridDD} dd The drag drop object
59279 * @param {String} targetId The target drag drop object
59280 * @param {event} e The raw browser event
59282 "dragenter" : true,
59285 * Fires when the dragged row(s) leave another DD target while being dragged
59286 * @param {Grid} this
59287 * @param {Roo.GridDD} dd The drag drop object
59288 * @param {String} targetId The target drag drop object
59289 * @param {event} e The raw browser event
59294 * Fires when a row is rendered, so you can change add a style to it.
59295 * @param {GridView} gridview The grid view
59296 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59302 * Fires when the grid is rendered
59303 * @param {Grid} grid
59308 * Fires when a date is selected
59309 * @param {DatePicker} this
59310 * @param {Date} date The selected date
59314 * @event monthchange
59315 * Fires when the displayed month changes
59316 * @param {DatePicker} this
59317 * @param {Date} date The selected month
59319 'monthchange': true,
59321 * @event evententer
59322 * Fires when mouse over an event
59323 * @param {Calendar} this
59324 * @param {event} Event
59326 'evententer': true,
59328 * @event eventleave
59329 * Fires when the mouse leaves an
59330 * @param {Calendar} this
59333 'eventleave': true,
59335 * @event eventclick
59336 * Fires when the mouse click an
59337 * @param {Calendar} this
59340 'eventclick': true,
59342 * @event eventrender
59343 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59344 * @param {Calendar} this
59345 * @param {data} data to be modified
59347 'eventrender': true
59351 Roo.grid.Grid.superclass.constructor.call(this);
59352 this.on('render', function() {
59353 this.view.el.addClass('x-grid-cal');
59355 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59359 if (!Roo.grid.Calendar.style) {
59360 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59363 '.x-grid-cal .x-grid-col' : {
59364 height: 'auto !important',
59365 'vertical-align': 'top'
59367 '.x-grid-cal .fc-event-hori' : {
59378 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59380 * @cfg {Store} eventStore The store that loads events.
59385 activeDate : false,
59388 monitorWindowResize : false,
59391 resizeColumns : function() {
59392 var col = (this.view.el.getWidth() / 7) - 3;
59393 // loop through cols, and setWidth
59394 for(var i =0 ; i < 7 ; i++){
59395 this.cm.setColumnWidth(i, col);
59398 setDate :function(date) {
59400 Roo.log('setDate?');
59402 this.resizeColumns();
59403 var vd = this.activeDate;
59404 this.activeDate = date;
59405 // if(vd && this.el){
59406 // var t = date.getTime();
59407 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59408 // Roo.log('using add remove');
59410 // this.fireEvent('monthchange', this, date);
59412 // this.cells.removeClass("fc-state-highlight");
59413 // this.cells.each(function(c){
59414 // if(c.dateValue == t){
59415 // c.addClass("fc-state-highlight");
59416 // setTimeout(function(){
59417 // try{c.dom.firstChild.focus();}catch(e){}
59427 var days = date.getDaysInMonth();
59429 var firstOfMonth = date.getFirstDateOfMonth();
59430 var startingPos = firstOfMonth.getDay()-this.startDay;
59432 if(startingPos < this.startDay){
59436 var pm = date.add(Date.MONTH, -1);
59437 var prevStart = pm.getDaysInMonth()-startingPos;
59441 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59443 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59444 //this.cells.addClassOnOver('fc-state-hover');
59446 var cells = this.cells.elements;
59447 var textEls = this.textNodes;
59449 //Roo.each(cells, function(cell){
59450 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59453 days += startingPos;
59455 // convert everything to numbers so it's fast
59456 var day = 86400000;
59457 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59460 //Roo.log(prevStart);
59462 var today = new Date().clearTime().getTime();
59463 var sel = date.clearTime().getTime();
59464 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59465 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59466 var ddMatch = this.disabledDatesRE;
59467 var ddText = this.disabledDatesText;
59468 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59469 var ddaysText = this.disabledDaysText;
59470 var format = this.format;
59472 var setCellClass = function(cal, cell){
59474 //Roo.log('set Cell Class');
59476 var t = d.getTime();
59481 cell.dateValue = t;
59483 cell.className += " fc-today";
59484 cell.className += " fc-state-highlight";
59485 cell.title = cal.todayText;
59488 // disable highlight in other month..
59489 cell.className += " fc-state-highlight";
59494 //cell.className = " fc-state-disabled";
59495 cell.title = cal.minText;
59499 //cell.className = " fc-state-disabled";
59500 cell.title = cal.maxText;
59504 if(ddays.indexOf(d.getDay()) != -1){
59505 // cell.title = ddaysText;
59506 // cell.className = " fc-state-disabled";
59509 if(ddMatch && format){
59510 var fvalue = d.dateFormat(format);
59511 if(ddMatch.test(fvalue)){
59512 cell.title = ddText.replace("%0", fvalue);
59513 cell.className = " fc-state-disabled";
59517 if (!cell.initialClassName) {
59518 cell.initialClassName = cell.dom.className;
59521 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59526 for(; i < startingPos; i++) {
59527 cells[i].dayName = (++prevStart);
59528 Roo.log(textEls[i]);
59529 d.setDate(d.getDate()+1);
59531 //cells[i].className = "fc-past fc-other-month";
59532 setCellClass(this, cells[i]);
59537 for(; i < days; i++){
59538 intDay = i - startingPos + 1;
59539 cells[i].dayName = (intDay);
59540 d.setDate(d.getDate()+1);
59542 cells[i].className = ''; // "x-date-active";
59543 setCellClass(this, cells[i]);
59547 for(; i < 42; i++) {
59548 //textEls[i].innerHTML = (++extraDays);
59550 d.setDate(d.getDate()+1);
59551 cells[i].dayName = (++extraDays);
59552 cells[i].className = "fc-future fc-other-month";
59553 setCellClass(this, cells[i]);
59556 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59558 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59560 // this will cause all the cells to mis
59563 for (var r = 0;r < 6;r++) {
59564 for (var c =0;c < 7;c++) {
59565 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59569 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59570 for(i=0;i<cells.length;i++) {
59572 this.cells.elements[i].dayName = cells[i].dayName ;
59573 this.cells.elements[i].className = cells[i].className;
59574 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59575 this.cells.elements[i].title = cells[i].title ;
59576 this.cells.elements[i].dateValue = cells[i].dateValue ;
59582 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59583 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59585 ////if(totalRows != 6){
59586 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59587 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59590 this.fireEvent('monthchange', this, date);
59595 * Returns the grid's SelectionModel.
59596 * @return {SelectionModel}
59598 getSelectionModel : function(){
59599 if(!this.selModel){
59600 this.selModel = new Roo.grid.CellSelectionModel();
59602 return this.selModel;
59606 this.eventStore.load()
59612 findCell : function(dt) {
59613 dt = dt.clearTime().getTime();
59615 this.cells.each(function(c){
59616 //Roo.log("check " +c.dateValue + '?=' + dt);
59617 if(c.dateValue == dt){
59627 findCells : function(rec) {
59628 var s = rec.data.start_dt.clone().clearTime().getTime();
59630 var e= rec.data.end_dt.clone().clearTime().getTime();
59633 this.cells.each(function(c){
59634 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59636 if(c.dateValue > e){
59639 if(c.dateValue < s){
59648 findBestRow: function(cells)
59652 for (var i =0 ; i < cells.length;i++) {
59653 ret = Math.max(cells[i].rows || 0,ret);
59660 addItem : function(rec)
59662 // look for vertical location slot in
59663 var cells = this.findCells(rec);
59665 rec.row = this.findBestRow(cells);
59667 // work out the location.
59671 for(var i =0; i < cells.length; i++) {
59679 if (crow.start.getY() == cells[i].getY()) {
59681 crow.end = cells[i];
59697 for (var i = 0; i < cells.length;i++) {
59698 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59705 clearEvents: function() {
59707 if (!this.eventStore.getCount()) {
59710 // reset number of rows in cells.
59711 Roo.each(this.cells.elements, function(c){
59715 this.eventStore.each(function(e) {
59716 this.clearEvent(e);
59721 clearEvent : function(ev)
59724 Roo.each(ev.els, function(el) {
59725 el.un('mouseenter' ,this.onEventEnter, this);
59726 el.un('mouseleave' ,this.onEventLeave, this);
59734 renderEvent : function(ev,ctr) {
59736 ctr = this.view.el.select('.fc-event-container',true).first();
59740 this.clearEvent(ev);
59746 var cells = ev.cells;
59747 var rows = ev.rows;
59748 this.fireEvent('eventrender', this, ev);
59750 for(var i =0; i < rows.length; i++) {
59754 cls += ' fc-event-start';
59756 if ((i+1) == rows.length) {
59757 cls += ' fc-event-end';
59760 //Roo.log(ev.data);
59761 // how many rows should it span..
59762 var cg = this.eventTmpl.append(ctr,Roo.apply({
59765 }, ev.data) , true);
59768 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59769 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59770 cg.on('click', this.onEventClick, this, ev);
59774 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59775 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59778 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59779 cg.setWidth(ebox.right - sbox.x -2);
59783 renderEvents: function()
59785 // first make sure there is enough space..
59787 if (!this.eventTmpl) {
59788 this.eventTmpl = new Roo.Template(
59789 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59790 '<div class="fc-event-inner">' +
59791 '<span class="fc-event-time">{time}</span>' +
59792 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59794 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59802 this.cells.each(function(c) {
59803 //Roo.log(c.select('.fc-day-content div',true).first());
59804 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59807 var ctr = this.view.el.select('.fc-event-container',true).first();
59810 this.eventStore.each(function(ev){
59812 this.renderEvent(ev);
59816 this.view.layout();
59820 onEventEnter: function (e, el,event,d) {
59821 this.fireEvent('evententer', this, el, event);
59824 onEventLeave: function (e, el,event,d) {
59825 this.fireEvent('eventleave', this, el, event);
59828 onEventClick: function (e, el,event,d) {
59829 this.fireEvent('eventclick', this, el, event);
59832 onMonthChange: function () {
59836 onLoad: function () {
59838 //Roo.log('calendar onload');
59840 if(this.eventStore.getCount() > 0){
59844 this.eventStore.each(function(d){
59849 if (typeof(add.end_dt) == 'undefined') {
59850 Roo.log("Missing End time in calendar data: ");
59854 if (typeof(add.start_dt) == 'undefined') {
59855 Roo.log("Missing Start time in calendar data: ");
59859 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59860 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59861 add.id = add.id || d.id;
59862 add.title = add.title || '??';
59870 this.renderEvents();
59880 render : function ()
59884 if (!this.view.el.hasClass('course-timesheet')) {
59885 this.view.el.addClass('course-timesheet');
59887 if (this.tsStyle) {
59892 Roo.log(_this.grid.view.el.getWidth());
59895 this.tsStyle = Roo.util.CSS.createStyleSheet({
59896 '.course-timesheet .x-grid-row' : {
59899 '.x-grid-row td' : {
59900 'vertical-align' : 0
59902 '.course-edit-link' : {
59904 'text-overflow' : 'ellipsis',
59905 'overflow' : 'hidden',
59906 'white-space' : 'nowrap',
59907 'cursor' : 'pointer'
59912 '.de-act-sup-link' : {
59913 'color' : 'purple',
59914 'text-decoration' : 'line-through'
59918 'text-decoration' : 'line-through'
59920 '.course-timesheet .course-highlight' : {
59921 'border-top-style': 'dashed !important',
59922 'border-bottom-bottom': 'dashed !important'
59924 '.course-timesheet .course-item' : {
59925 'font-family' : 'tahoma, arial, helvetica',
59926 'font-size' : '11px',
59927 'overflow' : 'hidden',
59928 'padding-left' : '10px',
59929 'padding-right' : '10px',
59930 'padding-top' : '10px'
59938 monitorWindowResize : false,
59939 cellrenderer : function(v,x,r)
59944 xtype: 'CellSelectionModel',
59951 beforeload : function (_self, options)
59953 options.params = options.params || {};
59954 options.params._month = _this.monthField.getValue();
59955 options.params.limit = 9999;
59956 options.params['sort'] = 'when_dt';
59957 options.params['dir'] = 'ASC';
59958 this.proxy.loadResponse = this.loadResponse;
59960 //this.addColumns();
59962 load : function (_self, records, options)
59964 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59965 // if you click on the translation.. you can edit it...
59966 var el = Roo.get(this);
59967 var id = el.dom.getAttribute('data-id');
59968 var d = el.dom.getAttribute('data-date');
59969 var t = el.dom.getAttribute('data-time');
59970 //var id = this.child('span').dom.textContent;
59973 Pman.Dialog.CourseCalendar.show({
59977 productitem_active : id ? 1 : 0
59979 _this.grid.ds.load({});
59984 _this.panel.fireEvent('resize', [ '', '' ]);
59987 loadResponse : function(o, success, response){
59988 // this is overridden on before load..
59990 Roo.log("our code?");
59991 //Roo.log(success);
59992 //Roo.log(response)
59993 delete this.activeRequest;
59995 this.fireEvent("loadexception", this, o, response);
59996 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60001 result = o.reader.read(response);
60003 Roo.log("load exception?");
60004 this.fireEvent("loadexception", this, o, response, e);
60005 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60008 Roo.log("ready...");
60009 // loop through result.records;
60010 // and set this.tdate[date] = [] << array of records..
60012 Roo.each(result.records, function(r){
60014 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
60015 _this.tdata[r.data.when_dt.format('j')] = [];
60017 _this.tdata[r.data.when_dt.format('j')].push(r.data);
60020 //Roo.log(_this.tdata);
60022 result.records = [];
60023 result.totalRecords = 6;
60025 // let's generate some duumy records for the rows.
60026 //var st = _this.dateField.getValue();
60028 // work out monday..
60029 //st = st.add(Date.DAY, -1 * st.format('w'));
60031 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60033 var firstOfMonth = date.getFirstDayOfMonth();
60034 var days = date.getDaysInMonth();
60036 var firstAdded = false;
60037 for (var i = 0; i < result.totalRecords ; i++) {
60038 //var d= st.add(Date.DAY, i);
60041 for(var w = 0 ; w < 7 ; w++){
60042 if(!firstAdded && firstOfMonth != w){
60049 var dd = (d > 0 && d < 10) ? "0"+d : d;
60050 row['weekday'+w] = String.format(
60051 '<span style="font-size: 16px;"><b>{0}</b></span>'+
60052 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
60054 date.format('Y-m-')+dd
60057 if(typeof(_this.tdata[d]) != 'undefined'){
60058 Roo.each(_this.tdata[d], function(r){
60062 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
60063 if(r.parent_id*1>0){
60064 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
60067 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
60068 deactive = 'de-act-link';
60071 row['weekday'+w] += String.format(
60072 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
60074 r.product_id_name, //1
60075 r.when_dt.format('h:ia'), //2
60085 // only do this if something added..
60087 result.records.push(_this.grid.dataSource.reader.newRow(row));
60091 // push it twice. (second one with an hour..
60095 this.fireEvent("load", this, o, o.request.arg);
60096 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60098 sortInfo : {field: 'when_dt', direction : 'ASC' },
60100 xtype: 'HttpProxy',
60103 url : baseURL + '/Roo/Shop_course.php'
60106 xtype: 'JsonReader',
60123 'name': 'parent_id',
60127 'name': 'product_id',
60131 'name': 'productitem_id',
60149 click : function (_self, e)
60151 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60152 sd.setMonth(sd.getMonth()-1);
60153 _this.monthField.setValue(sd.format('Y-m-d'));
60154 _this.grid.ds.load({});
60160 xtype: 'Separator',
60164 xtype: 'MonthField',
60167 render : function (_self)
60169 _this.monthField = _self;
60170 // _this.monthField.set today
60172 select : function (combo, date)
60174 _this.grid.ds.load({});
60177 value : (function() { return new Date(); })()
60180 xtype: 'Separator',
60186 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60196 click : function (_self, e)
60198 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60199 sd.setMonth(sd.getMonth()+1);
60200 _this.monthField.setValue(sd.format('Y-m-d'));
60201 _this.grid.ds.load({});
60214 * Ext JS Library 1.1.1
60215 * Copyright(c) 2006-2007, Ext JS, LLC.
60217 * Originally Released Under LGPL - original licence link has changed is not relivant.
60220 * <script type="text/javascript">
60224 * @class Roo.LoadMask
60225 * A simple utility class for generically masking elements while loading data. If the element being masked has
60226 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60227 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60228 * element's UpdateManager load indicator and will be destroyed after the initial load.
60230 * Create a new LoadMask
60231 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60232 * @param {Object} config The config object
60234 Roo.LoadMask = function(el, config){
60235 this.el = Roo.get(el);
60236 Roo.apply(this, config);
60238 this.store.on('beforeload', this.onBeforeLoad, this);
60239 this.store.on('load', this.onLoad, this);
60240 this.store.on('loadexception', this.onLoadException, this);
60241 this.removeMask = false;
60243 var um = this.el.getUpdateManager();
60244 um.showLoadIndicator = false; // disable the default indicator
60245 um.on('beforeupdate', this.onBeforeLoad, this);
60246 um.on('update', this.onLoad, this);
60247 um.on('failure', this.onLoad, this);
60248 this.removeMask = true;
60252 Roo.LoadMask.prototype = {
60254 * @cfg {Boolean} removeMask
60255 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60256 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60259 * @cfg {String} msg
60260 * The text to display in a centered loading message box (defaults to 'Loading...')
60262 msg : 'Loading...',
60264 * @cfg {String} msgCls
60265 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60267 msgCls : 'x-mask-loading',
60270 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60276 * Disables the mask to prevent it from being displayed
60278 disable : function(){
60279 this.disabled = true;
60283 * Enables the mask so that it can be displayed
60285 enable : function(){
60286 this.disabled = false;
60289 onLoadException : function()
60291 Roo.log(arguments);
60293 if (typeof(arguments[3]) != 'undefined') {
60294 Roo.MessageBox.alert("Error loading",arguments[3]);
60298 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60299 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60306 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60309 onLoad : function()
60311 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60315 onBeforeLoad : function(){
60316 if(!this.disabled){
60317 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60322 destroy : function(){
60324 this.store.un('beforeload', this.onBeforeLoad, this);
60325 this.store.un('load', this.onLoad, this);
60326 this.store.un('loadexception', this.onLoadException, this);
60328 var um = this.el.getUpdateManager();
60329 um.un('beforeupdate', this.onBeforeLoad, this);
60330 um.un('update', this.onLoad, this);
60331 um.un('failure', this.onLoad, this);
60336 * Ext JS Library 1.1.1
60337 * Copyright(c) 2006-2007, Ext JS, LLC.
60339 * Originally Released Under LGPL - original licence link has changed is not relivant.
60342 * <script type="text/javascript">
60347 * @class Roo.XTemplate
60348 * @extends Roo.Template
60349 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60351 var t = new Roo.XTemplate(
60352 '<select name="{name}">',
60353 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60357 // then append, applying the master template values
60360 * Supported features:
60365 {a_variable} - output encoded.
60366 {a_variable.format:("Y-m-d")} - call a method on the variable
60367 {a_variable:raw} - unencoded output
60368 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60369 {a_variable:this.method_on_template(...)} - call a method on the template object.
60374 <tpl for="a_variable or condition.."></tpl>
60375 <tpl if="a_variable or condition"></tpl>
60376 <tpl exec="some javascript"></tpl>
60377 <tpl name="named_template"></tpl> (experimental)
60379 <tpl for="."></tpl> - just iterate the property..
60380 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60384 Roo.XTemplate = function()
60386 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60393 Roo.extend(Roo.XTemplate, Roo.Template, {
60396 * The various sub templates
60401 * basic tag replacing syntax
60404 * // you can fake an object call by doing this
60408 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60411 * compile the template
60413 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60416 compile: function()
60420 s = ['<tpl>', s, '</tpl>'].join('');
60422 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60423 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60424 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60425 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60426 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60431 while(true == !!(m = s.match(re))){
60432 var forMatch = m[0].match(nameRe),
60433 ifMatch = m[0].match(ifRe),
60434 execMatch = m[0].match(execRe),
60435 namedMatch = m[0].match(namedRe),
60440 name = forMatch && forMatch[1] ? forMatch[1] : '';
60443 // if - puts fn into test..
60444 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60446 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60451 // exec - calls a function... returns empty if true is returned.
60452 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60454 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60462 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60463 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60464 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60467 var uid = namedMatch ? namedMatch[1] : id;
60471 id: namedMatch ? namedMatch[1] : id,
60478 s = s.replace(m[0], '');
60480 s = s.replace(m[0], '{xtpl'+ id + '}');
60485 for(var i = tpls.length-1; i >= 0; --i){
60486 this.compileTpl(tpls[i]);
60487 this.tpls[tpls[i].id] = tpls[i];
60489 this.master = tpls[tpls.length-1];
60493 * same as applyTemplate, except it's done to one of the subTemplates
60494 * when using named templates, you can do:
60496 * var str = pl.applySubTemplate('your-name', values);
60499 * @param {Number} id of the template
60500 * @param {Object} values to apply to template
60501 * @param {Object} parent (normaly the instance of this object)
60503 applySubTemplate : function(id, values, parent)
60507 var t = this.tpls[id];
60511 if(t.test && !t.test.call(this, values, parent)){
60515 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60516 Roo.log(e.toString());
60522 if(t.exec && t.exec.call(this, values, parent)){
60526 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60527 Roo.log(e.toString());
60532 var vs = t.target ? t.target.call(this, values, parent) : values;
60533 parent = t.target ? values : parent;
60534 if(t.target && vs instanceof Array){
60536 for(var i = 0, len = vs.length; i < len; i++){
60537 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60539 return buf.join('');
60541 return t.compiled.call(this, vs, parent);
60543 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60544 Roo.log(e.toString());
60545 Roo.log(t.compiled);
60550 compileTpl : function(tpl)
60552 var fm = Roo.util.Format;
60553 var useF = this.disableFormats !== true;
60554 var sep = Roo.isGecko ? "+" : ",";
60555 var undef = function(str) {
60556 Roo.log("Property not found :" + str);
60560 var fn = function(m, name, format, args)
60562 //Roo.log(arguments);
60563 args = args ? args.replace(/\\'/g,"'") : args;
60564 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60565 if (typeof(format) == 'undefined') {
60566 format= 'htmlEncode';
60568 if (format == 'raw' ) {
60572 if(name.substr(0, 4) == 'xtpl'){
60573 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60576 // build an array of options to determine if value is undefined..
60578 // basically get 'xxxx.yyyy' then do
60579 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60580 // (function () { Roo.log("Property not found"); return ''; })() :
60585 Roo.each(name.split('.'), function(st) {
60586 lookfor += (lookfor.length ? '.': '') + st;
60587 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60590 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60593 if(format && useF){
60595 args = args ? ',' + args : "";
60597 if(format.substr(0, 5) != "this."){
60598 format = "fm." + format + '(';
60600 format = 'this.call("'+ format.substr(5) + '", ';
60604 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60608 // called with xxyx.yuu:(test,test)
60610 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60612 // raw.. - :raw modifier..
60613 return "'"+ sep + udef_st + name + ")"+sep+"'";
60617 // branched to use + in gecko and [].join() in others
60619 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60620 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60623 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60624 body.push(tpl.body.replace(/(\r\n|\n)/g,
60625 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60626 body.push("'].join('');};};");
60627 body = body.join('');
60630 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60632 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60638 applyTemplate : function(values){
60639 return this.master.compiled.call(this, values, {});
60640 //var s = this.subs;
60643 apply : function(){
60644 return this.applyTemplate.apply(this, arguments);
60649 Roo.XTemplate.from = function(el){
60650 el = Roo.getDom(el);
60651 return new Roo.XTemplate(el.value || el.innerHTML);