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);
9129 this.addClass("x-masked");
9130 this._mask.setDisplayed(true);
9135 while (dom && dom.style) {
9136 if (!isNaN(parseInt(dom.style.zIndex))) {
9137 z = Math.max(z, parseInt(dom.style.zIndex));
9139 dom = dom.parentNode;
9141 // if we are masking the body - then it hides everything..
9142 if (this.dom == document.body) {
9144 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9145 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9148 if(typeof msg == 'string'){
9150 this._maskMsg = Roo.DomHelper.append(this.dom, {
9151 cls: "roo-el-mask-msg",
9155 cls: 'fa fa-spinner fa-spin'
9163 var mm = this._maskMsg;
9164 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9165 if (mm.dom.lastChild) { // weird IE issue?
9166 mm.dom.lastChild.innerHTML = msg;
9168 mm.setDisplayed(true);
9170 mm.setStyle('z-index', z + 102);
9172 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9173 this._mask.setHeight(this.getHeight());
9175 this._mask.setStyle('z-index', z + 100);
9181 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9182 * it is cached for reuse.
9184 unmask : function(removeEl){
9186 if(removeEl === true){
9187 this._mask.remove();
9190 this._maskMsg.remove();
9191 delete this._maskMsg;
9194 this._mask.setDisplayed(false);
9196 this._maskMsg.setDisplayed(false);
9200 this.removeClass("x-masked");
9204 * Returns true if this element is masked
9207 isMasked : function(){
9208 return this._mask && this._mask.isVisible();
9212 * Creates an iframe shim for this element to keep selects and other windowed objects from
9214 * @return {Roo.Element} The new shim element
9216 createShim : function(){
9217 var el = document.createElement('iframe');
9218 el.frameBorder = 'no';
9219 el.className = 'roo-shim';
9220 if(Roo.isIE && Roo.isSecure){
9221 el.src = Roo.SSL_SECURE_URL;
9223 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9224 shim.autoBoxAdjust = false;
9229 * Removes this element from the DOM and deletes it from the cache
9231 remove : function(){
9232 if(this.dom.parentNode){
9233 this.dom.parentNode.removeChild(this.dom);
9235 delete El.cache[this.dom.id];
9239 * Sets up event handlers to add and remove a css class when the mouse is over this element
9240 * @param {String} className
9241 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9242 * mouseout events for children elements
9243 * @return {Roo.Element} this
9245 addClassOnOver : function(className, preventFlicker){
9246 this.on("mouseover", function(){
9247 Roo.fly(this, '_internal').addClass(className);
9249 var removeFn = function(e){
9250 if(preventFlicker !== true || !e.within(this, true)){
9251 Roo.fly(this, '_internal').removeClass(className);
9254 this.on("mouseout", removeFn, this.dom);
9259 * Sets up event handlers to add and remove a css class when this element has the focus
9260 * @param {String} className
9261 * @return {Roo.Element} this
9263 addClassOnFocus : function(className){
9264 this.on("focus", function(){
9265 Roo.fly(this, '_internal').addClass(className);
9267 this.on("blur", function(){
9268 Roo.fly(this, '_internal').removeClass(className);
9273 * 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)
9274 * @param {String} className
9275 * @return {Roo.Element} this
9277 addClassOnClick : function(className){
9279 this.on("mousedown", function(){
9280 Roo.fly(dom, '_internal').addClass(className);
9281 var d = Roo.get(document);
9282 var fn = function(){
9283 Roo.fly(dom, '_internal').removeClass(className);
9284 d.removeListener("mouseup", fn);
9286 d.on("mouseup", fn);
9292 * Stops the specified event from bubbling and optionally prevents the default action
9293 * @param {String} eventName
9294 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9295 * @return {Roo.Element} this
9297 swallowEvent : function(eventName, preventDefault){
9298 var fn = function(e){
9299 e.stopPropagation();
9304 if(eventName instanceof Array){
9305 for(var i = 0, len = eventName.length; i < len; i++){
9306 this.on(eventName[i], fn);
9310 this.on(eventName, fn);
9317 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9320 * Sizes this element to its parent element's dimensions performing
9321 * neccessary box adjustments.
9322 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9323 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9324 * @return {Roo.Element} this
9326 fitToParent : function(monitorResize, targetParent) {
9327 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9328 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9329 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9332 var p = Roo.get(targetParent || this.dom.parentNode);
9333 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9334 if (monitorResize === true) {
9335 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9336 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9342 * Gets the next sibling, skipping text nodes
9343 * @return {HTMLElement} The next sibling or null
9345 getNextSibling : function(){
9346 var n = this.dom.nextSibling;
9347 while(n && n.nodeType != 1){
9354 * Gets the previous sibling, skipping text nodes
9355 * @return {HTMLElement} The previous sibling or null
9357 getPrevSibling : function(){
9358 var n = this.dom.previousSibling;
9359 while(n && n.nodeType != 1){
9360 n = n.previousSibling;
9367 * Appends the passed element(s) to this element
9368 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9369 * @return {Roo.Element} this
9371 appendChild: function(el){
9378 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9379 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9380 * automatically generated with the specified attributes.
9381 * @param {HTMLElement} insertBefore (optional) a child element of this element
9382 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9383 * @return {Roo.Element} The new child element
9385 createChild: function(config, insertBefore, returnDom){
9386 config = config || {tag:'div'};
9388 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9390 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9394 * Appends this element to the passed element
9395 * @param {String/HTMLElement/Element} el The new parent element
9396 * @return {Roo.Element} this
9398 appendTo: function(el){
9399 el = Roo.getDom(el);
9400 el.appendChild(this.dom);
9405 * Inserts this element before the passed element in the DOM
9406 * @param {String/HTMLElement/Element} el The element to insert before
9407 * @return {Roo.Element} this
9409 insertBefore: function(el){
9410 el = Roo.getDom(el);
9411 el.parentNode.insertBefore(this.dom, el);
9416 * Inserts this element after the passed element in the DOM
9417 * @param {String/HTMLElement/Element} el The element to insert after
9418 * @return {Roo.Element} this
9420 insertAfter: function(el){
9421 el = Roo.getDom(el);
9422 el.parentNode.insertBefore(this.dom, el.nextSibling);
9427 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9428 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9429 * @return {Roo.Element} The new child
9431 insertFirst: function(el, returnDom){
9433 if(typeof el == 'object' && !el.nodeType){ // dh config
9434 return this.createChild(el, this.dom.firstChild, returnDom);
9436 el = Roo.getDom(el);
9437 this.dom.insertBefore(el, this.dom.firstChild);
9438 return !returnDom ? Roo.get(el) : el;
9443 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9444 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9445 * @param {String} where (optional) 'before' or 'after' defaults to before
9446 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9447 * @return {Roo.Element} the inserted Element
9449 insertSibling: function(el, where, returnDom){
9450 where = where ? where.toLowerCase() : 'before';
9452 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9454 if(typeof el == 'object' && !el.nodeType){ // dh config
9455 if(where == 'after' && !this.dom.nextSibling){
9456 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9458 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9462 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9463 where == 'before' ? this.dom : this.dom.nextSibling);
9472 * Creates and wraps this element with another element
9473 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9474 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9475 * @return {HTMLElement/Element} The newly created wrapper element
9477 wrap: function(config, returnDom){
9479 config = {tag: "div"};
9481 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9482 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9487 * Replaces the passed element with this element
9488 * @param {String/HTMLElement/Element} el The element to replace
9489 * @return {Roo.Element} this
9491 replace: function(el){
9493 this.insertBefore(el);
9499 * Inserts an html fragment into this element
9500 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9501 * @param {String} html The HTML fragment
9502 * @param {Boolean} returnEl True to return an Roo.Element
9503 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9505 insertHtml : function(where, html, returnEl){
9506 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9507 return returnEl ? Roo.get(el) : el;
9511 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9512 * @param {Object} o The object with the attributes
9513 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9514 * @return {Roo.Element} this
9516 set : function(o, useSet){
9518 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9520 if(attr == "style" || typeof o[attr] == "function") { continue; }
9522 el.className = o["cls"];
9525 el.setAttribute(attr, o[attr]);
9532 Roo.DomHelper.applyStyles(el, o.style);
9538 * Convenience method for constructing a KeyMap
9539 * @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:
9540 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9541 * @param {Function} fn The function to call
9542 * @param {Object} scope (optional) The scope of the function
9543 * @return {Roo.KeyMap} The KeyMap created
9545 addKeyListener : function(key, fn, scope){
9547 if(typeof key != "object" || key instanceof Array){
9563 return new Roo.KeyMap(this, config);
9567 * Creates a KeyMap for this element
9568 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9569 * @return {Roo.KeyMap} The KeyMap created
9571 addKeyMap : function(config){
9572 return new Roo.KeyMap(this, config);
9576 * Returns true if this element is scrollable.
9579 isScrollable : function(){
9581 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9585 * 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().
9586 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9587 * @param {Number} value The new scroll value
9588 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9589 * @return {Element} this
9592 scrollTo : function(side, value, animate){
9593 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9595 this.dom[prop] = value;
9597 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9598 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9604 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9605 * within this element's scrollable range.
9606 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9607 * @param {Number} distance How far to scroll the element in pixels
9608 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9609 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9610 * was scrolled as far as it could go.
9612 scroll : function(direction, distance, animate){
9613 if(!this.isScrollable()){
9617 var l = el.scrollLeft, t = el.scrollTop;
9618 var w = el.scrollWidth, h = el.scrollHeight;
9619 var cw = el.clientWidth, ch = el.clientHeight;
9620 direction = direction.toLowerCase();
9621 var scrolled = false;
9622 var a = this.preanim(arguments, 2);
9627 var v = Math.min(l + distance, w-cw);
9628 this.scrollTo("left", v, a);
9635 var v = Math.max(l - distance, 0);
9636 this.scrollTo("left", v, a);
9644 var v = Math.max(t - distance, 0);
9645 this.scrollTo("top", v, a);
9653 var v = Math.min(t + distance, h-ch);
9654 this.scrollTo("top", v, a);
9663 * Translates the passed page coordinates into left/top css values for this element
9664 * @param {Number/Array} x The page x or an array containing [x, y]
9665 * @param {Number} y The page y
9666 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9668 translatePoints : function(x, y){
9669 if(typeof x == 'object' || x instanceof Array){
9672 var p = this.getStyle('position');
9673 var o = this.getXY();
9675 var l = parseInt(this.getStyle('left'), 10);
9676 var t = parseInt(this.getStyle('top'), 10);
9679 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9682 t = (p == "relative") ? 0 : this.dom.offsetTop;
9685 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9689 * Returns the current scroll position of the element.
9690 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9692 getScroll : function(){
9693 var d = this.dom, doc = document;
9694 if(d == doc || d == doc.body){
9695 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9696 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9697 return {left: l, top: t};
9699 return {left: d.scrollLeft, top: d.scrollTop};
9704 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9705 * are convert to standard 6 digit hex color.
9706 * @param {String} attr The css attribute
9707 * @param {String} defaultValue The default value to use when a valid color isn't found
9708 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9711 getColor : function(attr, defaultValue, prefix){
9712 var v = this.getStyle(attr);
9713 if(!v || v == "transparent" || v == "inherit") {
9714 return defaultValue;
9716 var color = typeof prefix == "undefined" ? "#" : prefix;
9717 if(v.substr(0, 4) == "rgb("){
9718 var rvs = v.slice(4, v.length -1).split(",");
9719 for(var i = 0; i < 3; i++){
9720 var h = parseInt(rvs[i]).toString(16);
9727 if(v.substr(0, 1) == "#"){
9729 for(var i = 1; i < 4; i++){
9730 var c = v.charAt(i);
9733 }else if(v.length == 7){
9734 color += v.substr(1);
9738 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9742 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9743 * gradient background, rounded corners and a 4-way shadow.
9744 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9745 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9746 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9747 * @return {Roo.Element} this
9749 boxWrap : function(cls){
9750 cls = cls || 'x-box';
9751 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9752 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9757 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9758 * @param {String} namespace The namespace in which to look for the attribute
9759 * @param {String} name The attribute name
9760 * @return {String} The attribute value
9762 getAttributeNS : Roo.isIE ? function(ns, name){
9764 var type = typeof d[ns+":"+name];
9765 if(type != 'undefined' && type != 'unknown'){
9766 return d[ns+":"+name];
9769 } : function(ns, name){
9771 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9776 * Sets or Returns the value the dom attribute value
9777 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9778 * @param {String} value (optional) The value to set the attribute to
9779 * @return {String} The attribute value
9781 attr : function(name){
9782 if (arguments.length > 1) {
9783 this.dom.setAttribute(name, arguments[1]);
9784 return arguments[1];
9786 if (typeof(name) == 'object') {
9787 for(var i in name) {
9788 this.attr(i, name[i]);
9794 if (!this.dom.hasAttribute(name)) {
9797 return this.dom.getAttribute(name);
9804 var ep = El.prototype;
9807 * Appends an event handler (Shorthand for addListener)
9808 * @param {String} eventName The type of event to append
9809 * @param {Function} fn The method the event invokes
9810 * @param {Object} scope (optional) The scope (this object) of the fn
9811 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9814 ep.on = ep.addListener;
9816 ep.mon = ep.addListener;
9819 * Removes an event handler from this element (shorthand for removeListener)
9820 * @param {String} eventName the type of event to remove
9821 * @param {Function} fn the method the event invokes
9822 * @return {Roo.Element} this
9825 ep.un = ep.removeListener;
9828 * true to automatically adjust width and height settings for box-model issues (default to true)
9830 ep.autoBoxAdjust = true;
9833 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9836 El.addUnits = function(v, defaultUnit){
9837 if(v === "" || v == "auto"){
9840 if(v === undefined){
9843 if(typeof v == "number" || !El.unitPattern.test(v)){
9844 return v + (defaultUnit || 'px');
9849 // special markup used throughout Roo when box wrapping elements
9850 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>';
9852 * Visibility mode constant - Use visibility to hide element
9858 * Visibility mode constant - Use display to hide element
9864 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9865 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9866 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9878 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9879 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9880 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9881 * @return {Element} The Element object
9884 El.get = function(el){
9886 if(!el){ return null; }
9887 if(typeof el == "string"){ // element id
9888 if(!(elm = document.getElementById(el))){
9891 if(ex = El.cache[el]){
9894 ex = El.cache[el] = new El(elm);
9897 }else if(el.tagName){ // dom element
9901 if(ex = El.cache[id]){
9904 ex = El.cache[id] = new El(el);
9907 }else if(el instanceof El){
9909 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9910 // catch case where it hasn't been appended
9911 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9914 }else if(el.isComposite){
9916 }else if(el instanceof Array){
9917 return El.select(el);
9918 }else if(el == document){
9919 // create a bogus element object representing the document object
9921 var f = function(){};
9922 f.prototype = El.prototype;
9924 docEl.dom = document;
9932 El.uncache = function(el){
9933 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9935 delete El.cache[a[i].id || a[i]];
9941 // Garbage collection - uncache elements/purge listeners on orphaned elements
9942 // so we don't hold a reference and cause the browser to retain them
9943 El.garbageCollect = function(){
9944 if(!Roo.enableGarbageCollector){
9945 clearInterval(El.collectorThread);
9948 for(var eid in El.cache){
9949 var el = El.cache[eid], d = el.dom;
9950 // -------------------------------------------------------
9951 // Determining what is garbage:
9952 // -------------------------------------------------------
9954 // dom node is null, definitely garbage
9955 // -------------------------------------------------------
9957 // no parentNode == direct orphan, definitely garbage
9958 // -------------------------------------------------------
9959 // !d.offsetParent && !document.getElementById(eid)
9960 // display none elements have no offsetParent so we will
9961 // also try to look it up by it's id. However, check
9962 // offsetParent first so we don't do unneeded lookups.
9963 // This enables collection of elements that are not orphans
9964 // directly, but somewhere up the line they have an orphan
9966 // -------------------------------------------------------
9967 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9968 delete El.cache[eid];
9969 if(d && Roo.enableListenerCollection){
9975 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9979 El.Flyweight = function(dom){
9982 El.Flyweight.prototype = El.prototype;
9984 El._flyweights = {};
9986 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9987 * the dom node can be overwritten by other code.
9988 * @param {String/HTMLElement} el The dom node or id
9989 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9990 * prevent conflicts (e.g. internally Roo uses "_internal")
9992 * @return {Element} The shared Element object
9994 El.fly = function(el, named){
9995 named = named || '_global';
9996 el = Roo.getDom(el);
10000 if(!El._flyweights[named]){
10001 El._flyweights[named] = new El.Flyweight();
10003 El._flyweights[named].dom = el;
10004 return El._flyweights[named];
10008 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10009 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10010 * Shorthand of {@link Roo.Element#get}
10011 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10012 * @return {Element} The Element object
10018 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10019 * the dom node can be overwritten by other code.
10020 * Shorthand of {@link Roo.Element#fly}
10021 * @param {String/HTMLElement} el The dom node or id
10022 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10023 * prevent conflicts (e.g. internally Roo uses "_internal")
10025 * @return {Element} The shared Element object
10031 // speedy lookup for elements never to box adjust
10032 var noBoxAdjust = Roo.isStrict ? {
10035 input:1, select:1, textarea:1
10037 if(Roo.isIE || Roo.isGecko){
10038 noBoxAdjust['button'] = 1;
10042 Roo.EventManager.on(window, 'unload', function(){
10044 delete El._flyweights;
10052 Roo.Element.selectorFunction = Roo.DomQuery.select;
10055 Roo.Element.select = function(selector, unique, root){
10057 if(typeof selector == "string"){
10058 els = Roo.Element.selectorFunction(selector, root);
10059 }else if(selector.length !== undefined){
10062 throw "Invalid selector";
10064 if(unique === true){
10065 return new Roo.CompositeElement(els);
10067 return new Roo.CompositeElementLite(els);
10071 * Selects elements based on the passed CSS selector to enable working on them as 1.
10072 * @param {String/Array} selector The CSS selector or an array of elements
10073 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10074 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10075 * @return {CompositeElementLite/CompositeElement}
10079 Roo.select = Roo.Element.select;
10096 * Ext JS Library 1.1.1
10097 * Copyright(c) 2006-2007, Ext JS, LLC.
10099 * Originally Released Under LGPL - original licence link has changed is not relivant.
10102 * <script type="text/javascript">
10107 //Notifies Element that fx methods are available
10108 Roo.enableFx = true;
10112 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10113 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10114 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10115 * Element effects to work.</p><br/>
10117 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10118 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10119 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10120 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10121 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10122 * expected results and should be done with care.</p><br/>
10124 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10125 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10128 ----- -----------------------------
10129 tl The top left corner
10130 t The center of the top edge
10131 tr The top right corner
10132 l The center of the left edge
10133 r The center of the right edge
10134 bl The bottom left corner
10135 b The center of the bottom edge
10136 br The bottom right corner
10138 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10139 * below are common options that can be passed to any Fx method.</b>
10140 * @cfg {Function} callback A function called when the effect is finished
10141 * @cfg {Object} scope The scope of the effect function
10142 * @cfg {String} easing A valid Easing value for the effect
10143 * @cfg {String} afterCls A css class to apply after the effect
10144 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10145 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10146 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10147 * effects that end with the element being visually hidden, ignored otherwise)
10148 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10149 * a function which returns such a specification that will be applied to the Element after the effect finishes
10150 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10151 * @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
10152 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10156 * Slides the element into view. An anchor point can be optionally passed to set the point of
10157 * origin for the slide effect. This function automatically handles wrapping the element with
10158 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10161 // default: slide the element in from the top
10164 // custom: slide the element in from the right with a 2-second duration
10165 el.slideIn('r', { duration: 2 });
10167 // common config options shown with default values
10173 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10174 * @param {Object} options (optional) Object literal with any of the Fx config options
10175 * @return {Roo.Element} The Element
10177 slideIn : function(anchor, o){
10178 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10183 anchor = anchor || "t";
10185 // fix display to visibility
10188 // restore values after effect
10189 var r = this.getFxRestore();
10190 var b = this.getBox();
10191 // fixed size for slide
10195 var wrap = this.fxWrap(r.pos, o, "hidden");
10197 var st = this.dom.style;
10198 st.visibility = "visible";
10199 st.position = "absolute";
10201 // clear out temp styles after slide and unwrap
10202 var after = function(){
10203 el.fxUnwrap(wrap, r.pos, o);
10204 st.width = r.width;
10205 st.height = r.height;
10208 // time to calc the positions
10209 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10211 switch(anchor.toLowerCase()){
10213 wrap.setSize(b.width, 0);
10214 st.left = st.bottom = "0";
10218 wrap.setSize(0, b.height);
10219 st.right = st.top = "0";
10223 wrap.setSize(0, b.height);
10224 wrap.setX(b.right);
10225 st.left = st.top = "0";
10226 a = {width: bw, points: pt};
10229 wrap.setSize(b.width, 0);
10230 wrap.setY(b.bottom);
10231 st.left = st.top = "0";
10232 a = {height: bh, points: pt};
10235 wrap.setSize(0, 0);
10236 st.right = st.bottom = "0";
10237 a = {width: bw, height: bh};
10240 wrap.setSize(0, 0);
10241 wrap.setY(b.y+b.height);
10242 st.right = st.top = "0";
10243 a = {width: bw, height: bh, points: pt};
10246 wrap.setSize(0, 0);
10247 wrap.setXY([b.right, b.bottom]);
10248 st.left = st.top = "0";
10249 a = {width: bw, height: bh, points: pt};
10252 wrap.setSize(0, 0);
10253 wrap.setX(b.x+b.width);
10254 st.left = st.bottom = "0";
10255 a = {width: bw, height: bh, points: pt};
10258 this.dom.style.visibility = "visible";
10261 arguments.callee.anim = wrap.fxanim(a,
10271 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10272 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10273 * 'hidden') but block elements will still take up space in the document. The element must be removed
10274 * from the DOM using the 'remove' config option if desired. This function automatically handles
10275 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10278 // default: slide the element out to the top
10281 // custom: slide the element out to the right with a 2-second duration
10282 el.slideOut('r', { duration: 2 });
10284 // common config options shown with default values
10292 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10293 * @param {Object} options (optional) Object literal with any of the Fx config options
10294 * @return {Roo.Element} The Element
10296 slideOut : function(anchor, o){
10297 var el = this.getFxEl();
10300 el.queueFx(o, function(){
10302 anchor = anchor || "t";
10304 // restore values after effect
10305 var r = this.getFxRestore();
10307 var b = this.getBox();
10308 // fixed size for slide
10312 var wrap = this.fxWrap(r.pos, o, "visible");
10314 var st = this.dom.style;
10315 st.visibility = "visible";
10316 st.position = "absolute";
10320 var after = function(){
10322 el.setDisplayed(false);
10327 el.fxUnwrap(wrap, r.pos, o);
10329 st.width = r.width;
10330 st.height = r.height;
10335 var a, zero = {to: 0};
10336 switch(anchor.toLowerCase()){
10338 st.left = st.bottom = "0";
10339 a = {height: zero};
10342 st.right = st.top = "0";
10346 st.left = st.top = "0";
10347 a = {width: zero, points: {to:[b.right, b.y]}};
10350 st.left = st.top = "0";
10351 a = {height: zero, points: {to:[b.x, b.bottom]}};
10354 st.right = st.bottom = "0";
10355 a = {width: zero, height: zero};
10358 st.right = st.top = "0";
10359 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10362 st.left = st.top = "0";
10363 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10366 st.left = st.bottom = "0";
10367 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10371 arguments.callee.anim = wrap.fxanim(a,
10381 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10382 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10383 * The element must be removed from the DOM using the 'remove' config option if desired.
10389 // common config options shown with default values
10397 * @param {Object} options (optional) Object literal with any of the Fx config options
10398 * @return {Roo.Element} The Element
10400 puff : function(o){
10401 var el = this.getFxEl();
10404 el.queueFx(o, function(){
10405 this.clearOpacity();
10408 // restore values after effect
10409 var r = this.getFxRestore();
10410 var st = this.dom.style;
10412 var after = function(){
10414 el.setDisplayed(false);
10421 el.setPositioning(r.pos);
10422 st.width = r.width;
10423 st.height = r.height;
10428 var width = this.getWidth();
10429 var height = this.getHeight();
10431 arguments.callee.anim = this.fxanim({
10432 width : {to: this.adjustWidth(width * 2)},
10433 height : {to: this.adjustHeight(height * 2)},
10434 points : {by: [-(width * .5), -(height * .5)]},
10436 fontSize: {to:200, unit: "%"}
10447 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10448 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10449 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10455 // all config options shown with default values
10463 * @param {Object} options (optional) Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 switchOff : function(o){
10467 var el = this.getFxEl();
10470 el.queueFx(o, function(){
10471 this.clearOpacity();
10474 // restore values after effect
10475 var r = this.getFxRestore();
10476 var st = this.dom.style;
10478 var after = function(){
10480 el.setDisplayed(false);
10486 el.setPositioning(r.pos);
10487 st.width = r.width;
10488 st.height = r.height;
10493 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10494 this.clearOpacity();
10498 points:{by:[0, this.getHeight() * .5]}
10499 }, o, 'motion', 0.3, 'easeIn', after);
10500 }).defer(100, this);
10507 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10508 * changed using the "attr" config option) and then fading back to the original color. If no original
10509 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10512 // default: highlight background to yellow
10515 // custom: highlight foreground text to blue for 2 seconds
10516 el.highlight("0000ff", { attr: 'color', duration: 2 });
10518 // common config options shown with default values
10519 el.highlight("ffff9c", {
10520 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10521 endColor: (current color) or "ffffff",
10526 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10527 * @param {Object} options (optional) Object literal with any of the Fx config options
10528 * @return {Roo.Element} The Element
10530 highlight : function(color, o){
10531 var el = this.getFxEl();
10534 el.queueFx(o, function(){
10535 color = color || "ffff9c";
10536 attr = o.attr || "backgroundColor";
10538 this.clearOpacity();
10541 var origColor = this.getColor(attr);
10542 var restoreColor = this.dom.style[attr];
10543 endColor = (o.endColor || origColor) || "ffffff";
10545 var after = function(){
10546 el.dom.style[attr] = restoreColor;
10551 a[attr] = {from: color, to: endColor};
10552 arguments.callee.anim = this.fxanim(a,
10562 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10565 // default: a single light blue ripple
10568 // custom: 3 red ripples lasting 3 seconds total
10569 el.frame("ff0000", 3, { duration: 3 });
10571 // common config options shown with default values
10572 el.frame("C3DAF9", 1, {
10573 duration: 1 //duration of entire animation (not each individual ripple)
10574 // Note: Easing is not configurable and will be ignored if included
10577 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10578 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10579 * @param {Object} options (optional) Object literal with any of the Fx config options
10580 * @return {Roo.Element} The Element
10582 frame : function(color, count, o){
10583 var el = this.getFxEl();
10586 el.queueFx(o, function(){
10587 color = color || "#C3DAF9";
10588 if(color.length == 6){
10589 color = "#" + color;
10591 count = count || 1;
10592 duration = o.duration || 1;
10595 var b = this.getBox();
10596 var animFn = function(){
10597 var proxy = this.createProxy({
10600 visbility:"hidden",
10601 position:"absolute",
10602 "z-index":"35000", // yee haw
10603 border:"0px solid " + color
10606 var scale = Roo.isBorderBox ? 2 : 1;
10608 top:{from:b.y, to:b.y - 20},
10609 left:{from:b.x, to:b.x - 20},
10610 borderWidth:{from:0, to:10},
10611 opacity:{from:1, to:0},
10612 height:{from:b.height, to:(b.height + (20*scale))},
10613 width:{from:b.width, to:(b.width + (20*scale))}
10614 }, duration, function(){
10618 animFn.defer((duration/2)*1000, this);
10629 * Creates a pause before any subsequent queued effects begin. If there are
10630 * no effects queued after the pause it will have no effect.
10635 * @param {Number} seconds The length of time to pause (in seconds)
10636 * @return {Roo.Element} The Element
10638 pause : function(seconds){
10639 var el = this.getFxEl();
10642 el.queueFx(o, function(){
10643 setTimeout(function(){
10645 }, seconds * 1000);
10651 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10652 * using the "endOpacity" config option.
10655 // default: fade in from opacity 0 to 100%
10658 // custom: fade in from opacity 0 to 75% over 2 seconds
10659 el.fadeIn({ endOpacity: .75, duration: 2});
10661 // common config options shown with default values
10663 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10668 * @param {Object} options (optional) Object literal with any of the Fx config options
10669 * @return {Roo.Element} The Element
10671 fadeIn : function(o){
10672 var el = this.getFxEl();
10674 el.queueFx(o, function(){
10675 this.setOpacity(0);
10677 this.dom.style.visibility = 'visible';
10678 var to = o.endOpacity || 1;
10679 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10680 o, null, .5, "easeOut", function(){
10682 this.clearOpacity();
10691 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10692 * using the "endOpacity" config option.
10695 // default: fade out from the element's current opacity to 0
10698 // custom: fade out from the element's current opacity to 25% over 2 seconds
10699 el.fadeOut({ endOpacity: .25, duration: 2});
10701 // common config options shown with default values
10703 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10710 * @param {Object} options (optional) Object literal with any of the Fx config options
10711 * @return {Roo.Element} The Element
10713 fadeOut : function(o){
10714 var el = this.getFxEl();
10716 el.queueFx(o, function(){
10717 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10718 o, null, .5, "easeOut", function(){
10719 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10720 this.dom.style.display = "none";
10722 this.dom.style.visibility = "hidden";
10724 this.clearOpacity();
10732 * Animates the transition of an element's dimensions from a starting height/width
10733 * to an ending height/width.
10736 // change height and width to 100x100 pixels
10737 el.scale(100, 100);
10739 // common config options shown with default values. The height and width will default to
10740 // the element's existing values if passed as null.
10743 [element's height], {
10748 * @param {Number} width The new width (pass undefined to keep the original width)
10749 * @param {Number} height The new height (pass undefined to keep the original height)
10750 * @param {Object} options (optional) Object literal with any of the Fx config options
10751 * @return {Roo.Element} The Element
10753 scale : function(w, h, o){
10754 this.shift(Roo.apply({}, o, {
10762 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10763 * Any of these properties not specified in the config object will not be changed. This effect
10764 * requires that at least one new dimension, position or opacity setting must be passed in on
10765 * the config object in order for the function to have any effect.
10768 // slide the element horizontally to x position 200 while changing the height and opacity
10769 el.shift({ x: 200, height: 50, opacity: .8 });
10771 // common config options shown with default values.
10773 width: [element's width],
10774 height: [element's height],
10775 x: [element's x position],
10776 y: [element's y position],
10777 opacity: [element's opacity],
10782 * @param {Object} options Object literal with any of the Fx config options
10783 * @return {Roo.Element} The Element
10785 shift : function(o){
10786 var el = this.getFxEl();
10788 el.queueFx(o, function(){
10789 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10790 if(w !== undefined){
10791 a.width = {to: this.adjustWidth(w)};
10793 if(h !== undefined){
10794 a.height = {to: this.adjustHeight(h)};
10796 if(x !== undefined || y !== undefined){
10798 x !== undefined ? x : this.getX(),
10799 y !== undefined ? y : this.getY()
10802 if(op !== undefined){
10803 a.opacity = {to: op};
10805 if(o.xy !== undefined){
10806 a.points = {to: o.xy};
10808 arguments.callee.anim = this.fxanim(a,
10809 o, 'motion', .35, "easeOut", function(){
10817 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10818 * ending point of the effect.
10821 // default: slide the element downward while fading out
10824 // custom: slide the element out to the right with a 2-second duration
10825 el.ghost('r', { duration: 2 });
10827 // common config options shown with default values
10835 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10836 * @param {Object} options (optional) Object literal with any of the Fx config options
10837 * @return {Roo.Element} The Element
10839 ghost : function(anchor, o){
10840 var el = this.getFxEl();
10843 el.queueFx(o, function(){
10844 anchor = anchor || "b";
10846 // restore values after effect
10847 var r = this.getFxRestore();
10848 var w = this.getWidth(),
10849 h = this.getHeight();
10851 var st = this.dom.style;
10853 var after = function(){
10855 el.setDisplayed(false);
10861 el.setPositioning(r.pos);
10862 st.width = r.width;
10863 st.height = r.height;
10868 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10869 switch(anchor.toLowerCase()){
10896 arguments.callee.anim = this.fxanim(a,
10906 * Ensures that all effects queued after syncFx is called on the element are
10907 * run concurrently. This is the opposite of {@link #sequenceFx}.
10908 * @return {Roo.Element} The Element
10910 syncFx : function(){
10911 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10920 * Ensures that all effects queued after sequenceFx is called on the element are
10921 * run in sequence. This is the opposite of {@link #syncFx}.
10922 * @return {Roo.Element} The Element
10924 sequenceFx : function(){
10925 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10927 concurrent : false,
10934 nextFx : function(){
10935 var ef = this.fxQueue[0];
10942 * Returns true if the element has any effects actively running or queued, else returns false.
10943 * @return {Boolean} True if element has active effects, else false
10945 hasActiveFx : function(){
10946 return this.fxQueue && this.fxQueue[0];
10950 * Stops any running effects and clears the element's internal effects queue if it contains
10951 * any additional effects that haven't started yet.
10952 * @return {Roo.Element} The Element
10954 stopFx : function(){
10955 if(this.hasActiveFx()){
10956 var cur = this.fxQueue[0];
10957 if(cur && cur.anim && cur.anim.isAnimated()){
10958 this.fxQueue = [cur]; // clear out others
10959 cur.anim.stop(true);
10966 beforeFx : function(o){
10967 if(this.hasActiveFx() && !o.concurrent){
10978 * Returns true if the element is currently blocking so that no other effect can be queued
10979 * until this effect is finished, else returns false if blocking is not set. This is commonly
10980 * used to ensure that an effect initiated by a user action runs to completion prior to the
10981 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10982 * @return {Boolean} True if blocking, else false
10984 hasFxBlock : function(){
10985 var q = this.fxQueue;
10986 return q && q[0] && q[0].block;
10990 queueFx : function(o, fn){
10994 if(!this.hasFxBlock()){
10995 Roo.applyIf(o, this.fxDefaults);
10997 var run = this.beforeFx(o);
10998 fn.block = o.block;
10999 this.fxQueue.push(fn);
11011 fxWrap : function(pos, o, vis){
11013 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11016 wrapXY = this.getXY();
11018 var div = document.createElement("div");
11019 div.style.visibility = vis;
11020 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11021 wrap.setPositioning(pos);
11022 if(wrap.getStyle("position") == "static"){
11023 wrap.position("relative");
11025 this.clearPositioning('auto');
11027 wrap.dom.appendChild(this.dom);
11029 wrap.setXY(wrapXY);
11036 fxUnwrap : function(wrap, pos, o){
11037 this.clearPositioning();
11038 this.setPositioning(pos);
11040 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11046 getFxRestore : function(){
11047 var st = this.dom.style;
11048 return {pos: this.getPositioning(), width: st.width, height : st.height};
11052 afterFx : function(o){
11054 this.applyStyles(o.afterStyle);
11057 this.addClass(o.afterCls);
11059 if(o.remove === true){
11062 Roo.callback(o.callback, o.scope, [this]);
11064 this.fxQueue.shift();
11070 getFxEl : function(){ // support for composite element fx
11071 return Roo.get(this.dom);
11075 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11076 animType = animType || 'run';
11078 var anim = Roo.lib.Anim[animType](
11080 (opt.duration || defaultDur) || .35,
11081 (opt.easing || defaultEase) || 'easeOut',
11083 Roo.callback(cb, this);
11092 // backwords compat
11093 Roo.Fx.resize = Roo.Fx.scale;
11095 //When included, Roo.Fx is automatically applied to Element so that all basic
11096 //effects are available directly via the Element API
11097 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11099 * Ext JS Library 1.1.1
11100 * Copyright(c) 2006-2007, Ext JS, LLC.
11102 * Originally Released Under LGPL - original licence link has changed is not relivant.
11105 * <script type="text/javascript">
11110 * @class Roo.CompositeElement
11111 * Standard composite class. Creates a Roo.Element for every element in the collection.
11113 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11114 * actions will be performed on all the elements in this collection.</b>
11116 * All methods return <i>this</i> and can be chained.
11118 var els = Roo.select("#some-el div.some-class", true);
11119 // or select directly from an existing element
11120 var el = Roo.get('some-el');
11121 el.select('div.some-class', true);
11123 els.setWidth(100); // all elements become 100 width
11124 els.hide(true); // all elements fade out and hide
11126 els.setWidth(100).hide(true);
11129 Roo.CompositeElement = function(els){
11130 this.elements = [];
11131 this.addElements(els);
11133 Roo.CompositeElement.prototype = {
11135 addElements : function(els){
11139 if(typeof els == "string"){
11140 els = Roo.Element.selectorFunction(els);
11142 var yels = this.elements;
11143 var index = yels.length-1;
11144 for(var i = 0, len = els.length; i < len; i++) {
11145 yels[++index] = Roo.get(els[i]);
11151 * Clears this composite and adds the elements returned by the passed selector.
11152 * @param {String/Array} els A string CSS selector, an array of elements or an element
11153 * @return {CompositeElement} this
11155 fill : function(els){
11156 this.elements = [];
11162 * Filters this composite to only elements that match the passed selector.
11163 * @param {String} selector A string CSS selector
11164 * @param {Boolean} inverse return inverse filter (not matches)
11165 * @return {CompositeElement} this
11167 filter : function(selector, inverse){
11169 inverse = inverse || false;
11170 this.each(function(el){
11171 var match = inverse ? !el.is(selector) : el.is(selector);
11173 els[els.length] = el.dom;
11180 invoke : function(fn, args){
11181 var els = this.elements;
11182 for(var i = 0, len = els.length; i < len; i++) {
11183 Roo.Element.prototype[fn].apply(els[i], args);
11188 * Adds elements to this composite.
11189 * @param {String/Array} els A string CSS selector, an array of elements or an element
11190 * @return {CompositeElement} this
11192 add : function(els){
11193 if(typeof els == "string"){
11194 this.addElements(Roo.Element.selectorFunction(els));
11195 }else if(els.length !== undefined){
11196 this.addElements(els);
11198 this.addElements([els]);
11203 * Calls the passed function passing (el, this, index) for each element in this composite.
11204 * @param {Function} fn The function to call
11205 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11206 * @return {CompositeElement} this
11208 each : function(fn, scope){
11209 var els = this.elements;
11210 for(var i = 0, len = els.length; i < len; i++){
11211 if(fn.call(scope || els[i], els[i], this, i) === false) {
11219 * Returns the Element object at the specified index
11220 * @param {Number} index
11221 * @return {Roo.Element}
11223 item : function(index){
11224 return this.elements[index] || null;
11228 * Returns the first Element
11229 * @return {Roo.Element}
11231 first : function(){
11232 return this.item(0);
11236 * Returns the last Element
11237 * @return {Roo.Element}
11240 return this.item(this.elements.length-1);
11244 * Returns the number of elements in this composite
11247 getCount : function(){
11248 return this.elements.length;
11252 * Returns true if this composite contains the passed element
11255 contains : function(el){
11256 return this.indexOf(el) !== -1;
11260 * Returns true if this composite contains the passed element
11263 indexOf : function(el){
11264 return this.elements.indexOf(Roo.get(el));
11269 * Removes the specified element(s).
11270 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11271 * or an array of any of those.
11272 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11273 * @return {CompositeElement} this
11275 removeElement : function(el, removeDom){
11276 if(el instanceof Array){
11277 for(var i = 0, len = el.length; i < len; i++){
11278 this.removeElement(el[i]);
11282 var index = typeof el == 'number' ? el : this.indexOf(el);
11285 var d = this.elements[index];
11289 d.parentNode.removeChild(d);
11292 this.elements.splice(index, 1);
11298 * Replaces the specified element with the passed element.
11299 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11301 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11302 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11303 * @return {CompositeElement} this
11305 replaceElement : function(el, replacement, domReplace){
11306 var index = typeof el == 'number' ? el : this.indexOf(el);
11309 this.elements[index].replaceWith(replacement);
11311 this.elements.splice(index, 1, Roo.get(replacement))
11318 * Removes all elements.
11320 clear : function(){
11321 this.elements = [];
11325 Roo.CompositeElement.createCall = function(proto, fnName){
11326 if(!proto[fnName]){
11327 proto[fnName] = function(){
11328 return this.invoke(fnName, arguments);
11332 for(var fnName in Roo.Element.prototype){
11333 if(typeof Roo.Element.prototype[fnName] == "function"){
11334 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11340 * Ext JS Library 1.1.1
11341 * Copyright(c) 2006-2007, Ext JS, LLC.
11343 * Originally Released Under LGPL - original licence link has changed is not relivant.
11346 * <script type="text/javascript">
11350 * @class Roo.CompositeElementLite
11351 * @extends Roo.CompositeElement
11352 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11354 var els = Roo.select("#some-el div.some-class");
11355 // or select directly from an existing element
11356 var el = Roo.get('some-el');
11357 el.select('div.some-class');
11359 els.setWidth(100); // all elements become 100 width
11360 els.hide(true); // all elements fade out and hide
11362 els.setWidth(100).hide(true);
11363 </code></pre><br><br>
11364 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11365 * actions will be performed on all the elements in this collection.</b>
11367 Roo.CompositeElementLite = function(els){
11368 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11369 this.el = new Roo.Element.Flyweight();
11371 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11372 addElements : function(els){
11374 if(els instanceof Array){
11375 this.elements = this.elements.concat(els);
11377 var yels = this.elements;
11378 var index = yels.length-1;
11379 for(var i = 0, len = els.length; i < len; i++) {
11380 yels[++index] = els[i];
11386 invoke : function(fn, args){
11387 var els = this.elements;
11389 for(var i = 0, len = els.length; i < len; i++) {
11391 Roo.Element.prototype[fn].apply(el, args);
11396 * Returns a flyweight Element of the dom element object at the specified index
11397 * @param {Number} index
11398 * @return {Roo.Element}
11400 item : function(index){
11401 if(!this.elements[index]){
11404 this.el.dom = this.elements[index];
11408 // fixes scope with flyweight
11409 addListener : function(eventName, handler, scope, opt){
11410 var els = this.elements;
11411 for(var i = 0, len = els.length; i < len; i++) {
11412 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11418 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11419 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11420 * a reference to the dom node, use el.dom.</b>
11421 * @param {Function} fn The function to call
11422 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11423 * @return {CompositeElement} this
11425 each : function(fn, scope){
11426 var els = this.elements;
11428 for(var i = 0, len = els.length; i < len; i++){
11430 if(fn.call(scope || el, el, this, i) === false){
11437 indexOf : function(el){
11438 return this.elements.indexOf(Roo.getDom(el));
11441 replaceElement : function(el, replacement, domReplace){
11442 var index = typeof el == 'number' ? el : this.indexOf(el);
11444 replacement = Roo.getDom(replacement);
11446 var d = this.elements[index];
11447 d.parentNode.insertBefore(replacement, d);
11448 d.parentNode.removeChild(d);
11450 this.elements.splice(index, 1, replacement);
11455 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11459 * Ext JS Library 1.1.1
11460 * Copyright(c) 2006-2007, Ext JS, LLC.
11462 * Originally Released Under LGPL - original licence link has changed is not relivant.
11465 * <script type="text/javascript">
11471 * @class Roo.data.Connection
11472 * @extends Roo.util.Observable
11473 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11474 * either to a configured URL, or to a URL specified at request time.<br><br>
11476 * Requests made by this class are asynchronous, and will return immediately. No data from
11477 * the server will be available to the statement immediately following the {@link #request} call.
11478 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11480 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11481 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11482 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11483 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11484 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11485 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11486 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11487 * standard DOM methods.
11489 * @param {Object} config a configuration object.
11491 Roo.data.Connection = function(config){
11492 Roo.apply(this, config);
11495 * @event beforerequest
11496 * Fires before a network request is made to retrieve a data object.
11497 * @param {Connection} conn This Connection object.
11498 * @param {Object} options The options config object passed to the {@link #request} method.
11500 "beforerequest" : true,
11502 * @event requestcomplete
11503 * Fires if the request was successfully completed.
11504 * @param {Connection} conn This Connection object.
11505 * @param {Object} response The XHR object containing the response data.
11506 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11507 * @param {Object} options The options config object passed to the {@link #request} method.
11509 "requestcomplete" : true,
11511 * @event requestexception
11512 * Fires if an error HTTP status was returned from the server.
11513 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11514 * @param {Connection} conn This Connection object.
11515 * @param {Object} response The XHR object containing the response data.
11516 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11517 * @param {Object} options The options config object passed to the {@link #request} method.
11519 "requestexception" : true
11521 Roo.data.Connection.superclass.constructor.call(this);
11524 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11526 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11529 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11530 * extra parameters to each request made by this object. (defaults to undefined)
11533 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11534 * to each request made by this object. (defaults to undefined)
11537 * @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)
11540 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11544 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11550 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11553 disableCaching: true,
11556 * Sends an HTTP request to a remote server.
11557 * @param {Object} options An object which may contain the following properties:<ul>
11558 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11559 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11560 * request, a url encoded string or a function to call to get either.</li>
11561 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11562 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11563 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11564 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11565 * <li>options {Object} The parameter to the request call.</li>
11566 * <li>success {Boolean} True if the request succeeded.</li>
11567 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11569 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11570 * The callback is passed the following parameters:<ul>
11571 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11572 * <li>options {Object} The parameter to the request call.</li>
11574 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11575 * The callback is passed the following parameters:<ul>
11576 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11577 * <li>options {Object} The parameter to the request call.</li>
11579 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11580 * for the callback function. Defaults to the browser window.</li>
11581 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11582 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11583 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11584 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11585 * params for the post data. Any params will be appended to the URL.</li>
11586 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11588 * @return {Number} transactionId
11590 request : function(o){
11591 if(this.fireEvent("beforerequest", this, o) !== false){
11594 if(typeof p == "function"){
11595 p = p.call(o.scope||window, o);
11597 if(typeof p == "object"){
11598 p = Roo.urlEncode(o.params);
11600 if(this.extraParams){
11601 var extras = Roo.urlEncode(this.extraParams);
11602 p = p ? (p + '&' + extras) : extras;
11605 var url = o.url || this.url;
11606 if(typeof url == 'function'){
11607 url = url.call(o.scope||window, o);
11611 var form = Roo.getDom(o.form);
11612 url = url || form.action;
11614 var enctype = form.getAttribute("enctype");
11617 return this.doFormDataUpload(o,p,url);
11620 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11621 return this.doFormUpload(o, p, url);
11623 var f = Roo.lib.Ajax.serializeForm(form);
11624 p = p ? (p + '&' + f) : f;
11627 var hs = o.headers;
11628 if(this.defaultHeaders){
11629 hs = Roo.apply(hs || {}, this.defaultHeaders);
11636 success: this.handleResponse,
11637 failure: this.handleFailure,
11639 argument: {options: o},
11640 timeout : o.timeout || this.timeout
11643 var method = o.method||this.method||(p ? "POST" : "GET");
11645 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11646 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11649 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11653 }else if(this.autoAbort !== false){
11657 if((method == 'GET' && p) || o.xmlData){
11658 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11661 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11662 return this.transId;
11664 Roo.callback(o.callback, o.scope, [o, null, null]);
11670 * Determine whether this object has a request outstanding.
11671 * @param {Number} transactionId (Optional) defaults to the last transaction
11672 * @return {Boolean} True if there is an outstanding request.
11674 isLoading : function(transId){
11676 return Roo.lib.Ajax.isCallInProgress(transId);
11678 return this.transId ? true : false;
11683 * Aborts any outstanding request.
11684 * @param {Number} transactionId (Optional) defaults to the last transaction
11686 abort : function(transId){
11687 if(transId || this.isLoading()){
11688 Roo.lib.Ajax.abort(transId || this.transId);
11693 handleResponse : function(response){
11694 this.transId = false;
11695 var options = response.argument.options;
11696 response.argument = options ? options.argument : null;
11697 this.fireEvent("requestcomplete", this, response, options);
11698 Roo.callback(options.success, options.scope, [response, options]);
11699 Roo.callback(options.callback, options.scope, [options, true, response]);
11703 handleFailure : function(response, e){
11704 this.transId = false;
11705 var options = response.argument.options;
11706 response.argument = options ? options.argument : null;
11707 this.fireEvent("requestexception", this, response, options, e);
11708 Roo.callback(options.failure, options.scope, [response, options]);
11709 Roo.callback(options.callback, options.scope, [options, false, response]);
11713 doFormUpload : function(o, ps, url){
11715 var frame = document.createElement('iframe');
11718 frame.className = 'x-hidden';
11720 frame.src = Roo.SSL_SECURE_URL;
11722 document.body.appendChild(frame);
11725 document.frames[id].name = id;
11728 var form = Roo.getDom(o.form);
11730 form.method = 'POST';
11731 form.enctype = form.encoding = 'multipart/form-data';
11737 if(ps){ // add dynamic params
11739 ps = Roo.urlDecode(ps, false);
11741 if(ps.hasOwnProperty(k)){
11742 hd = document.createElement('input');
11743 hd.type = 'hidden';
11746 form.appendChild(hd);
11753 var r = { // bogus response object
11758 r.argument = o ? o.argument : null;
11763 doc = frame.contentWindow.document;
11765 doc = (frame.contentDocument || window.frames[id].document);
11767 if(doc && doc.body){
11768 r.responseText = doc.body.innerHTML;
11770 if(doc && doc.XMLDocument){
11771 r.responseXML = doc.XMLDocument;
11773 r.responseXML = doc;
11780 Roo.EventManager.removeListener(frame, 'load', cb, this);
11782 this.fireEvent("requestcomplete", this, r, o);
11783 Roo.callback(o.success, o.scope, [r, o]);
11784 Roo.callback(o.callback, o.scope, [o, true, r]);
11786 setTimeout(function(){document.body.removeChild(frame);}, 100);
11789 Roo.EventManager.on(frame, 'load', cb, this);
11792 if(hiddens){ // remove dynamic params
11793 for(var i = 0, len = hiddens.length; i < len; i++){
11794 form.removeChild(hiddens[i]);
11798 // this is a 'formdata version???'
11801 doFormDataUpload : function(o, ps, url)
11803 var form = Roo.getDom(o.form);
11804 form.enctype = form.encoding = 'multipart/form-data';
11805 var formData = o.formData === true ? new FormData(form) : o.formData;
11808 success: this.handleResponse,
11809 failure: this.handleFailure,
11811 argument: {options: o},
11812 timeout : o.timeout || this.timeout
11815 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11819 }else if(this.autoAbort !== false){
11823 //Roo.lib.Ajax.defaultPostHeader = null;
11824 Roo.lib.Ajax.useDefaultHeader = false;
11825 this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
11826 Roo.lib.Ajax.useDefaultHeader = true;
11834 * Ext JS Library 1.1.1
11835 * Copyright(c) 2006-2007, Ext JS, LLC.
11837 * Originally Released Under LGPL - original licence link has changed is not relivant.
11840 * <script type="text/javascript">
11844 * Global Ajax request class.
11847 * @extends Roo.data.Connection
11850 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11851 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11852 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11853 * @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)
11854 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11855 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11856 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11858 Roo.Ajax = new Roo.data.Connection({
11867 * Serialize the passed form into a url encoded string
11869 * @param {String/HTMLElement} form
11872 serializeForm : function(form){
11873 return Roo.lib.Ajax.serializeForm(form);
11877 * Ext JS Library 1.1.1
11878 * Copyright(c) 2006-2007, Ext JS, LLC.
11880 * Originally Released Under LGPL - original licence link has changed is not relivant.
11883 * <script type="text/javascript">
11888 * @class Roo.UpdateManager
11889 * @extends Roo.util.Observable
11890 * Provides AJAX-style update for Element object.<br><br>
11893 * // Get it from a Roo.Element object
11894 * var el = Roo.get("foo");
11895 * var mgr = el.getUpdateManager();
11896 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11898 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11900 * // or directly (returns the same UpdateManager instance)
11901 * var mgr = new Roo.UpdateManager("myElementId");
11902 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11903 * mgr.on("update", myFcnNeedsToKnow);
11905 // short handed call directly from the element object
11906 Roo.get("foo").load({
11910 text: "Loading Foo..."
11914 * Create new UpdateManager directly.
11915 * @param {String/HTMLElement/Roo.Element} el The element to update
11916 * @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).
11918 Roo.UpdateManager = function(el, forceNew){
11920 if(!forceNew && el.updateManager){
11921 return el.updateManager;
11924 * The Element object
11925 * @type Roo.Element
11929 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11932 this.defaultUrl = null;
11936 * @event beforeupdate
11937 * Fired before an update is made, return false from your handler and the update is cancelled.
11938 * @param {Roo.Element} el
11939 * @param {String/Object/Function} url
11940 * @param {String/Object} params
11942 "beforeupdate": true,
11945 * Fired after successful update is made.
11946 * @param {Roo.Element} el
11947 * @param {Object} oResponseObject The response Object
11952 * Fired on update failure.
11953 * @param {Roo.Element} el
11954 * @param {Object} oResponseObject The response Object
11958 var d = Roo.UpdateManager.defaults;
11960 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11963 this.sslBlankUrl = d.sslBlankUrl;
11965 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11968 this.disableCaching = d.disableCaching;
11970 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11973 this.indicatorText = d.indicatorText;
11975 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11978 this.showLoadIndicator = d.showLoadIndicator;
11980 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11983 this.timeout = d.timeout;
11986 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11989 this.loadScripts = d.loadScripts;
11992 * Transaction object of current executing transaction
11994 this.transaction = null;
11999 this.autoRefreshProcId = null;
12001 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12004 this.refreshDelegate = this.refresh.createDelegate(this);
12006 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12009 this.updateDelegate = this.update.createDelegate(this);
12011 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12014 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12018 this.successDelegate = this.processSuccess.createDelegate(this);
12022 this.failureDelegate = this.processFailure.createDelegate(this);
12024 if(!this.renderer){
12026 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12028 this.renderer = new Roo.UpdateManager.BasicRenderer();
12031 Roo.UpdateManager.superclass.constructor.call(this);
12034 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12036 * Get the Element this UpdateManager is bound to
12037 * @return {Roo.Element} The element
12039 getEl : function(){
12043 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12044 * @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:
12047 url: "your-url.php",<br/>
12048 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12049 callback: yourFunction,<br/>
12050 scope: yourObject, //(optional scope) <br/>
12051 discardUrl: false, <br/>
12052 nocache: false,<br/>
12053 text: "Loading...",<br/>
12055 scripts: false<br/>
12058 * The only required property is url. The optional properties nocache, text and scripts
12059 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12060 * @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}
12061 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12062 * @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.
12064 update : function(url, params, callback, discardUrl){
12065 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12066 var method = this.method,
12068 if(typeof url == "object"){ // must be config object
12071 params = params || cfg.params;
12072 callback = callback || cfg.callback;
12073 discardUrl = discardUrl || cfg.discardUrl;
12074 if(callback && cfg.scope){
12075 callback = callback.createDelegate(cfg.scope);
12077 if(typeof cfg.method != "undefined"){method = cfg.method;};
12078 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12079 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12080 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12081 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12083 this.showLoading();
12085 this.defaultUrl = url;
12087 if(typeof url == "function"){
12088 url = url.call(this);
12091 method = method || (params ? "POST" : "GET");
12092 if(method == "GET"){
12093 url = this.prepareUrl(url);
12096 var o = Roo.apply(cfg ||{}, {
12099 success: this.successDelegate,
12100 failure: this.failureDelegate,
12101 callback: undefined,
12102 timeout: (this.timeout*1000),
12103 argument: {"url": url, "form": null, "callback": callback, "params": params}
12105 Roo.log("updated manager called with timeout of " + o.timeout);
12106 this.transaction = Roo.Ajax.request(o);
12111 * 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.
12112 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12113 * @param {String/HTMLElement} form The form Id or form element
12114 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12115 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12116 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12118 formUpdate : function(form, url, reset, callback){
12119 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12120 if(typeof url == "function"){
12121 url = url.call(this);
12123 form = Roo.getDom(form);
12124 this.transaction = Roo.Ajax.request({
12127 success: this.successDelegate,
12128 failure: this.failureDelegate,
12129 timeout: (this.timeout*1000),
12130 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12132 this.showLoading.defer(1, this);
12137 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12138 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12140 refresh : function(callback){
12141 if(this.defaultUrl == null){
12144 this.update(this.defaultUrl, null, callback, true);
12148 * Set this element to auto refresh.
12149 * @param {Number} interval How often to update (in seconds).
12150 * @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)
12151 * @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}
12152 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12153 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12155 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12157 this.update(url || this.defaultUrl, params, callback, true);
12159 if(this.autoRefreshProcId){
12160 clearInterval(this.autoRefreshProcId);
12162 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12166 * Stop auto refresh on this element.
12168 stopAutoRefresh : function(){
12169 if(this.autoRefreshProcId){
12170 clearInterval(this.autoRefreshProcId);
12171 delete this.autoRefreshProcId;
12175 isAutoRefreshing : function(){
12176 return this.autoRefreshProcId ? true : false;
12179 * Called to update the element to "Loading" state. Override to perform custom action.
12181 showLoading : function(){
12182 if(this.showLoadIndicator){
12183 this.el.update(this.indicatorText);
12188 * Adds unique parameter to query string if disableCaching = true
12191 prepareUrl : function(url){
12192 if(this.disableCaching){
12193 var append = "_dc=" + (new Date().getTime());
12194 if(url.indexOf("?") !== -1){
12195 url += "&" + append;
12197 url += "?" + append;
12206 processSuccess : function(response){
12207 this.transaction = null;
12208 if(response.argument.form && response.argument.reset){
12209 try{ // put in try/catch since some older FF releases had problems with this
12210 response.argument.form.reset();
12213 if(this.loadScripts){
12214 this.renderer.render(this.el, response, this,
12215 this.updateComplete.createDelegate(this, [response]));
12217 this.renderer.render(this.el, response, this);
12218 this.updateComplete(response);
12222 updateComplete : function(response){
12223 this.fireEvent("update", this.el, response);
12224 if(typeof response.argument.callback == "function"){
12225 response.argument.callback(this.el, true, response);
12232 processFailure : function(response){
12233 this.transaction = null;
12234 this.fireEvent("failure", this.el, response);
12235 if(typeof response.argument.callback == "function"){
12236 response.argument.callback(this.el, false, response);
12241 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12242 * @param {Object} renderer The object implementing the render() method
12244 setRenderer : function(renderer){
12245 this.renderer = renderer;
12248 getRenderer : function(){
12249 return this.renderer;
12253 * Set the defaultUrl used for updates
12254 * @param {String/Function} defaultUrl The url or a function to call to get the url
12256 setDefaultUrl : function(defaultUrl){
12257 this.defaultUrl = defaultUrl;
12261 * Aborts the executing transaction
12263 abort : function(){
12264 if(this.transaction){
12265 Roo.Ajax.abort(this.transaction);
12270 * Returns true if an update is in progress
12271 * @return {Boolean}
12273 isUpdating : function(){
12274 if(this.transaction){
12275 return Roo.Ajax.isLoading(this.transaction);
12282 * @class Roo.UpdateManager.defaults
12283 * @static (not really - but it helps the doc tool)
12284 * The defaults collection enables customizing the default properties of UpdateManager
12286 Roo.UpdateManager.defaults = {
12288 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12294 * True to process scripts by default (Defaults to false).
12297 loadScripts : false,
12300 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12303 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12305 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12308 disableCaching : false,
12310 * Whether to show indicatorText when loading (Defaults to true).
12313 showLoadIndicator : true,
12315 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12318 indicatorText : '<div class="loading-indicator">Loading...</div>'
12322 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12324 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12325 * @param {String/HTMLElement/Roo.Element} el The element to update
12326 * @param {String} url The url
12327 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12328 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12331 * @member Roo.UpdateManager
12333 Roo.UpdateManager.updateElement = function(el, url, params, options){
12334 var um = Roo.get(el, true).getUpdateManager();
12335 Roo.apply(um, options);
12336 um.update(url, params, options ? options.callback : null);
12338 // alias for backwards compat
12339 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12341 * @class Roo.UpdateManager.BasicRenderer
12342 * Default Content renderer. Updates the elements innerHTML with the responseText.
12344 Roo.UpdateManager.BasicRenderer = function(){};
12346 Roo.UpdateManager.BasicRenderer.prototype = {
12348 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12349 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12350 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12351 * @param {Roo.Element} el The element being rendered
12352 * @param {Object} response The YUI Connect response object
12353 * @param {UpdateManager} updateManager The calling update manager
12354 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12356 render : function(el, response, updateManager, callback){
12357 el.update(response.responseText, updateManager.loadScripts, callback);
12363 * (c)) Alan Knowles
12369 * @class Roo.DomTemplate
12370 * @extends Roo.Template
12371 * An effort at a dom based template engine..
12373 * Similar to XTemplate, except it uses dom parsing to create the template..
12375 * Supported features:
12380 {a_variable} - output encoded.
12381 {a_variable.format:("Y-m-d")} - call a method on the variable
12382 {a_variable:raw} - unencoded output
12383 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12384 {a_variable:this.method_on_template(...)} - call a method on the template object.
12389 <div roo-for="a_variable or condition.."></div>
12390 <div roo-if="a_variable or condition"></div>
12391 <div roo-exec="some javascript"></div>
12392 <div roo-name="named_template"></div>
12397 Roo.DomTemplate = function()
12399 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12406 Roo.extend(Roo.DomTemplate, Roo.Template, {
12408 * id counter for sub templates.
12412 * flag to indicate if dom parser is inside a pre,
12413 * it will strip whitespace if not.
12418 * The various sub templates
12426 * basic tag replacing syntax
12429 * // you can fake an object call by doing this
12433 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12434 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12436 iterChild : function (node, method) {
12438 var oldPre = this.inPre;
12439 if (node.tagName == 'PRE') {
12442 for( var i = 0; i < node.childNodes.length; i++) {
12443 method.call(this, node.childNodes[i]);
12445 this.inPre = oldPre;
12451 * compile the template
12453 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12456 compile: function()
12460 // covert the html into DOM...
12464 doc = document.implementation.createHTMLDocument("");
12465 doc.documentElement.innerHTML = this.html ;
12466 div = doc.documentElement;
12468 // old IE... - nasty -- it causes all sorts of issues.. with
12469 // images getting pulled from server..
12470 div = document.createElement('div');
12471 div.innerHTML = this.html;
12473 //doc.documentElement.innerHTML = htmlBody
12479 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12481 var tpls = this.tpls;
12483 // create a top level template from the snippet..
12485 //Roo.log(div.innerHTML);
12492 body : div.innerHTML,
12505 Roo.each(tpls, function(tp){
12506 this.compileTpl(tp);
12507 this.tpls[tp.id] = tp;
12510 this.master = tpls[0];
12516 compileNode : function(node, istop) {
12521 // skip anything not a tag..
12522 if (node.nodeType != 1) {
12523 if (node.nodeType == 3 && !this.inPre) {
12524 // reduce white space..
12525 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12548 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12549 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12550 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12551 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12557 // just itterate children..
12558 this.iterChild(node,this.compileNode);
12561 tpl.uid = this.id++;
12562 tpl.value = node.getAttribute('roo-' + tpl.attr);
12563 node.removeAttribute('roo-'+ tpl.attr);
12564 if (tpl.attr != 'name') {
12565 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12566 node.parentNode.replaceChild(placeholder, node);
12569 var placeholder = document.createElement('span');
12570 placeholder.className = 'roo-tpl-' + tpl.value;
12571 node.parentNode.replaceChild(placeholder, node);
12574 // parent now sees '{domtplXXXX}
12575 this.iterChild(node,this.compileNode);
12577 // we should now have node body...
12578 var div = document.createElement('div');
12579 div.appendChild(node);
12581 // this has the unfortunate side effect of converting tagged attributes
12582 // eg. href="{...}" into %7C...%7D
12583 // this has been fixed by searching for those combo's although it's a bit hacky..
12586 tpl.body = div.innerHTML;
12593 switch (tpl.value) {
12594 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12595 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12596 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12601 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12605 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12609 tpl.id = tpl.value; // replace non characters???
12615 this.tpls.push(tpl);
12625 * Compile a segment of the template into a 'sub-template'
12631 compileTpl : function(tpl)
12633 var fm = Roo.util.Format;
12634 var useF = this.disableFormats !== true;
12636 var sep = Roo.isGecko ? "+\n" : ",\n";
12638 var undef = function(str) {
12639 Roo.debug && Roo.log("Property not found :" + str);
12643 //Roo.log(tpl.body);
12647 var fn = function(m, lbrace, name, format, args)
12650 //Roo.log(arguments);
12651 args = args ? args.replace(/\\'/g,"'") : args;
12652 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12653 if (typeof(format) == 'undefined') {
12654 format = 'htmlEncode';
12656 if (format == 'raw' ) {
12660 if(name.substr(0, 6) == 'domtpl'){
12661 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12664 // build an array of options to determine if value is undefined..
12666 // basically get 'xxxx.yyyy' then do
12667 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12668 // (function () { Roo.log("Property not found"); return ''; })() :
12673 Roo.each(name.split('.'), function(st) {
12674 lookfor += (lookfor.length ? '.': '') + st;
12675 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12678 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12681 if(format && useF){
12683 args = args ? ',' + args : "";
12685 if(format.substr(0, 5) != "this."){
12686 format = "fm." + format + '(';
12688 format = 'this.call("'+ format.substr(5) + '", ';
12692 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12695 if (args && args.length) {
12696 // called with xxyx.yuu:(test,test)
12698 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12700 // raw.. - :raw modifier..
12701 return "'"+ sep + udef_st + name + ")"+sep+"'";
12705 // branched to use + in gecko and [].join() in others
12707 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12708 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12711 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12712 body.push(tpl.body.replace(/(\r\n|\n)/g,
12713 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12714 body.push("'].join('');};};");
12715 body = body.join('');
12718 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12720 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12727 * same as applyTemplate, except it's done to one of the subTemplates
12728 * when using named templates, you can do:
12730 * var str = pl.applySubTemplate('your-name', values);
12733 * @param {Number} id of the template
12734 * @param {Object} values to apply to template
12735 * @param {Object} parent (normaly the instance of this object)
12737 applySubTemplate : function(id, values, parent)
12741 var t = this.tpls[id];
12745 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12746 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12750 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12757 if(t.execCall && t.execCall.call(this, values, parent)){
12761 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12767 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12768 parent = t.target ? values : parent;
12769 if(t.forCall && vs instanceof Array){
12771 for(var i = 0, len = vs.length; i < len; i++){
12773 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12775 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12777 //Roo.log(t.compiled);
12781 return buf.join('');
12784 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12789 return t.compiled.call(this, vs, parent);
12791 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12793 //Roo.log(t.compiled);
12801 applyTemplate : function(values){
12802 return this.master.compiled.call(this, values, {});
12803 //var s = this.subs;
12806 apply : function(){
12807 return this.applyTemplate.apply(this, arguments);
12812 Roo.DomTemplate.from = function(el){
12813 el = Roo.getDom(el);
12814 return new Roo.Domtemplate(el.value || el.innerHTML);
12817 * Ext JS Library 1.1.1
12818 * Copyright(c) 2006-2007, Ext JS, LLC.
12820 * Originally Released Under LGPL - original licence link has changed is not relivant.
12823 * <script type="text/javascript">
12827 * @class Roo.util.DelayedTask
12828 * Provides a convenient method of performing setTimeout where a new
12829 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12830 * You can use this class to buffer
12831 * the keypress events for a certain number of milliseconds, and perform only if they stop
12832 * for that amount of time.
12833 * @constructor The parameters to this constructor serve as defaults and are not required.
12834 * @param {Function} fn (optional) The default function to timeout
12835 * @param {Object} scope (optional) The default scope of that timeout
12836 * @param {Array} args (optional) The default Array of arguments
12838 Roo.util.DelayedTask = function(fn, scope, args){
12839 var id = null, d, t;
12841 var call = function(){
12842 var now = new Date().getTime();
12846 fn.apply(scope, args || []);
12850 * Cancels any pending timeout and queues a new one
12851 * @param {Number} delay The milliseconds to delay
12852 * @param {Function} newFn (optional) Overrides function passed to constructor
12853 * @param {Object} newScope (optional) Overrides scope passed to constructor
12854 * @param {Array} newArgs (optional) Overrides args passed to constructor
12856 this.delay = function(delay, newFn, newScope, newArgs){
12857 if(id && delay != d){
12861 t = new Date().getTime();
12863 scope = newScope || scope;
12864 args = newArgs || args;
12866 id = setInterval(call, d);
12871 * Cancel the last queued timeout
12873 this.cancel = function(){
12881 * Ext JS Library 1.1.1
12882 * Copyright(c) 2006-2007, Ext JS, LLC.
12884 * Originally Released Under LGPL - original licence link has changed is not relivant.
12887 * <script type="text/javascript">
12891 Roo.util.TaskRunner = function(interval){
12892 interval = interval || 10;
12893 var tasks = [], removeQueue = [];
12895 var running = false;
12897 var stopThread = function(){
12903 var startThread = function(){
12906 id = setInterval(runTasks, interval);
12910 var removeTask = function(task){
12911 removeQueue.push(task);
12917 var runTasks = function(){
12918 if(removeQueue.length > 0){
12919 for(var i = 0, len = removeQueue.length; i < len; i++){
12920 tasks.remove(removeQueue[i]);
12923 if(tasks.length < 1){
12928 var now = new Date().getTime();
12929 for(var i = 0, len = tasks.length; i < len; ++i){
12931 var itime = now - t.taskRunTime;
12932 if(t.interval <= itime){
12933 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12934 t.taskRunTime = now;
12935 if(rt === false || t.taskRunCount === t.repeat){
12940 if(t.duration && t.duration <= (now - t.taskStartTime)){
12947 * Queues a new task.
12948 * @param {Object} task
12950 this.start = function(task){
12952 task.taskStartTime = new Date().getTime();
12953 task.taskRunTime = 0;
12954 task.taskRunCount = 0;
12959 this.stop = function(task){
12964 this.stopAll = function(){
12966 for(var i = 0, len = tasks.length; i < len; i++){
12967 if(tasks[i].onStop){
12976 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12978 * Ext JS Library 1.1.1
12979 * Copyright(c) 2006-2007, Ext JS, LLC.
12981 * Originally Released Under LGPL - original licence link has changed is not relivant.
12984 * <script type="text/javascript">
12989 * @class Roo.util.MixedCollection
12990 * @extends Roo.util.Observable
12991 * A Collection class that maintains both numeric indexes and keys and exposes events.
12993 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12994 * collection (defaults to false)
12995 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12996 * and return the key value for that item. This is used when available to look up the key on items that
12997 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12998 * equivalent to providing an implementation for the {@link #getKey} method.
13000 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13008 * Fires when the collection is cleared.
13013 * Fires when an item is added to the collection.
13014 * @param {Number} index The index at which the item was added.
13015 * @param {Object} o The item added.
13016 * @param {String} key The key associated with the added item.
13021 * Fires when an item is replaced in the collection.
13022 * @param {String} key he key associated with the new added.
13023 * @param {Object} old The item being replaced.
13024 * @param {Object} new The new item.
13029 * Fires when an item is removed from the collection.
13030 * @param {Object} o The item being removed.
13031 * @param {String} key (optional) The key associated with the removed item.
13036 this.allowFunctions = allowFunctions === true;
13038 this.getKey = keyFn;
13040 Roo.util.MixedCollection.superclass.constructor.call(this);
13043 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13044 allowFunctions : false,
13047 * Adds an item to the collection.
13048 * @param {String} key The key to associate with the item
13049 * @param {Object} o The item to add.
13050 * @return {Object} The item added.
13052 add : function(key, o){
13053 if(arguments.length == 1){
13055 key = this.getKey(o);
13057 if(typeof key == "undefined" || key === null){
13059 this.items.push(o);
13060 this.keys.push(null);
13062 var old = this.map[key];
13064 return this.replace(key, o);
13067 this.items.push(o);
13069 this.keys.push(key);
13071 this.fireEvent("add", this.length-1, o, key);
13076 * MixedCollection has a generic way to fetch keys if you implement getKey.
13079 var mc = new Roo.util.MixedCollection();
13080 mc.add(someEl.dom.id, someEl);
13081 mc.add(otherEl.dom.id, otherEl);
13085 var mc = new Roo.util.MixedCollection();
13086 mc.getKey = function(el){
13092 // or via the constructor
13093 var mc = new Roo.util.MixedCollection(false, function(el){
13099 * @param o {Object} The item for which to find the key.
13100 * @return {Object} The key for the passed item.
13102 getKey : function(o){
13107 * Replaces an item in the collection.
13108 * @param {String} key The key associated with the item to replace, or the item to replace.
13109 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13110 * @return {Object} The new item.
13112 replace : function(key, o){
13113 if(arguments.length == 1){
13115 key = this.getKey(o);
13117 var old = this.item(key);
13118 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13119 return this.add(key, o);
13121 var index = this.indexOfKey(key);
13122 this.items[index] = o;
13124 this.fireEvent("replace", key, old, o);
13129 * Adds all elements of an Array or an Object to the collection.
13130 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13131 * an Array of values, each of which are added to the collection.
13133 addAll : function(objs){
13134 if(arguments.length > 1 || objs instanceof Array){
13135 var args = arguments.length > 1 ? arguments : objs;
13136 for(var i = 0, len = args.length; i < len; i++){
13140 for(var key in objs){
13141 if(this.allowFunctions || typeof objs[key] != "function"){
13142 this.add(key, objs[key]);
13149 * Executes the specified function once for every item in the collection, passing each
13150 * item as the first and only parameter. returning false from the function will stop the iteration.
13151 * @param {Function} fn The function to execute for each item.
13152 * @param {Object} scope (optional) The scope in which to execute the function.
13154 each : function(fn, scope){
13155 var items = [].concat(this.items); // each safe for removal
13156 for(var i = 0, len = items.length; i < len; i++){
13157 if(fn.call(scope || items[i], items[i], i, len) === false){
13164 * Executes the specified function once for every key in the collection, passing each
13165 * key, and its associated item as the first two parameters.
13166 * @param {Function} fn The function to execute for each item.
13167 * @param {Object} scope (optional) The scope in which to execute the function.
13169 eachKey : function(fn, scope){
13170 for(var i = 0, len = this.keys.length; i < len; i++){
13171 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13176 * Returns the first item in the collection which elicits a true return value from the
13177 * passed selection function.
13178 * @param {Function} fn The selection function to execute for each item.
13179 * @param {Object} scope (optional) The scope in which to execute the function.
13180 * @return {Object} The first item in the collection which returned true from the selection function.
13182 find : function(fn, scope){
13183 for(var i = 0, len = this.items.length; i < len; i++){
13184 if(fn.call(scope || window, this.items[i], this.keys[i])){
13185 return this.items[i];
13192 * Inserts an item at the specified index in the collection.
13193 * @param {Number} index The index to insert the item at.
13194 * @param {String} key The key to associate with the new item, or the item itself.
13195 * @param {Object} o (optional) If the second parameter was a key, the new item.
13196 * @return {Object} The item inserted.
13198 insert : function(index, key, o){
13199 if(arguments.length == 2){
13201 key = this.getKey(o);
13203 if(index >= this.length){
13204 return this.add(key, o);
13207 this.items.splice(index, 0, o);
13208 if(typeof key != "undefined" && key != null){
13211 this.keys.splice(index, 0, key);
13212 this.fireEvent("add", index, o, key);
13217 * Removed an item from the collection.
13218 * @param {Object} o The item to remove.
13219 * @return {Object} The item removed.
13221 remove : function(o){
13222 return this.removeAt(this.indexOf(o));
13226 * Remove an item from a specified index in the collection.
13227 * @param {Number} index The index within the collection of the item to remove.
13229 removeAt : function(index){
13230 if(index < this.length && index >= 0){
13232 var o = this.items[index];
13233 this.items.splice(index, 1);
13234 var key = this.keys[index];
13235 if(typeof key != "undefined"){
13236 delete this.map[key];
13238 this.keys.splice(index, 1);
13239 this.fireEvent("remove", o, key);
13244 * Removed an item associated with the passed key fom the collection.
13245 * @param {String} key The key of the item to remove.
13247 removeKey : function(key){
13248 return this.removeAt(this.indexOfKey(key));
13252 * Returns the number of items in the collection.
13253 * @return {Number} the number of items in the collection.
13255 getCount : function(){
13256 return this.length;
13260 * Returns index within the collection of the passed Object.
13261 * @param {Object} o The item to find the index of.
13262 * @return {Number} index of the item.
13264 indexOf : function(o){
13265 if(!this.items.indexOf){
13266 for(var i = 0, len = this.items.length; i < len; i++){
13267 if(this.items[i] == o) {
13273 return this.items.indexOf(o);
13278 * Returns index within the collection of the passed key.
13279 * @param {String} key The key to find the index of.
13280 * @return {Number} index of the key.
13282 indexOfKey : function(key){
13283 if(!this.keys.indexOf){
13284 for(var i = 0, len = this.keys.length; i < len; i++){
13285 if(this.keys[i] == key) {
13291 return this.keys.indexOf(key);
13296 * Returns the item associated with the passed key OR index. Key has priority over index.
13297 * @param {String/Number} key The key or index of the item.
13298 * @return {Object} The item associated with the passed key.
13300 item : function(key){
13301 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13302 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13306 * Returns the item at the specified index.
13307 * @param {Number} index The index of the item.
13310 itemAt : function(index){
13311 return this.items[index];
13315 * Returns the item associated with the passed key.
13316 * @param {String/Number} key The key of the item.
13317 * @return {Object} The item associated with the passed key.
13319 key : function(key){
13320 return this.map[key];
13324 * Returns true if the collection contains the passed Object as an item.
13325 * @param {Object} o The Object to look for in the collection.
13326 * @return {Boolean} True if the collection contains the Object as an item.
13328 contains : function(o){
13329 return this.indexOf(o) != -1;
13333 * Returns true if the collection contains the passed Object as a key.
13334 * @param {String} key The key to look for in the collection.
13335 * @return {Boolean} True if the collection contains the Object as a key.
13337 containsKey : function(key){
13338 return typeof this.map[key] != "undefined";
13342 * Removes all items from the collection.
13344 clear : function(){
13349 this.fireEvent("clear");
13353 * Returns the first item in the collection.
13354 * @return {Object} the first item in the collection..
13356 first : function(){
13357 return this.items[0];
13361 * Returns the last item in the collection.
13362 * @return {Object} the last item in the collection..
13365 return this.items[this.length-1];
13368 _sort : function(property, dir, fn){
13369 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13370 fn = fn || function(a, b){
13373 var c = [], k = this.keys, items = this.items;
13374 for(var i = 0, len = items.length; i < len; i++){
13375 c[c.length] = {key: k[i], value: items[i], index: i};
13377 c.sort(function(a, b){
13378 var v = fn(a[property], b[property]) * dsc;
13380 v = (a.index < b.index ? -1 : 1);
13384 for(var i = 0, len = c.length; i < len; i++){
13385 items[i] = c[i].value;
13388 this.fireEvent("sort", this);
13392 * Sorts this collection with the passed comparison function
13393 * @param {String} direction (optional) "ASC" or "DESC"
13394 * @param {Function} fn (optional) comparison function
13396 sort : function(dir, fn){
13397 this._sort("value", dir, fn);
13401 * Sorts this collection by keys
13402 * @param {String} direction (optional) "ASC" or "DESC"
13403 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13405 keySort : function(dir, fn){
13406 this._sort("key", dir, fn || function(a, b){
13407 return String(a).toUpperCase()-String(b).toUpperCase();
13412 * Returns a range of items in this collection
13413 * @param {Number} startIndex (optional) defaults to 0
13414 * @param {Number} endIndex (optional) default to the last item
13415 * @return {Array} An array of items
13417 getRange : function(start, end){
13418 var items = this.items;
13419 if(items.length < 1){
13422 start = start || 0;
13423 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13426 for(var i = start; i <= end; i++) {
13427 r[r.length] = items[i];
13430 for(var i = start; i >= end; i--) {
13431 r[r.length] = items[i];
13438 * Filter the <i>objects</i> in this collection by a specific property.
13439 * Returns a new collection that has been filtered.
13440 * @param {String} property A property on your objects
13441 * @param {String/RegExp} value Either string that the property values
13442 * should start with or a RegExp to test against the property
13443 * @return {MixedCollection} The new filtered collection
13445 filter : function(property, value){
13446 if(!value.exec){ // not a regex
13447 value = String(value);
13448 if(value.length == 0){
13449 return this.clone();
13451 value = new RegExp("^" + Roo.escapeRe(value), "i");
13453 return this.filterBy(function(o){
13454 return o && value.test(o[property]);
13459 * Filter by a function. * Returns a new collection that has been filtered.
13460 * The passed function will be called with each
13461 * object in the collection. If the function returns true, the value is included
13462 * otherwise it is filtered.
13463 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13464 * @param {Object} scope (optional) The scope of the function (defaults to this)
13465 * @return {MixedCollection} The new filtered collection
13467 filterBy : function(fn, scope){
13468 var r = new Roo.util.MixedCollection();
13469 r.getKey = this.getKey;
13470 var k = this.keys, it = this.items;
13471 for(var i = 0, len = it.length; i < len; i++){
13472 if(fn.call(scope||this, it[i], k[i])){
13473 r.add(k[i], it[i]);
13480 * Creates a duplicate of this collection
13481 * @return {MixedCollection}
13483 clone : function(){
13484 var r = new Roo.util.MixedCollection();
13485 var k = this.keys, it = this.items;
13486 for(var i = 0, len = it.length; i < len; i++){
13487 r.add(k[i], it[i]);
13489 r.getKey = this.getKey;
13494 * Returns the item associated with the passed key or index.
13496 * @param {String/Number} key The key or index of the item.
13497 * @return {Object} The item associated with the passed key.
13499 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13501 * Ext JS Library 1.1.1
13502 * Copyright(c) 2006-2007, Ext JS, LLC.
13504 * Originally Released Under LGPL - original licence link has changed is not relivant.
13507 * <script type="text/javascript">
13510 * @class Roo.util.JSON
13511 * Modified version of Douglas Crockford"s json.js that doesn"t
13512 * mess with the Object prototype
13513 * http://www.json.org/js.html
13516 Roo.util.JSON = new (function(){
13517 var useHasOwn = {}.hasOwnProperty ? true : false;
13519 // crashes Safari in some instances
13520 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13522 var pad = function(n) {
13523 return n < 10 ? "0" + n : n;
13536 var encodeString = function(s){
13537 if (/["\\\x00-\x1f]/.test(s)) {
13538 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13543 c = b.charCodeAt();
13545 Math.floor(c / 16).toString(16) +
13546 (c % 16).toString(16);
13549 return '"' + s + '"';
13552 var encodeArray = function(o){
13553 var a = ["["], b, i, l = o.length, v;
13554 for (i = 0; i < l; i += 1) {
13556 switch (typeof v) {
13565 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13573 var encodeDate = function(o){
13574 return '"' + o.getFullYear() + "-" +
13575 pad(o.getMonth() + 1) + "-" +
13576 pad(o.getDate()) + "T" +
13577 pad(o.getHours()) + ":" +
13578 pad(o.getMinutes()) + ":" +
13579 pad(o.getSeconds()) + '"';
13583 * Encodes an Object, Array or other value
13584 * @param {Mixed} o The variable to encode
13585 * @return {String} The JSON string
13587 this.encode = function(o)
13589 // should this be extended to fully wrap stringify..
13591 if(typeof o == "undefined" || o === null){
13593 }else if(o instanceof Array){
13594 return encodeArray(o);
13595 }else if(o instanceof Date){
13596 return encodeDate(o);
13597 }else if(typeof o == "string"){
13598 return encodeString(o);
13599 }else if(typeof o == "number"){
13600 return isFinite(o) ? String(o) : "null";
13601 }else if(typeof o == "boolean"){
13604 var a = ["{"], b, i, v;
13606 if(!useHasOwn || o.hasOwnProperty(i)) {
13608 switch (typeof v) {
13617 a.push(this.encode(i), ":",
13618 v === null ? "null" : this.encode(v));
13629 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13630 * @param {String} json The JSON string
13631 * @return {Object} The resulting object
13633 this.decode = function(json){
13635 return /** eval:var:json */ eval("(" + json + ')');
13639 * Shorthand for {@link Roo.util.JSON#encode}
13640 * @member Roo encode
13642 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13644 * Shorthand for {@link Roo.util.JSON#decode}
13645 * @member Roo decode
13647 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13650 * Ext JS Library 1.1.1
13651 * Copyright(c) 2006-2007, Ext JS, LLC.
13653 * Originally Released Under LGPL - original licence link has changed is not relivant.
13656 * <script type="text/javascript">
13660 * @class Roo.util.Format
13661 * Reusable data formatting functions
13664 Roo.util.Format = function(){
13665 var trimRe = /^\s+|\s+$/g;
13668 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13669 * @param {String} value The string to truncate
13670 * @param {Number} length The maximum length to allow before truncating
13671 * @return {String} The converted text
13673 ellipsis : function(value, len){
13674 if(value && value.length > len){
13675 return value.substr(0, len-3)+"...";
13681 * Checks a reference and converts it to empty string if it is undefined
13682 * @param {Mixed} value Reference to check
13683 * @return {Mixed} Empty string if converted, otherwise the original value
13685 undef : function(value){
13686 return typeof value != "undefined" ? value : "";
13690 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13691 * @param {String} value The string to encode
13692 * @return {String} The encoded text
13694 htmlEncode : function(value){
13695 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13699 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13700 * @param {String} value The string to decode
13701 * @return {String} The decoded text
13703 htmlDecode : function(value){
13704 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13708 * Trims any whitespace from either side of a string
13709 * @param {String} value The text to trim
13710 * @return {String} The trimmed text
13712 trim : function(value){
13713 return String(value).replace(trimRe, "");
13717 * Returns a substring from within an original string
13718 * @param {String} value The original text
13719 * @param {Number} start The start index of the substring
13720 * @param {Number} length The length of the substring
13721 * @return {String} The substring
13723 substr : function(value, start, length){
13724 return String(value).substr(start, length);
13728 * Converts a string to all lower case letters
13729 * @param {String} value The text to convert
13730 * @return {String} The converted text
13732 lowercase : function(value){
13733 return String(value).toLowerCase();
13737 * Converts a string to all upper case letters
13738 * @param {String} value The text to convert
13739 * @return {String} The converted text
13741 uppercase : function(value){
13742 return String(value).toUpperCase();
13746 * Converts the first character only of a string to upper case
13747 * @param {String} value The text to convert
13748 * @return {String} The converted text
13750 capitalize : function(value){
13751 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13755 call : function(value, fn){
13756 if(arguments.length > 2){
13757 var args = Array.prototype.slice.call(arguments, 2);
13758 args.unshift(value);
13760 return /** eval:var:value */ eval(fn).apply(window, args);
13762 /** eval:var:value */
13763 return /** eval:var:value */ eval(fn).call(window, value);
13769 * safer version of Math.toFixed..??/
13770 * @param {Number/String} value The numeric value to format
13771 * @param {Number/String} value Decimal places
13772 * @return {String} The formatted currency string
13774 toFixed : function(v, n)
13776 // why not use to fixed - precision is buggered???
13778 return Math.round(v-0);
13780 var fact = Math.pow(10,n+1);
13781 v = (Math.round((v-0)*fact))/fact;
13782 var z = (''+fact).substring(2);
13783 if (v == Math.floor(v)) {
13784 return Math.floor(v) + '.' + z;
13787 // now just padd decimals..
13788 var ps = String(v).split('.');
13789 var fd = (ps[1] + z);
13790 var r = fd.substring(0,n);
13791 var rm = fd.substring(n);
13793 return ps[0] + '.' + r;
13795 r*=1; // turn it into a number;
13797 if (String(r).length != n) {
13800 r = String(r).substring(1); // chop the end off.
13803 return ps[0] + '.' + r;
13808 * Format a number as US currency
13809 * @param {Number/String} value The numeric value to format
13810 * @return {String} The formatted currency string
13812 usMoney : function(v){
13813 return '$' + Roo.util.Format.number(v);
13818 * eventually this should probably emulate php's number_format
13819 * @param {Number/String} value The numeric value to format
13820 * @param {Number} decimals number of decimal places
13821 * @param {String} delimiter for thousands (default comma)
13822 * @return {String} The formatted currency string
13824 number : function(v, decimals, thousandsDelimiter)
13826 // multiply and round.
13827 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13828 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13830 var mul = Math.pow(10, decimals);
13831 var zero = String(mul).substring(1);
13832 v = (Math.round((v-0)*mul))/mul;
13834 // if it's '0' number.. then
13836 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13838 var ps = v.split('.');
13841 var r = /(\d+)(\d{3})/;
13844 if(thousandsDelimiter.length != 0) {
13845 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13850 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13851 // does not have decimals
13852 (decimals ? ('.' + zero) : '');
13855 return whole + sub ;
13859 * Parse a value into a formatted date using the specified format pattern.
13860 * @param {Mixed} value The value to format
13861 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13862 * @return {String} The formatted date string
13864 date : function(v, format){
13868 if(!(v instanceof Date)){
13869 v = new Date(Date.parse(v));
13871 return v.dateFormat(format || Roo.util.Format.defaults.date);
13875 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13876 * @param {String} format Any valid date format string
13877 * @return {Function} The date formatting function
13879 dateRenderer : function(format){
13880 return function(v){
13881 return Roo.util.Format.date(v, format);
13886 stripTagsRE : /<\/?[^>]+>/gi,
13889 * Strips all HTML tags
13890 * @param {Mixed} value The text from which to strip tags
13891 * @return {String} The stripped text
13893 stripTags : function(v){
13894 return !v ? v : String(v).replace(this.stripTagsRE, "");
13898 Roo.util.Format.defaults = {
13902 * Ext JS Library 1.1.1
13903 * Copyright(c) 2006-2007, Ext JS, LLC.
13905 * Originally Released Under LGPL - original licence link has changed is not relivant.
13908 * <script type="text/javascript">
13915 * @class Roo.MasterTemplate
13916 * @extends Roo.Template
13917 * Provides a template that can have child templates. The syntax is:
13919 var t = new Roo.MasterTemplate(
13920 '<select name="{name}">',
13921 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13924 t.add('options', {value: 'foo', text: 'bar'});
13925 // or you can add multiple child elements in one shot
13926 t.addAll('options', [
13927 {value: 'foo', text: 'bar'},
13928 {value: 'foo2', text: 'bar2'},
13929 {value: 'foo3', text: 'bar3'}
13931 // then append, applying the master template values
13932 t.append('my-form', {name: 'my-select'});
13934 * A name attribute for the child template is not required if you have only one child
13935 * template or you want to refer to them by index.
13937 Roo.MasterTemplate = function(){
13938 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13939 this.originalHtml = this.html;
13941 var m, re = this.subTemplateRe;
13944 while(m = re.exec(this.html)){
13945 var name = m[1], content = m[2];
13950 tpl : new Roo.Template(content)
13953 st[name] = st[subIndex];
13955 st[subIndex].tpl.compile();
13956 st[subIndex].tpl.call = this.call.createDelegate(this);
13959 this.subCount = subIndex;
13962 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13964 * The regular expression used to match sub templates
13968 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13971 * Applies the passed values to a child template.
13972 * @param {String/Number} name (optional) The name or index of the child template
13973 * @param {Array/Object} values The values to be applied to the template
13974 * @return {MasterTemplate} this
13976 add : function(name, values){
13977 if(arguments.length == 1){
13978 values = arguments[0];
13981 var s = this.subs[name];
13982 s.buffer[s.buffer.length] = s.tpl.apply(values);
13987 * Applies all the passed values to a child template.
13988 * @param {String/Number} name (optional) The name or index of the child template
13989 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13990 * @param {Boolean} reset (optional) True to reset the template first
13991 * @return {MasterTemplate} this
13993 fill : function(name, values, reset){
13995 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14003 for(var i = 0, len = values.length; i < len; i++){
14004 this.add(name, values[i]);
14010 * Resets the template for reuse
14011 * @return {MasterTemplate} this
14013 reset : function(){
14015 for(var i = 0; i < this.subCount; i++){
14021 applyTemplate : function(values){
14023 var replaceIndex = -1;
14024 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14025 return s[++replaceIndex].buffer.join("");
14027 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14030 apply : function(){
14031 return this.applyTemplate.apply(this, arguments);
14034 compile : function(){return this;}
14038 * Alias for fill().
14041 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14043 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14044 * var tpl = Roo.MasterTemplate.from('element-id');
14045 * @param {String/HTMLElement} el
14046 * @param {Object} config
14049 Roo.MasterTemplate.from = function(el, config){
14050 el = Roo.getDom(el);
14051 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14054 * Ext JS Library 1.1.1
14055 * Copyright(c) 2006-2007, Ext JS, LLC.
14057 * Originally Released Under LGPL - original licence link has changed is not relivant.
14060 * <script type="text/javascript">
14065 * @class Roo.util.CSS
14066 * Utility class for manipulating CSS rules
14069 Roo.util.CSS = function(){
14071 var doc = document;
14073 var camelRe = /(-[a-z])/gi;
14074 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14078 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14079 * tag and appended to the HEAD of the document.
14080 * @param {String|Object} cssText The text containing the css rules
14081 * @param {String} id An id to add to the stylesheet for later removal
14082 * @return {StyleSheet}
14084 createStyleSheet : function(cssText, id){
14086 var head = doc.getElementsByTagName("head")[0];
14087 var nrules = doc.createElement("style");
14088 nrules.setAttribute("type", "text/css");
14090 nrules.setAttribute("id", id);
14092 if (typeof(cssText) != 'string') {
14093 // support object maps..
14094 // not sure if this a good idea..
14095 // perhaps it should be merged with the general css handling
14096 // and handle js style props.
14097 var cssTextNew = [];
14098 for(var n in cssText) {
14100 for(var k in cssText[n]) {
14101 citems.push( k + ' : ' +cssText[n][k] + ';' );
14103 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14106 cssText = cssTextNew.join("\n");
14112 head.appendChild(nrules);
14113 ss = nrules.styleSheet;
14114 ss.cssText = cssText;
14117 nrules.appendChild(doc.createTextNode(cssText));
14119 nrules.cssText = cssText;
14121 head.appendChild(nrules);
14122 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14124 this.cacheStyleSheet(ss);
14129 * Removes a style or link tag by id
14130 * @param {String} id The id of the tag
14132 removeStyleSheet : function(id){
14133 var existing = doc.getElementById(id);
14135 existing.parentNode.removeChild(existing);
14140 * Dynamically swaps an existing stylesheet reference for a new one
14141 * @param {String} id The id of an existing link tag to remove
14142 * @param {String} url The href of the new stylesheet to include
14144 swapStyleSheet : function(id, url){
14145 this.removeStyleSheet(id);
14146 var ss = doc.createElement("link");
14147 ss.setAttribute("rel", "stylesheet");
14148 ss.setAttribute("type", "text/css");
14149 ss.setAttribute("id", id);
14150 ss.setAttribute("href", url);
14151 doc.getElementsByTagName("head")[0].appendChild(ss);
14155 * Refresh the rule cache if you have dynamically added stylesheets
14156 * @return {Object} An object (hash) of rules indexed by selector
14158 refreshCache : function(){
14159 return this.getRules(true);
14163 cacheStyleSheet : function(stylesheet){
14167 try{// try catch for cross domain access issue
14168 var ssRules = stylesheet.cssRules || stylesheet.rules;
14169 for(var j = ssRules.length-1; j >= 0; --j){
14170 rules[ssRules[j].selectorText] = ssRules[j];
14176 * Gets all css rules for the document
14177 * @param {Boolean} refreshCache true to refresh the internal cache
14178 * @return {Object} An object (hash) of rules indexed by selector
14180 getRules : function(refreshCache){
14181 if(rules == null || refreshCache){
14183 var ds = doc.styleSheets;
14184 for(var i =0, len = ds.length; i < len; i++){
14186 this.cacheStyleSheet(ds[i]);
14194 * Gets an an individual CSS rule by selector(s)
14195 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14196 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14197 * @return {CSSRule} The CSS rule or null if one is not found
14199 getRule : function(selector, refreshCache){
14200 var rs = this.getRules(refreshCache);
14201 if(!(selector instanceof Array)){
14202 return rs[selector];
14204 for(var i = 0; i < selector.length; i++){
14205 if(rs[selector[i]]){
14206 return rs[selector[i]];
14214 * Updates a rule property
14215 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14216 * @param {String} property The css property
14217 * @param {String} value The new value for the property
14218 * @return {Boolean} true If a rule was found and updated
14220 updateRule : function(selector, property, value){
14221 if(!(selector instanceof Array)){
14222 var rule = this.getRule(selector);
14224 rule.style[property.replace(camelRe, camelFn)] = value;
14228 for(var i = 0; i < selector.length; i++){
14229 if(this.updateRule(selector[i], property, value)){
14239 * Ext JS Library 1.1.1
14240 * Copyright(c) 2006-2007, Ext JS, LLC.
14242 * Originally Released Under LGPL - original licence link has changed is not relivant.
14245 * <script type="text/javascript">
14251 * @class Roo.util.ClickRepeater
14252 * @extends Roo.util.Observable
14254 * A wrapper class which can be applied to any element. Fires a "click" event while the
14255 * mouse is pressed. The interval between firings may be specified in the config but
14256 * defaults to 10 milliseconds.
14258 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14260 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14261 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14262 * Similar to an autorepeat key delay.
14263 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14264 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14265 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14266 * "interval" and "delay" are ignored. "immediate" is honored.
14267 * @cfg {Boolean} preventDefault True to prevent the default click event
14268 * @cfg {Boolean} stopDefault True to stop the default click event
14271 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14272 * 2007-02-02 jvs Renamed to ClickRepeater
14273 * 2007-02-03 jvs Modifications for FF Mac and Safari
14276 * @param {String/HTMLElement/Element} el The element to listen on
14277 * @param {Object} config
14279 Roo.util.ClickRepeater = function(el, config)
14281 this.el = Roo.get(el);
14282 this.el.unselectable();
14284 Roo.apply(this, config);
14289 * Fires when the mouse button is depressed.
14290 * @param {Roo.util.ClickRepeater} this
14292 "mousedown" : true,
14295 * Fires on a specified interval during the time the element is pressed.
14296 * @param {Roo.util.ClickRepeater} this
14301 * Fires when the mouse key is released.
14302 * @param {Roo.util.ClickRepeater} this
14307 this.el.on("mousedown", this.handleMouseDown, this);
14308 if(this.preventDefault || this.stopDefault){
14309 this.el.on("click", function(e){
14310 if(this.preventDefault){
14311 e.preventDefault();
14313 if(this.stopDefault){
14319 // allow inline handler
14321 this.on("click", this.handler, this.scope || this);
14324 Roo.util.ClickRepeater.superclass.constructor.call(this);
14327 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14330 preventDefault : true,
14331 stopDefault : false,
14335 handleMouseDown : function(){
14336 clearTimeout(this.timer);
14338 if(this.pressClass){
14339 this.el.addClass(this.pressClass);
14341 this.mousedownTime = new Date();
14343 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14344 this.el.on("mouseout", this.handleMouseOut, this);
14346 this.fireEvent("mousedown", this);
14347 this.fireEvent("click", this);
14349 this.timer = this.click.defer(this.delay || this.interval, this);
14353 click : function(){
14354 this.fireEvent("click", this);
14355 this.timer = this.click.defer(this.getInterval(), this);
14359 getInterval: function(){
14360 if(!this.accelerate){
14361 return this.interval;
14363 var pressTime = this.mousedownTime.getElapsed();
14364 if(pressTime < 500){
14366 }else if(pressTime < 1700){
14368 }else if(pressTime < 2600){
14370 }else if(pressTime < 3500){
14372 }else if(pressTime < 4400){
14374 }else if(pressTime < 5300){
14376 }else if(pressTime < 6200){
14384 handleMouseOut : function(){
14385 clearTimeout(this.timer);
14386 if(this.pressClass){
14387 this.el.removeClass(this.pressClass);
14389 this.el.on("mouseover", this.handleMouseReturn, this);
14393 handleMouseReturn : function(){
14394 this.el.un("mouseover", this.handleMouseReturn);
14395 if(this.pressClass){
14396 this.el.addClass(this.pressClass);
14402 handleMouseUp : function(){
14403 clearTimeout(this.timer);
14404 this.el.un("mouseover", this.handleMouseReturn);
14405 this.el.un("mouseout", this.handleMouseOut);
14406 Roo.get(document).un("mouseup", this.handleMouseUp);
14407 this.el.removeClass(this.pressClass);
14408 this.fireEvent("mouseup", this);
14412 * Ext JS Library 1.1.1
14413 * Copyright(c) 2006-2007, Ext JS, LLC.
14415 * Originally Released Under LGPL - original licence link has changed is not relivant.
14418 * <script type="text/javascript">
14423 * @class Roo.KeyNav
14424 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14425 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14426 * way to implement custom navigation schemes for any UI component.</p>
14427 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14428 * pageUp, pageDown, del, home, end. Usage:</p>
14430 var nav = new Roo.KeyNav("my-element", {
14431 "left" : function(e){
14432 this.moveLeft(e.ctrlKey);
14434 "right" : function(e){
14435 this.moveRight(e.ctrlKey);
14437 "enter" : function(e){
14444 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14445 * @param {Object} config The config
14447 Roo.KeyNav = function(el, config){
14448 this.el = Roo.get(el);
14449 Roo.apply(this, config);
14450 if(!this.disabled){
14451 this.disabled = true;
14456 Roo.KeyNav.prototype = {
14458 * @cfg {Boolean} disabled
14459 * True to disable this KeyNav instance (defaults to false)
14463 * @cfg {String} defaultEventAction
14464 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14465 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14466 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14468 defaultEventAction: "stopEvent",
14470 * @cfg {Boolean} forceKeyDown
14471 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14472 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14473 * handle keydown instead of keypress.
14475 forceKeyDown : false,
14478 prepareEvent : function(e){
14479 var k = e.getKey();
14480 var h = this.keyToHandler[k];
14481 //if(h && this[h]){
14482 // e.stopPropagation();
14484 if(Roo.isSafari && h && k >= 37 && k <= 40){
14490 relay : function(e){
14491 var k = e.getKey();
14492 var h = this.keyToHandler[k];
14494 if(this.doRelay(e, this[h], h) !== true){
14495 e[this.defaultEventAction]();
14501 doRelay : function(e, h, hname){
14502 return h.call(this.scope || this, e);
14505 // possible handlers
14519 // quick lookup hash
14536 * Enable this KeyNav
14538 enable: function(){
14540 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14541 // the EventObject will normalize Safari automatically
14542 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14543 this.el.on("keydown", this.relay, this);
14545 this.el.on("keydown", this.prepareEvent, this);
14546 this.el.on("keypress", this.relay, this);
14548 this.disabled = false;
14553 * Disable this KeyNav
14555 disable: function(){
14556 if(!this.disabled){
14557 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14558 this.el.un("keydown", this.relay);
14560 this.el.un("keydown", this.prepareEvent);
14561 this.el.un("keypress", this.relay);
14563 this.disabled = true;
14568 * Ext JS Library 1.1.1
14569 * Copyright(c) 2006-2007, Ext JS, LLC.
14571 * Originally Released Under LGPL - original licence link has changed is not relivant.
14574 * <script type="text/javascript">
14579 * @class Roo.KeyMap
14580 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14581 * The constructor accepts the same config object as defined by {@link #addBinding}.
14582 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14583 * combination it will call the function with this signature (if the match is a multi-key
14584 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14585 * A KeyMap can also handle a string representation of keys.<br />
14588 // map one key by key code
14589 var map = new Roo.KeyMap("my-element", {
14590 key: 13, // or Roo.EventObject.ENTER
14595 // map multiple keys to one action by string
14596 var map = new Roo.KeyMap("my-element", {
14602 // map multiple keys to multiple actions by strings and array of codes
14603 var map = new Roo.KeyMap("my-element", [
14606 fn: function(){ alert("Return was pressed"); }
14609 fn: function(){ alert('a, b or c was pressed'); }
14614 fn: function(){ alert('Control + shift + tab was pressed.'); }
14618 * <b>Note: A KeyMap starts enabled</b>
14620 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14621 * @param {Object} config The config (see {@link #addBinding})
14622 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14624 Roo.KeyMap = function(el, config, eventName){
14625 this.el = Roo.get(el);
14626 this.eventName = eventName || "keydown";
14627 this.bindings = [];
14629 this.addBinding(config);
14634 Roo.KeyMap.prototype = {
14636 * True to stop the event from bubbling and prevent the default browser action if the
14637 * key was handled by the KeyMap (defaults to false)
14643 * Add a new binding to this KeyMap. The following config object properties are supported:
14645 Property Type Description
14646 ---------- --------------- ----------------------------------------------------------------------
14647 key String/Array A single keycode or an array of keycodes to handle
14648 shift Boolean True to handle key only when shift is pressed (defaults to false)
14649 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14650 alt Boolean True to handle key only when alt is pressed (defaults to false)
14651 fn Function The function to call when KeyMap finds the expected key combination
14652 scope Object The scope of the callback function
14658 var map = new Roo.KeyMap(document, {
14659 key: Roo.EventObject.ENTER,
14664 //Add a new binding to the existing KeyMap later
14672 * @param {Object/Array} config A single KeyMap config or an array of configs
14674 addBinding : function(config){
14675 if(config instanceof Array){
14676 for(var i = 0, len = config.length; i < len; i++){
14677 this.addBinding(config[i]);
14681 var keyCode = config.key,
14682 shift = config.shift,
14683 ctrl = config.ctrl,
14686 scope = config.scope;
14687 if(typeof keyCode == "string"){
14689 var keyString = keyCode.toUpperCase();
14690 for(var j = 0, len = keyString.length; j < len; j++){
14691 ks.push(keyString.charCodeAt(j));
14695 var keyArray = keyCode instanceof Array;
14696 var handler = function(e){
14697 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14698 var k = e.getKey();
14700 for(var i = 0, len = keyCode.length; i < len; i++){
14701 if(keyCode[i] == k){
14702 if(this.stopEvent){
14705 fn.call(scope || window, k, e);
14711 if(this.stopEvent){
14714 fn.call(scope || window, k, e);
14719 this.bindings.push(handler);
14723 * Shorthand for adding a single key listener
14724 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14725 * following options:
14726 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14727 * @param {Function} fn The function to call
14728 * @param {Object} scope (optional) The scope of the function
14730 on : function(key, fn, scope){
14731 var keyCode, shift, ctrl, alt;
14732 if(typeof key == "object" && !(key instanceof Array)){
14751 handleKeyDown : function(e){
14752 if(this.enabled){ //just in case
14753 var b = this.bindings;
14754 for(var i = 0, len = b.length; i < len; i++){
14755 b[i].call(this, e);
14761 * Returns true if this KeyMap is enabled
14762 * @return {Boolean}
14764 isEnabled : function(){
14765 return this.enabled;
14769 * Enables this KeyMap
14771 enable: function(){
14773 this.el.on(this.eventName, this.handleKeyDown, this);
14774 this.enabled = true;
14779 * Disable this KeyMap
14781 disable: function(){
14783 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14784 this.enabled = false;
14789 * Ext JS Library 1.1.1
14790 * Copyright(c) 2006-2007, Ext JS, LLC.
14792 * Originally Released Under LGPL - original licence link has changed is not relivant.
14795 * <script type="text/javascript">
14800 * @class Roo.util.TextMetrics
14801 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14802 * wide, in pixels, a given block of text will be.
14805 Roo.util.TextMetrics = function(){
14809 * Measures the size of the specified text
14810 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14811 * that can affect the size of the rendered text
14812 * @param {String} text The text to measure
14813 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14814 * in order to accurately measure the text height
14815 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14817 measure : function(el, text, fixedWidth){
14819 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14822 shared.setFixedWidth(fixedWidth || 'auto');
14823 return shared.getSize(text);
14827 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14828 * the overhead of multiple calls to initialize the style properties on each measurement.
14829 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14830 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14831 * in order to accurately measure the text height
14832 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14834 createInstance : function(el, fixedWidth){
14835 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14842 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14843 var ml = new Roo.Element(document.createElement('div'));
14844 document.body.appendChild(ml.dom);
14845 ml.position('absolute');
14846 ml.setLeftTop(-1000, -1000);
14850 ml.setWidth(fixedWidth);
14855 * Returns the size of the specified text based on the internal element's style and width properties
14856 * @memberOf Roo.util.TextMetrics.Instance#
14857 * @param {String} text The text to measure
14858 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14860 getSize : function(text){
14862 var s = ml.getSize();
14868 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14869 * that can affect the size of the rendered text
14870 * @memberOf Roo.util.TextMetrics.Instance#
14871 * @param {String/HTMLElement} el The element, dom node or id
14873 bind : function(el){
14875 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14880 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14881 * to set a fixed width in order to accurately measure the text height.
14882 * @memberOf Roo.util.TextMetrics.Instance#
14883 * @param {Number} width The width to set on the element
14885 setFixedWidth : function(width){
14886 ml.setWidth(width);
14890 * Returns the measured width of the specified text
14891 * @memberOf Roo.util.TextMetrics.Instance#
14892 * @param {String} text The text to measure
14893 * @return {Number} width The width in pixels
14895 getWidth : function(text){
14896 ml.dom.style.width = 'auto';
14897 return this.getSize(text).width;
14901 * Returns the measured height of the specified text. For multiline text, be sure to call
14902 * {@link #setFixedWidth} if necessary.
14903 * @memberOf Roo.util.TextMetrics.Instance#
14904 * @param {String} text The text to measure
14905 * @return {Number} height The height in pixels
14907 getHeight : function(text){
14908 return this.getSize(text).height;
14912 instance.bind(bindTo);
14917 // backwards compat
14918 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14920 * Ext JS Library 1.1.1
14921 * Copyright(c) 2006-2007, Ext JS, LLC.
14923 * Originally Released Under LGPL - original licence link has changed is not relivant.
14926 * <script type="text/javascript">
14930 * @class Roo.state.Provider
14931 * Abstract base class for state provider implementations. This class provides methods
14932 * for encoding and decoding <b>typed</b> variables including dates and defines the
14933 * Provider interface.
14935 Roo.state.Provider = function(){
14937 * @event statechange
14938 * Fires when a state change occurs.
14939 * @param {Provider} this This state provider
14940 * @param {String} key The state key which was changed
14941 * @param {String} value The encoded value for the state
14944 "statechange": true
14947 Roo.state.Provider.superclass.constructor.call(this);
14949 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14951 * Returns the current value for a key
14952 * @param {String} name The key name
14953 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14954 * @return {Mixed} The state data
14956 get : function(name, defaultValue){
14957 return typeof this.state[name] == "undefined" ?
14958 defaultValue : this.state[name];
14962 * Clears a value from the state
14963 * @param {String} name The key name
14965 clear : function(name){
14966 delete this.state[name];
14967 this.fireEvent("statechange", this, name, null);
14971 * Sets the value for a key
14972 * @param {String} name The key name
14973 * @param {Mixed} value The value to set
14975 set : function(name, value){
14976 this.state[name] = value;
14977 this.fireEvent("statechange", this, name, value);
14981 * Decodes a string previously encoded with {@link #encodeValue}.
14982 * @param {String} value The value to decode
14983 * @return {Mixed} The decoded value
14985 decodeValue : function(cookie){
14986 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14987 var matches = re.exec(unescape(cookie));
14988 if(!matches || !matches[1]) {
14989 return; // non state cookie
14991 var type = matches[1];
14992 var v = matches[2];
14995 return parseFloat(v);
14997 return new Date(Date.parse(v));
15002 var values = v.split("^");
15003 for(var i = 0, len = values.length; i < len; i++){
15004 all.push(this.decodeValue(values[i]));
15009 var values = v.split("^");
15010 for(var i = 0, len = values.length; i < len; i++){
15011 var kv = values[i].split("=");
15012 all[kv[0]] = this.decodeValue(kv[1]);
15021 * Encodes a value including type information. Decode with {@link #decodeValue}.
15022 * @param {Mixed} value The value to encode
15023 * @return {String} The encoded value
15025 encodeValue : function(v){
15027 if(typeof v == "number"){
15029 }else if(typeof v == "boolean"){
15030 enc = "b:" + (v ? "1" : "0");
15031 }else if(v instanceof Date){
15032 enc = "d:" + v.toGMTString();
15033 }else if(v instanceof Array){
15035 for(var i = 0, len = v.length; i < len; i++){
15036 flat += this.encodeValue(v[i]);
15042 }else if(typeof v == "object"){
15045 if(typeof v[key] != "function"){
15046 flat += key + "=" + this.encodeValue(v[key]) + "^";
15049 enc = "o:" + flat.substring(0, flat.length-1);
15053 return escape(enc);
15059 * Ext JS Library 1.1.1
15060 * Copyright(c) 2006-2007, Ext JS, LLC.
15062 * Originally Released Under LGPL - original licence link has changed is not relivant.
15065 * <script type="text/javascript">
15068 * @class Roo.state.Manager
15069 * This is the global state manager. By default all components that are "state aware" check this class
15070 * for state information if you don't pass them a custom state provider. In order for this class
15071 * to be useful, it must be initialized with a provider when your application initializes.
15073 // in your initialization function
15075 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15077 // supposed you have a {@link Roo.BorderLayout}
15078 var layout = new Roo.BorderLayout(...);
15079 layout.restoreState();
15080 // or a {Roo.BasicDialog}
15081 var dialog = new Roo.BasicDialog(...);
15082 dialog.restoreState();
15086 Roo.state.Manager = function(){
15087 var provider = new Roo.state.Provider();
15091 * Configures the default state provider for your application
15092 * @param {Provider} stateProvider The state provider to set
15094 setProvider : function(stateProvider){
15095 provider = stateProvider;
15099 * Returns the current value for a key
15100 * @param {String} name The key name
15101 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15102 * @return {Mixed} The state data
15104 get : function(key, defaultValue){
15105 return provider.get(key, defaultValue);
15109 * Sets the value for a key
15110 * @param {String} name The key name
15111 * @param {Mixed} value The state data
15113 set : function(key, value){
15114 provider.set(key, value);
15118 * Clears a value from the state
15119 * @param {String} name The key name
15121 clear : function(key){
15122 provider.clear(key);
15126 * Gets the currently configured state provider
15127 * @return {Provider} The state provider
15129 getProvider : function(){
15136 * Ext JS Library 1.1.1
15137 * Copyright(c) 2006-2007, Ext JS, LLC.
15139 * Originally Released Under LGPL - original licence link has changed is not relivant.
15142 * <script type="text/javascript">
15145 * @class Roo.state.CookieProvider
15146 * @extends Roo.state.Provider
15147 * The default Provider implementation which saves state via cookies.
15150 var cp = new Roo.state.CookieProvider({
15152 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15153 domain: "roojs.com"
15155 Roo.state.Manager.setProvider(cp);
15157 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15158 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15159 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15160 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15161 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15162 * domain the page is running on including the 'www' like 'www.roojs.com')
15163 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15165 * Create a new CookieProvider
15166 * @param {Object} config The configuration object
15168 Roo.state.CookieProvider = function(config){
15169 Roo.state.CookieProvider.superclass.constructor.call(this);
15171 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15172 this.domain = null;
15173 this.secure = false;
15174 Roo.apply(this, config);
15175 this.state = this.readCookies();
15178 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15180 set : function(name, value){
15181 if(typeof value == "undefined" || value === null){
15185 this.setCookie(name, value);
15186 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15190 clear : function(name){
15191 this.clearCookie(name);
15192 Roo.state.CookieProvider.superclass.clear.call(this, name);
15196 readCookies : function(){
15198 var c = document.cookie + ";";
15199 var re = /\s?(.*?)=(.*?);/g;
15201 while((matches = re.exec(c)) != null){
15202 var name = matches[1];
15203 var value = matches[2];
15204 if(name && name.substring(0,3) == "ys-"){
15205 cookies[name.substr(3)] = this.decodeValue(value);
15212 setCookie : function(name, value){
15213 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15214 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15215 ((this.path == null) ? "" : ("; path=" + this.path)) +
15216 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15217 ((this.secure == true) ? "; secure" : "");
15221 clearCookie : function(name){
15222 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15223 ((this.path == null) ? "" : ("; path=" + this.path)) +
15224 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15225 ((this.secure == true) ? "; secure" : "");
15229 * Ext JS Library 1.1.1
15230 * Copyright(c) 2006-2007, Ext JS, LLC.
15232 * Originally Released Under LGPL - original licence link has changed is not relivant.
15235 * <script type="text/javascript">
15240 * @class Roo.ComponentMgr
15241 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15244 Roo.ComponentMgr = function(){
15245 var all = new Roo.util.MixedCollection();
15249 * Registers a component.
15250 * @param {Roo.Component} c The component
15252 register : function(c){
15257 * Unregisters a component.
15258 * @param {Roo.Component} c The component
15260 unregister : function(c){
15265 * Returns a component by id
15266 * @param {String} id The component id
15268 get : function(id){
15269 return all.get(id);
15273 * Registers a function that will be called when a specified component is added to ComponentMgr
15274 * @param {String} id The component id
15275 * @param {Funtction} fn The callback function
15276 * @param {Object} scope The scope of the callback
15278 onAvailable : function(id, fn, scope){
15279 all.on("add", function(index, o){
15281 fn.call(scope || o, o);
15282 all.un("add", fn, scope);
15289 * Ext JS Library 1.1.1
15290 * Copyright(c) 2006-2007, Ext JS, LLC.
15292 * Originally Released Under LGPL - original licence link has changed is not relivant.
15295 * <script type="text/javascript">
15299 * @class Roo.Component
15300 * @extends Roo.util.Observable
15301 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15302 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15303 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15304 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15305 * All visual components (widgets) that require rendering into a layout should subclass Component.
15307 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15308 * 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
15309 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15311 Roo.Component = function(config){
15312 config = config || {};
15313 if(config.tagName || config.dom || typeof config == "string"){ // element object
15314 config = {el: config, id: config.id || config};
15316 this.initialConfig = config;
15318 Roo.apply(this, config);
15322 * Fires after the component is disabled.
15323 * @param {Roo.Component} this
15328 * Fires after the component is enabled.
15329 * @param {Roo.Component} this
15333 * @event beforeshow
15334 * Fires before the component is shown. Return false to stop the show.
15335 * @param {Roo.Component} this
15340 * Fires after the component is shown.
15341 * @param {Roo.Component} this
15345 * @event beforehide
15346 * Fires before the component is hidden. Return false to stop the hide.
15347 * @param {Roo.Component} this
15352 * Fires after the component is hidden.
15353 * @param {Roo.Component} this
15357 * @event beforerender
15358 * Fires before the component is rendered. Return false to stop the render.
15359 * @param {Roo.Component} this
15361 beforerender : true,
15364 * Fires after the component is rendered.
15365 * @param {Roo.Component} this
15369 * @event beforedestroy
15370 * Fires before the component is destroyed. Return false to stop the destroy.
15371 * @param {Roo.Component} this
15373 beforedestroy : true,
15376 * Fires after the component is destroyed.
15377 * @param {Roo.Component} this
15382 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15384 Roo.ComponentMgr.register(this);
15385 Roo.Component.superclass.constructor.call(this);
15386 this.initComponent();
15387 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15388 this.render(this.renderTo);
15389 delete this.renderTo;
15394 Roo.Component.AUTO_ID = 1000;
15396 Roo.extend(Roo.Component, Roo.util.Observable, {
15398 * @scope Roo.Component.prototype
15400 * true if this component is hidden. Read-only.
15405 * true if this component is disabled. Read-only.
15410 * true if this component has been rendered. Read-only.
15414 /** @cfg {String} disableClass
15415 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15417 disabledClass : "x-item-disabled",
15418 /** @cfg {Boolean} allowDomMove
15419 * Whether the component can move the Dom node when rendering (defaults to true).
15421 allowDomMove : true,
15422 /** @cfg {String} hideMode (display|visibility)
15423 * How this component should hidden. Supported values are
15424 * "visibility" (css visibility), "offsets" (negative offset position) and
15425 * "display" (css display) - defaults to "display".
15427 hideMode: 'display',
15430 ctype : "Roo.Component",
15433 * @cfg {String} actionMode
15434 * which property holds the element that used for hide() / show() / disable() / enable()
15440 getActionEl : function(){
15441 return this[this.actionMode];
15444 initComponent : Roo.emptyFn,
15446 * If this is a lazy rendering component, render it to its container element.
15447 * @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.
15449 render : function(container, position){
15455 if(this.fireEvent("beforerender", this) === false){
15459 if(!container && this.el){
15460 this.el = Roo.get(this.el);
15461 container = this.el.dom.parentNode;
15462 this.allowDomMove = false;
15464 this.container = Roo.get(container);
15465 this.rendered = true;
15466 if(position !== undefined){
15467 if(typeof position == 'number'){
15468 position = this.container.dom.childNodes[position];
15470 position = Roo.getDom(position);
15473 this.onRender(this.container, position || null);
15475 this.el.addClass(this.cls);
15479 this.el.applyStyles(this.style);
15482 this.fireEvent("render", this);
15483 this.afterRender(this.container);
15496 // default function is not really useful
15497 onRender : function(ct, position){
15499 this.el = Roo.get(this.el);
15500 if(this.allowDomMove !== false){
15501 ct.dom.insertBefore(this.el.dom, position);
15507 getAutoCreate : function(){
15508 var cfg = typeof this.autoCreate == "object" ?
15509 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15510 if(this.id && !cfg.id){
15517 afterRender : Roo.emptyFn,
15520 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15521 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15523 destroy : function(){
15524 if(this.fireEvent("beforedestroy", this) !== false){
15525 this.purgeListeners();
15526 this.beforeDestroy();
15528 this.el.removeAllListeners();
15530 if(this.actionMode == "container"){
15531 this.container.remove();
15535 Roo.ComponentMgr.unregister(this);
15536 this.fireEvent("destroy", this);
15541 beforeDestroy : function(){
15546 onDestroy : function(){
15551 * Returns the underlying {@link Roo.Element}.
15552 * @return {Roo.Element} The element
15554 getEl : function(){
15559 * Returns the id of this component.
15562 getId : function(){
15567 * Try to focus this component.
15568 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15569 * @return {Roo.Component} this
15571 focus : function(selectText){
15574 if(selectText === true){
15575 this.el.dom.select();
15590 * Disable this component.
15591 * @return {Roo.Component} this
15593 disable : function(){
15597 this.disabled = true;
15598 this.fireEvent("disable", this);
15603 onDisable : function(){
15604 this.getActionEl().addClass(this.disabledClass);
15605 this.el.dom.disabled = true;
15609 * Enable this component.
15610 * @return {Roo.Component} this
15612 enable : function(){
15616 this.disabled = false;
15617 this.fireEvent("enable", this);
15622 onEnable : function(){
15623 this.getActionEl().removeClass(this.disabledClass);
15624 this.el.dom.disabled = false;
15628 * Convenience function for setting disabled/enabled by boolean.
15629 * @param {Boolean} disabled
15631 setDisabled : function(disabled){
15632 this[disabled ? "disable" : "enable"]();
15636 * Show this component.
15637 * @return {Roo.Component} this
15640 if(this.fireEvent("beforeshow", this) !== false){
15641 this.hidden = false;
15645 this.fireEvent("show", this);
15651 onShow : function(){
15652 var ae = this.getActionEl();
15653 if(this.hideMode == 'visibility'){
15654 ae.dom.style.visibility = "visible";
15655 }else if(this.hideMode == 'offsets'){
15656 ae.removeClass('x-hidden');
15658 ae.dom.style.display = "";
15663 * Hide this component.
15664 * @return {Roo.Component} this
15667 if(this.fireEvent("beforehide", this) !== false){
15668 this.hidden = true;
15672 this.fireEvent("hide", this);
15678 onHide : function(){
15679 var ae = this.getActionEl();
15680 if(this.hideMode == 'visibility'){
15681 ae.dom.style.visibility = "hidden";
15682 }else if(this.hideMode == 'offsets'){
15683 ae.addClass('x-hidden');
15685 ae.dom.style.display = "none";
15690 * Convenience function to hide or show this component by boolean.
15691 * @param {Boolean} visible True to show, false to hide
15692 * @return {Roo.Component} this
15694 setVisible: function(visible){
15704 * Returns true if this component is visible.
15706 isVisible : function(){
15707 return this.getActionEl().isVisible();
15710 cloneConfig : function(overrides){
15711 overrides = overrides || {};
15712 var id = overrides.id || Roo.id();
15713 var cfg = Roo.applyIf(overrides, this.initialConfig);
15714 cfg.id = id; // prevent dup id
15715 return new this.constructor(cfg);
15719 * Ext JS Library 1.1.1
15720 * Copyright(c) 2006-2007, Ext JS, LLC.
15722 * Originally Released Under LGPL - original licence link has changed is not relivant.
15725 * <script type="text/javascript">
15729 * @class Roo.BoxComponent
15730 * @extends Roo.Component
15731 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15732 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15733 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15734 * layout containers.
15736 * @param {Roo.Element/String/Object} config The configuration options.
15738 Roo.BoxComponent = function(config){
15739 Roo.Component.call(this, config);
15743 * Fires after the component is resized.
15744 * @param {Roo.Component} this
15745 * @param {Number} adjWidth The box-adjusted width that was set
15746 * @param {Number} adjHeight The box-adjusted height that was set
15747 * @param {Number} rawWidth The width that was originally specified
15748 * @param {Number} rawHeight The height that was originally specified
15753 * Fires after the component is moved.
15754 * @param {Roo.Component} this
15755 * @param {Number} x The new x position
15756 * @param {Number} y The new y position
15762 Roo.extend(Roo.BoxComponent, Roo.Component, {
15763 // private, set in afterRender to signify that the component has been rendered
15765 // private, used to defer height settings to subclasses
15766 deferHeight: false,
15767 /** @cfg {Number} width
15768 * width (optional) size of component
15770 /** @cfg {Number} height
15771 * height (optional) size of component
15775 * Sets the width and height of the component. This method fires the resize event. This method can accept
15776 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15777 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15778 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15779 * @return {Roo.BoxComponent} this
15781 setSize : function(w, h){
15782 // support for standard size objects
15783 if(typeof w == 'object'){
15788 if(!this.boxReady){
15794 // prevent recalcs when not needed
15795 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15798 this.lastSize = {width: w, height: h};
15800 var adj = this.adjustSize(w, h);
15801 var aw = adj.width, ah = adj.height;
15802 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15803 var rz = this.getResizeEl();
15804 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15805 rz.setSize(aw, ah);
15806 }else if(!this.deferHeight && ah !== undefined){
15808 }else if(aw !== undefined){
15811 this.onResize(aw, ah, w, h);
15812 this.fireEvent('resize', this, aw, ah, w, h);
15818 * Gets the current size of the component's underlying element.
15819 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15821 getSize : function(){
15822 return this.el.getSize();
15826 * Gets the current XY position of the component's underlying element.
15827 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15828 * @return {Array} The XY position of the element (e.g., [100, 200])
15830 getPosition : function(local){
15831 if(local === true){
15832 return [this.el.getLeft(true), this.el.getTop(true)];
15834 return this.xy || this.el.getXY();
15838 * Gets the current box measurements of the component's underlying element.
15839 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15840 * @returns {Object} box An object in the format {x, y, width, height}
15842 getBox : function(local){
15843 var s = this.el.getSize();
15845 s.x = this.el.getLeft(true);
15846 s.y = this.el.getTop(true);
15848 var xy = this.xy || this.el.getXY();
15856 * Sets the current box measurements of the component's underlying element.
15857 * @param {Object} box An object in the format {x, y, width, height}
15858 * @returns {Roo.BoxComponent} this
15860 updateBox : function(box){
15861 this.setSize(box.width, box.height);
15862 this.setPagePosition(box.x, box.y);
15867 getResizeEl : function(){
15868 return this.resizeEl || this.el;
15872 getPositionEl : function(){
15873 return this.positionEl || this.el;
15877 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15878 * This method fires the move event.
15879 * @param {Number} left The new left
15880 * @param {Number} top The new top
15881 * @returns {Roo.BoxComponent} this
15883 setPosition : function(x, y){
15886 if(!this.boxReady){
15889 var adj = this.adjustPosition(x, y);
15890 var ax = adj.x, ay = adj.y;
15892 var el = this.getPositionEl();
15893 if(ax !== undefined || ay !== undefined){
15894 if(ax !== undefined && ay !== undefined){
15895 el.setLeftTop(ax, ay);
15896 }else if(ax !== undefined){
15898 }else if(ay !== undefined){
15901 this.onPosition(ax, ay);
15902 this.fireEvent('move', this, ax, ay);
15908 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15909 * This method fires the move event.
15910 * @param {Number} x The new x position
15911 * @param {Number} y The new y position
15912 * @returns {Roo.BoxComponent} this
15914 setPagePosition : function(x, y){
15917 if(!this.boxReady){
15920 if(x === undefined || y === undefined){ // cannot translate undefined points
15923 var p = this.el.translatePoints(x, y);
15924 this.setPosition(p.left, p.top);
15929 onRender : function(ct, position){
15930 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15932 this.resizeEl = Roo.get(this.resizeEl);
15934 if(this.positionEl){
15935 this.positionEl = Roo.get(this.positionEl);
15940 afterRender : function(){
15941 Roo.BoxComponent.superclass.afterRender.call(this);
15942 this.boxReady = true;
15943 this.setSize(this.width, this.height);
15944 if(this.x || this.y){
15945 this.setPosition(this.x, this.y);
15947 if(this.pageX || this.pageY){
15948 this.setPagePosition(this.pageX, this.pageY);
15953 * Force the component's size to recalculate based on the underlying element's current height and width.
15954 * @returns {Roo.BoxComponent} this
15956 syncSize : function(){
15957 delete this.lastSize;
15958 this.setSize(this.el.getWidth(), this.el.getHeight());
15963 * Called after the component is resized, this method is empty by default but can be implemented by any
15964 * subclass that needs to perform custom logic after a resize occurs.
15965 * @param {Number} adjWidth The box-adjusted width that was set
15966 * @param {Number} adjHeight The box-adjusted height that was set
15967 * @param {Number} rawWidth The width that was originally specified
15968 * @param {Number} rawHeight The height that was originally specified
15970 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15975 * Called after the component is moved, this method is empty by default but can be implemented by any
15976 * subclass that needs to perform custom logic after a move occurs.
15977 * @param {Number} x The new x position
15978 * @param {Number} y The new y position
15980 onPosition : function(x, y){
15985 adjustSize : function(w, h){
15986 if(this.autoWidth){
15989 if(this.autoHeight){
15992 return {width : w, height: h};
15996 adjustPosition : function(x, y){
15997 return {x : x, y: y};
16000 * Original code for Roojs - LGPL
16001 * <script type="text/javascript">
16005 * @class Roo.XComponent
16006 * A delayed Element creator...
16007 * Or a way to group chunks of interface together.
16008 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16009 * used in conjunction with XComponent.build() it will create an instance of each element,
16010 * then call addxtype() to build the User interface.
16012 * Mypart.xyx = new Roo.XComponent({
16014 parent : 'Mypart.xyz', // empty == document.element.!!
16018 disabled : function() {}
16020 tree : function() { // return an tree of xtype declared components
16024 xtype : 'NestedLayoutPanel',
16031 * It can be used to build a big heiracy, with parent etc.
16032 * or you can just use this to render a single compoent to a dom element
16033 * MYPART.render(Roo.Element | String(id) | dom_element )
16040 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16041 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16043 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16045 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16046 * - if mulitple topModules exist, the last one is defined as the top module.
16050 * When the top level or multiple modules are to embedded into a existing HTML page,
16051 * the parent element can container '#id' of the element where the module will be drawn.
16055 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16056 * it relies more on a include mechanism, where sub modules are included into an outer page.
16057 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16059 * Bootstrap Roo Included elements
16061 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16062 * hence confusing the component builder as it thinks there are multiple top level elements.
16064 * String Over-ride & Translations
16066 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16067 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16068 * are needed. @see Roo.XComponent.overlayString
16072 * @extends Roo.util.Observable
16074 * @param cfg {Object} configuration of component
16077 Roo.XComponent = function(cfg) {
16078 Roo.apply(this, cfg);
16082 * Fires when this the componnt is built
16083 * @param {Roo.XComponent} c the component
16088 this.region = this.region || 'center'; // default..
16089 Roo.XComponent.register(this);
16090 this.modules = false;
16091 this.el = false; // where the layout goes..
16095 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16098 * The created element (with Roo.factory())
16099 * @type {Roo.Layout}
16105 * for BC - use el in new code
16106 * @type {Roo.Layout}
16112 * for BC - use el in new code
16113 * @type {Roo.Layout}
16118 * @cfg {Function|boolean} disabled
16119 * If this module is disabled by some rule, return true from the funtion
16124 * @cfg {String} parent
16125 * Name of parent element which it get xtype added to..
16130 * @cfg {String} order
16131 * Used to set the order in which elements are created (usefull for multiple tabs)
16136 * @cfg {String} name
16137 * String to display while loading.
16141 * @cfg {String} region
16142 * Region to render component to (defaults to center)
16147 * @cfg {Array} items
16148 * A single item array - the first element is the root of the tree..
16149 * It's done this way to stay compatible with the Xtype system...
16155 * The method that retuns the tree of parts that make up this compoennt
16162 * render element to dom or tree
16163 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16166 render : function(el)
16170 var hp = this.parent ? 1 : 0;
16171 Roo.debug && Roo.log(this);
16173 var tree = this._tree ? this._tree() : this.tree();
16176 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16177 // if parent is a '#.....' string, then let's use that..
16178 var ename = this.parent.substr(1);
16179 this.parent = false;
16180 Roo.debug && Roo.log(ename);
16182 case 'bootstrap-body':
16183 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16184 // this is the BorderLayout standard?
16185 this.parent = { el : true };
16188 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16189 // need to insert stuff...
16191 el : new Roo.bootstrap.layout.Border({
16192 el : document.body,
16198 tabPosition: 'top',
16199 //resizeTabs: true,
16200 alwaysShowTabs: true,
16210 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16211 this.parent = { el : new Roo.bootstrap.Body() };
16212 Roo.debug && Roo.log("setting el to doc body");
16215 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16219 this.parent = { el : true};
16222 el = Roo.get(ename);
16223 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16224 this.parent = { el : true};
16231 if (!el && !this.parent) {
16232 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16237 Roo.debug && Roo.log("EL:");
16238 Roo.debug && Roo.log(el);
16239 Roo.debug && Roo.log("this.parent.el:");
16240 Roo.debug && Roo.log(this.parent.el);
16243 // altertive root elements ??? - we need a better way to indicate these.
16244 var is_alt = Roo.XComponent.is_alt ||
16245 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16246 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16247 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16251 if (!this.parent && is_alt) {
16252 //el = Roo.get(document.body);
16253 this.parent = { el : true };
16258 if (!this.parent) {
16260 Roo.debug && Roo.log("no parent - creating one");
16262 el = el ? Roo.get(el) : false;
16264 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16267 el : new Roo.bootstrap.layout.Border({
16268 el: el || document.body,
16274 tabPosition: 'top',
16275 //resizeTabs: true,
16276 alwaysShowTabs: false,
16279 overflow: 'visible'
16285 // it's a top level one..
16287 el : new Roo.BorderLayout(el || document.body, {
16292 tabPosition: 'top',
16293 //resizeTabs: true,
16294 alwaysShowTabs: el && hp? false : true,
16295 hideTabs: el || !hp ? true : false,
16303 if (!this.parent.el) {
16304 // probably an old style ctor, which has been disabled.
16308 // The 'tree' method is '_tree now'
16310 tree.region = tree.region || this.region;
16311 var is_body = false;
16312 if (this.parent.el === true) {
16313 // bootstrap... - body..
16317 this.parent.el = Roo.factory(tree);
16321 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16322 this.fireEvent('built', this);
16324 this.panel = this.el;
16325 this.layout = this.panel.layout;
16326 this.parentLayout = this.parent.layout || false;
16332 Roo.apply(Roo.XComponent, {
16334 * @property hideProgress
16335 * true to disable the building progress bar.. usefull on single page renders.
16338 hideProgress : false,
16340 * @property buildCompleted
16341 * True when the builder has completed building the interface.
16344 buildCompleted : false,
16347 * @property topModule
16348 * the upper most module - uses document.element as it's constructor.
16355 * @property modules
16356 * array of modules to be created by registration system.
16357 * @type {Array} of Roo.XComponent
16362 * @property elmodules
16363 * array of modules to be created by which use #ID
16364 * @type {Array} of Roo.XComponent
16371 * Is an alternative Root - normally used by bootstrap or other systems,
16372 * where the top element in the tree can wrap 'body'
16373 * @type {boolean} (default false)
16378 * @property build_from_html
16379 * Build elements from html - used by bootstrap HTML stuff
16380 * - this is cleared after build is completed
16381 * @type {boolean} (default false)
16384 build_from_html : false,
16386 * Register components to be built later.
16388 * This solves the following issues
16389 * - Building is not done on page load, but after an authentication process has occured.
16390 * - Interface elements are registered on page load
16391 * - Parent Interface elements may not be loaded before child, so this handles that..
16398 module : 'Pman.Tab.projectMgr',
16400 parent : 'Pman.layout',
16401 disabled : false, // or use a function..
16404 * * @param {Object} details about module
16406 register : function(obj) {
16408 Roo.XComponent.event.fireEvent('register', obj);
16409 switch(typeof(obj.disabled) ) {
16415 if ( obj.disabled() ) {
16421 if (obj.disabled) {
16427 this.modules.push(obj);
16431 * convert a string to an object..
16432 * eg. 'AAA.BBB' -> finds AAA.BBB
16436 toObject : function(str)
16438 if (!str || typeof(str) == 'object') {
16441 if (str.substring(0,1) == '#') {
16445 var ar = str.split('.');
16450 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16452 throw "Module not found : " + str;
16456 throw "Module not found : " + str;
16458 Roo.each(ar, function(e) {
16459 if (typeof(o[e]) == 'undefined') {
16460 throw "Module not found : " + str;
16471 * move modules into their correct place in the tree..
16474 preBuild : function ()
16477 Roo.each(this.modules , function (obj)
16479 Roo.XComponent.event.fireEvent('beforebuild', obj);
16481 var opar = obj.parent;
16483 obj.parent = this.toObject(opar);
16485 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16490 Roo.debug && Roo.log("GOT top level module");
16491 Roo.debug && Roo.log(obj);
16492 obj.modules = new Roo.util.MixedCollection(false,
16493 function(o) { return o.order + '' }
16495 this.topModule = obj;
16498 // parent is a string (usually a dom element name..)
16499 if (typeof(obj.parent) == 'string') {
16500 this.elmodules.push(obj);
16503 if (obj.parent.constructor != Roo.XComponent) {
16504 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16506 if (!obj.parent.modules) {
16507 obj.parent.modules = new Roo.util.MixedCollection(false,
16508 function(o) { return o.order + '' }
16511 if (obj.parent.disabled) {
16512 obj.disabled = true;
16514 obj.parent.modules.add(obj);
16519 * make a list of modules to build.
16520 * @return {Array} list of modules.
16523 buildOrder : function()
16526 var cmp = function(a,b) {
16527 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16529 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16530 throw "No top level modules to build";
16533 // make a flat list in order of modules to build.
16534 var mods = this.topModule ? [ this.topModule ] : [];
16537 // elmodules (is a list of DOM based modules )
16538 Roo.each(this.elmodules, function(e) {
16540 if (!this.topModule &&
16541 typeof(e.parent) == 'string' &&
16542 e.parent.substring(0,1) == '#' &&
16543 Roo.get(e.parent.substr(1))
16546 _this.topModule = e;
16552 // add modules to their parents..
16553 var addMod = function(m) {
16554 Roo.debug && Roo.log("build Order: add: " + m.name);
16557 if (m.modules && !m.disabled) {
16558 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16559 m.modules.keySort('ASC', cmp );
16560 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16562 m.modules.each(addMod);
16564 Roo.debug && Roo.log("build Order: no child modules");
16566 // not sure if this is used any more..
16568 m.finalize.name = m.name + " (clean up) ";
16569 mods.push(m.finalize);
16573 if (this.topModule && this.topModule.modules) {
16574 this.topModule.modules.keySort('ASC', cmp );
16575 this.topModule.modules.each(addMod);
16581 * Build the registered modules.
16582 * @param {Object} parent element.
16583 * @param {Function} optional method to call after module has been added.
16587 build : function(opts)
16590 if (typeof(opts) != 'undefined') {
16591 Roo.apply(this,opts);
16595 var mods = this.buildOrder();
16597 //this.allmods = mods;
16598 //Roo.debug && Roo.log(mods);
16600 if (!mods.length) { // should not happen
16601 throw "NO modules!!!";
16605 var msg = "Building Interface...";
16606 // flash it up as modal - so we store the mask!?
16607 if (!this.hideProgress && Roo.MessageBox) {
16608 Roo.MessageBox.show({ title: 'loading' });
16609 Roo.MessageBox.show({
16610 title: "Please wait...",
16620 var total = mods.length;
16623 var progressRun = function() {
16624 if (!mods.length) {
16625 Roo.debug && Roo.log('hide?');
16626 if (!this.hideProgress && Roo.MessageBox) {
16627 Roo.MessageBox.hide();
16629 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16631 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16637 var m = mods.shift();
16640 Roo.debug && Roo.log(m);
16641 // not sure if this is supported any more.. - modules that are are just function
16642 if (typeof(m) == 'function') {
16644 return progressRun.defer(10, _this);
16648 msg = "Building Interface " + (total - mods.length) +
16650 (m.name ? (' - ' + m.name) : '');
16651 Roo.debug && Roo.log(msg);
16652 if (!_this.hideProgress && Roo.MessageBox) {
16653 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16657 // is the module disabled?
16658 var disabled = (typeof(m.disabled) == 'function') ?
16659 m.disabled.call(m.module.disabled) : m.disabled;
16663 return progressRun(); // we do not update the display!
16671 // it's 10 on top level, and 1 on others??? why...
16672 return progressRun.defer(10, _this);
16675 progressRun.defer(1, _this);
16681 * Overlay a set of modified strings onto a component
16682 * This is dependant on our builder exporting the strings and 'named strings' elements.
16684 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16685 * @param {Object} associative array of 'named' string and it's new value.
16688 overlayStrings : function( component, strings )
16690 if (typeof(component['_named_strings']) == 'undefined') {
16691 throw "ERROR: component does not have _named_strings";
16693 for ( var k in strings ) {
16694 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16695 if (md !== false) {
16696 component['_strings'][md] = strings[k];
16698 Roo.log('could not find named string: ' + k + ' in');
16699 Roo.log(component);
16714 * wrapper for event.on - aliased later..
16715 * Typically use to register a event handler for register:
16717 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16726 Roo.XComponent.event = new Roo.util.Observable({
16730 * Fires when an Component is registered,
16731 * set the disable property on the Component to stop registration.
16732 * @param {Roo.XComponent} c the component being registerd.
16737 * @event beforebuild
16738 * Fires before each Component is built
16739 * can be used to apply permissions.
16740 * @param {Roo.XComponent} c the component being registerd.
16743 'beforebuild' : true,
16745 * @event buildcomplete
16746 * Fires on the top level element when all elements have been built
16747 * @param {Roo.XComponent} the top level component.
16749 'buildcomplete' : true
16754 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16757 * marked - a markdown parser
16758 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16759 * https://github.com/chjj/marked
16765 * Roo.Markdown - is a very crude wrapper around marked..
16769 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16771 * Note: move the sample code to the bottom of this
16772 * file before uncommenting it.
16777 Roo.Markdown.toHtml = function(text) {
16779 var c = new Roo.Markdown.marked.setOptions({
16780 renderer: new Roo.Markdown.marked.Renderer(),
16791 text = text.replace(/\\\n/g,' ');
16792 return Roo.Markdown.marked(text);
16797 // Wraps all "globals" so that the only thing
16798 // exposed is makeHtml().
16803 * Block-Level Grammar
16808 code: /^( {4}[^\n]+\n*)+/,
16810 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16811 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16813 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16814 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16815 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16816 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16817 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16819 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16823 block.bullet = /(?:[*+-]|\d+\.)/;
16824 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16825 block.item = replace(block.item, 'gm')
16826 (/bull/g, block.bullet)
16829 block.list = replace(block.list)
16830 (/bull/g, block.bullet)
16831 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16832 ('def', '\\n+(?=' + block.def.source + ')')
16835 block.blockquote = replace(block.blockquote)
16839 block._tag = '(?!(?:'
16840 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16841 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16842 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16844 block.html = replace(block.html)
16845 ('comment', /<!--[\s\S]*?-->/)
16846 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16847 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16848 (/tag/g, block._tag)
16851 block.paragraph = replace(block.paragraph)
16853 ('heading', block.heading)
16854 ('lheading', block.lheading)
16855 ('blockquote', block.blockquote)
16856 ('tag', '<' + block._tag)
16861 * Normal Block Grammar
16864 block.normal = merge({}, block);
16867 * GFM Block Grammar
16870 block.gfm = merge({}, block.normal, {
16871 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16873 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16876 block.gfm.paragraph = replace(block.paragraph)
16878 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16879 + block.list.source.replace('\\1', '\\3') + '|')
16883 * GFM + Tables Block Grammar
16886 block.tables = merge({}, block.gfm, {
16887 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16888 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16895 function Lexer(options) {
16897 this.tokens.links = {};
16898 this.options = options || marked.defaults;
16899 this.rules = block.normal;
16901 if (this.options.gfm) {
16902 if (this.options.tables) {
16903 this.rules = block.tables;
16905 this.rules = block.gfm;
16911 * Expose Block Rules
16914 Lexer.rules = block;
16917 * Static Lex Method
16920 Lexer.lex = function(src, options) {
16921 var lexer = new Lexer(options);
16922 return lexer.lex(src);
16929 Lexer.prototype.lex = function(src) {
16931 .replace(/\r\n|\r/g, '\n')
16932 .replace(/\t/g, ' ')
16933 .replace(/\u00a0/g, ' ')
16934 .replace(/\u2424/g, '\n');
16936 return this.token(src, true);
16943 Lexer.prototype.token = function(src, top, bq) {
16944 var src = src.replace(/^ +$/gm, '')
16957 if (cap = this.rules.newline.exec(src)) {
16958 src = src.substring(cap[0].length);
16959 if (cap[0].length > 1) {
16967 if (cap = this.rules.code.exec(src)) {
16968 src = src.substring(cap[0].length);
16969 cap = cap[0].replace(/^ {4}/gm, '');
16972 text: !this.options.pedantic
16973 ? cap.replace(/\n+$/, '')
16980 if (cap = this.rules.fences.exec(src)) {
16981 src = src.substring(cap[0].length);
16991 if (cap = this.rules.heading.exec(src)) {
16992 src = src.substring(cap[0].length);
16995 depth: cap[1].length,
17001 // table no leading pipe (gfm)
17002 if (top && (cap = this.rules.nptable.exec(src))) {
17003 src = src.substring(cap[0].length);
17007 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17008 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17009 cells: cap[3].replace(/\n$/, '').split('\n')
17012 for (i = 0; i < item.align.length; i++) {
17013 if (/^ *-+: *$/.test(item.align[i])) {
17014 item.align[i] = 'right';
17015 } else if (/^ *:-+: *$/.test(item.align[i])) {
17016 item.align[i] = 'center';
17017 } else if (/^ *:-+ *$/.test(item.align[i])) {
17018 item.align[i] = 'left';
17020 item.align[i] = null;
17024 for (i = 0; i < item.cells.length; i++) {
17025 item.cells[i] = item.cells[i].split(/ *\| */);
17028 this.tokens.push(item);
17034 if (cap = this.rules.lheading.exec(src)) {
17035 src = src.substring(cap[0].length);
17038 depth: cap[2] === '=' ? 1 : 2,
17045 if (cap = this.rules.hr.exec(src)) {
17046 src = src.substring(cap[0].length);
17054 if (cap = this.rules.blockquote.exec(src)) {
17055 src = src.substring(cap[0].length);
17058 type: 'blockquote_start'
17061 cap = cap[0].replace(/^ *> ?/gm, '');
17063 // Pass `top` to keep the current
17064 // "toplevel" state. This is exactly
17065 // how markdown.pl works.
17066 this.token(cap, top, true);
17069 type: 'blockquote_end'
17076 if (cap = this.rules.list.exec(src)) {
17077 src = src.substring(cap[0].length);
17081 type: 'list_start',
17082 ordered: bull.length > 1
17085 // Get each top-level item.
17086 cap = cap[0].match(this.rules.item);
17092 for (; i < l; i++) {
17095 // Remove the list item's bullet
17096 // so it is seen as the next token.
17097 space = item.length;
17098 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17100 // Outdent whatever the
17101 // list item contains. Hacky.
17102 if (~item.indexOf('\n ')) {
17103 space -= item.length;
17104 item = !this.options.pedantic
17105 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17106 : item.replace(/^ {1,4}/gm, '');
17109 // Determine whether the next list item belongs here.
17110 // Backpedal if it does not belong in this list.
17111 if (this.options.smartLists && i !== l - 1) {
17112 b = block.bullet.exec(cap[i + 1])[0];
17113 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17114 src = cap.slice(i + 1).join('\n') + src;
17119 // Determine whether item is loose or not.
17120 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17121 // for discount behavior.
17122 loose = next || /\n\n(?!\s*$)/.test(item);
17124 next = item.charAt(item.length - 1) === '\n';
17125 if (!loose) { loose = next; }
17130 ? 'loose_item_start'
17131 : 'list_item_start'
17135 this.token(item, false, bq);
17138 type: 'list_item_end'
17150 if (cap = this.rules.html.exec(src)) {
17151 src = src.substring(cap[0].length);
17153 type: this.options.sanitize
17156 pre: !this.options.sanitizer
17157 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17164 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17165 src = src.substring(cap[0].length);
17166 this.tokens.links[cap[1].toLowerCase()] = {
17174 if (top && (cap = this.rules.table.exec(src))) {
17175 src = src.substring(cap[0].length);
17179 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17180 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17181 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17184 for (i = 0; i < item.align.length; i++) {
17185 if (/^ *-+: *$/.test(item.align[i])) {
17186 item.align[i] = 'right';
17187 } else if (/^ *:-+: *$/.test(item.align[i])) {
17188 item.align[i] = 'center';
17189 } else if (/^ *:-+ *$/.test(item.align[i])) {
17190 item.align[i] = 'left';
17192 item.align[i] = null;
17196 for (i = 0; i < item.cells.length; i++) {
17197 item.cells[i] = item.cells[i]
17198 .replace(/^ *\| *| *\| *$/g, '')
17202 this.tokens.push(item);
17207 // top-level paragraph
17208 if (top && (cap = this.rules.paragraph.exec(src))) {
17209 src = src.substring(cap[0].length);
17212 text: cap[1].charAt(cap[1].length - 1) === '\n'
17213 ? cap[1].slice(0, -1)
17220 if (cap = this.rules.text.exec(src)) {
17221 // Top-level should never reach here.
17222 src = src.substring(cap[0].length);
17232 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17236 return this.tokens;
17240 * Inline-Level Grammar
17244 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17245 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17247 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17248 link: /^!?\[(inside)\]\(href\)/,
17249 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17250 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17251 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17252 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17253 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17254 br: /^ {2,}\n(?!\s*$)/,
17256 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17259 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17260 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17262 inline.link = replace(inline.link)
17263 ('inside', inline._inside)
17264 ('href', inline._href)
17267 inline.reflink = replace(inline.reflink)
17268 ('inside', inline._inside)
17272 * Normal Inline Grammar
17275 inline.normal = merge({}, inline);
17278 * Pedantic Inline Grammar
17281 inline.pedantic = merge({}, inline.normal, {
17282 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17283 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17287 * GFM Inline Grammar
17290 inline.gfm = merge({}, inline.normal, {
17291 escape: replace(inline.escape)('])', '~|])')(),
17292 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17293 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17294 text: replace(inline.text)
17296 ('|', '|https?://|')
17301 * GFM + Line Breaks Inline Grammar
17304 inline.breaks = merge({}, inline.gfm, {
17305 br: replace(inline.br)('{2,}', '*')(),
17306 text: replace(inline.gfm.text)('{2,}', '*')()
17310 * Inline Lexer & Compiler
17313 function InlineLexer(links, options) {
17314 this.options = options || marked.defaults;
17315 this.links = links;
17316 this.rules = inline.normal;
17317 this.renderer = this.options.renderer || new Renderer;
17318 this.renderer.options = this.options;
17322 Error('Tokens array requires a `links` property.');
17325 if (this.options.gfm) {
17326 if (this.options.breaks) {
17327 this.rules = inline.breaks;
17329 this.rules = inline.gfm;
17331 } else if (this.options.pedantic) {
17332 this.rules = inline.pedantic;
17337 * Expose Inline Rules
17340 InlineLexer.rules = inline;
17343 * Static Lexing/Compiling Method
17346 InlineLexer.output = function(src, links, options) {
17347 var inline = new InlineLexer(links, options);
17348 return inline.output(src);
17355 InlineLexer.prototype.output = function(src) {
17364 if (cap = this.rules.escape.exec(src)) {
17365 src = src.substring(cap[0].length);
17371 if (cap = this.rules.autolink.exec(src)) {
17372 src = src.substring(cap[0].length);
17373 if (cap[2] === '@') {
17374 text = cap[1].charAt(6) === ':'
17375 ? this.mangle(cap[1].substring(7))
17376 : this.mangle(cap[1]);
17377 href = this.mangle('mailto:') + text;
17379 text = escape(cap[1]);
17382 out += this.renderer.link(href, null, text);
17387 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17388 src = src.substring(cap[0].length);
17389 text = escape(cap[1]);
17391 out += this.renderer.link(href, null, text);
17396 if (cap = this.rules.tag.exec(src)) {
17397 if (!this.inLink && /^<a /i.test(cap[0])) {
17398 this.inLink = true;
17399 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17400 this.inLink = false;
17402 src = src.substring(cap[0].length);
17403 out += this.options.sanitize
17404 ? this.options.sanitizer
17405 ? this.options.sanitizer(cap[0])
17412 if (cap = this.rules.link.exec(src)) {
17413 src = src.substring(cap[0].length);
17414 this.inLink = true;
17415 out += this.outputLink(cap, {
17419 this.inLink = false;
17424 if ((cap = this.rules.reflink.exec(src))
17425 || (cap = this.rules.nolink.exec(src))) {
17426 src = src.substring(cap[0].length);
17427 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17428 link = this.links[link.toLowerCase()];
17429 if (!link || !link.href) {
17430 out += cap[0].charAt(0);
17431 src = cap[0].substring(1) + src;
17434 this.inLink = true;
17435 out += this.outputLink(cap, link);
17436 this.inLink = false;
17441 if (cap = this.rules.strong.exec(src)) {
17442 src = src.substring(cap[0].length);
17443 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17448 if (cap = this.rules.em.exec(src)) {
17449 src = src.substring(cap[0].length);
17450 out += this.renderer.em(this.output(cap[2] || cap[1]));
17455 if (cap = this.rules.code.exec(src)) {
17456 src = src.substring(cap[0].length);
17457 out += this.renderer.codespan(escape(cap[2], true));
17462 if (cap = this.rules.br.exec(src)) {
17463 src = src.substring(cap[0].length);
17464 out += this.renderer.br();
17469 if (cap = this.rules.del.exec(src)) {
17470 src = src.substring(cap[0].length);
17471 out += this.renderer.del(this.output(cap[1]));
17476 if (cap = this.rules.text.exec(src)) {
17477 src = src.substring(cap[0].length);
17478 out += this.renderer.text(escape(this.smartypants(cap[0])));
17484 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17495 InlineLexer.prototype.outputLink = function(cap, link) {
17496 var href = escape(link.href)
17497 , title = link.title ? escape(link.title) : null;
17499 return cap[0].charAt(0) !== '!'
17500 ? this.renderer.link(href, title, this.output(cap[1]))
17501 : this.renderer.image(href, title, escape(cap[1]));
17505 * Smartypants Transformations
17508 InlineLexer.prototype.smartypants = function(text) {
17509 if (!this.options.smartypants) { return text; }
17512 .replace(/---/g, '\u2014')
17514 .replace(/--/g, '\u2013')
17516 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17517 // closing singles & apostrophes
17518 .replace(/'/g, '\u2019')
17520 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17522 .replace(/"/g, '\u201d')
17524 .replace(/\.{3}/g, '\u2026');
17531 InlineLexer.prototype.mangle = function(text) {
17532 if (!this.options.mangle) { return text; }
17538 for (; i < l; i++) {
17539 ch = text.charCodeAt(i);
17540 if (Math.random() > 0.5) {
17541 ch = 'x' + ch.toString(16);
17543 out += '&#' + ch + ';';
17553 function Renderer(options) {
17554 this.options = options || {};
17557 Renderer.prototype.code = function(code, lang, escaped) {
17558 if (this.options.highlight) {
17559 var out = this.options.highlight(code, lang);
17560 if (out != null && out !== code) {
17565 // hack!!! - it's already escapeD?
17570 return '<pre><code>'
17571 + (escaped ? code : escape(code, true))
17572 + '\n</code></pre>';
17575 return '<pre><code class="'
17576 + this.options.langPrefix
17577 + escape(lang, true)
17579 + (escaped ? code : escape(code, true))
17580 + '\n</code></pre>\n';
17583 Renderer.prototype.blockquote = function(quote) {
17584 return '<blockquote>\n' + quote + '</blockquote>\n';
17587 Renderer.prototype.html = function(html) {
17591 Renderer.prototype.heading = function(text, level, raw) {
17595 + this.options.headerPrefix
17596 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17604 Renderer.prototype.hr = function() {
17605 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17608 Renderer.prototype.list = function(body, ordered) {
17609 var type = ordered ? 'ol' : 'ul';
17610 return '<' + type + '>\n' + body + '</' + type + '>\n';
17613 Renderer.prototype.listitem = function(text) {
17614 return '<li>' + text + '</li>\n';
17617 Renderer.prototype.paragraph = function(text) {
17618 return '<p>' + text + '</p>\n';
17621 Renderer.prototype.table = function(header, body) {
17622 return '<table class="table table-striped">\n'
17632 Renderer.prototype.tablerow = function(content) {
17633 return '<tr>\n' + content + '</tr>\n';
17636 Renderer.prototype.tablecell = function(content, flags) {
17637 var type = flags.header ? 'th' : 'td';
17638 var tag = flags.align
17639 ? '<' + type + ' style="text-align:' + flags.align + '">'
17640 : '<' + type + '>';
17641 return tag + content + '</' + type + '>\n';
17644 // span level renderer
17645 Renderer.prototype.strong = function(text) {
17646 return '<strong>' + text + '</strong>';
17649 Renderer.prototype.em = function(text) {
17650 return '<em>' + text + '</em>';
17653 Renderer.prototype.codespan = function(text) {
17654 return '<code>' + text + '</code>';
17657 Renderer.prototype.br = function() {
17658 return this.options.xhtml ? '<br/>' : '<br>';
17661 Renderer.prototype.del = function(text) {
17662 return '<del>' + text + '</del>';
17665 Renderer.prototype.link = function(href, title, text) {
17666 if (this.options.sanitize) {
17668 var prot = decodeURIComponent(unescape(href))
17669 .replace(/[^\w:]/g, '')
17674 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17678 var out = '<a href="' + href + '"';
17680 out += ' title="' + title + '"';
17682 out += '>' + text + '</a>';
17686 Renderer.prototype.image = function(href, title, text) {
17687 var out = '<img src="' + href + '" alt="' + text + '"';
17689 out += ' title="' + title + '"';
17691 out += this.options.xhtml ? '/>' : '>';
17695 Renderer.prototype.text = function(text) {
17700 * Parsing & Compiling
17703 function Parser(options) {
17706 this.options = options || marked.defaults;
17707 this.options.renderer = this.options.renderer || new Renderer;
17708 this.renderer = this.options.renderer;
17709 this.renderer.options = this.options;
17713 * Static Parse Method
17716 Parser.parse = function(src, options, renderer) {
17717 var parser = new Parser(options, renderer);
17718 return parser.parse(src);
17725 Parser.prototype.parse = function(src) {
17726 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17727 this.tokens = src.reverse();
17730 while (this.next()) {
17741 Parser.prototype.next = function() {
17742 return this.token = this.tokens.pop();
17746 * Preview Next Token
17749 Parser.prototype.peek = function() {
17750 return this.tokens[this.tokens.length - 1] || 0;
17754 * Parse Text Tokens
17757 Parser.prototype.parseText = function() {
17758 var body = this.token.text;
17760 while (this.peek().type === 'text') {
17761 body += '\n' + this.next().text;
17764 return this.inline.output(body);
17768 * Parse Current Token
17771 Parser.prototype.tok = function() {
17772 switch (this.token.type) {
17777 return this.renderer.hr();
17780 return this.renderer.heading(
17781 this.inline.output(this.token.text),
17786 return this.renderer.code(this.token.text,
17788 this.token.escaped);
17801 for (i = 0; i < this.token.header.length; i++) {
17802 flags = { header: true, align: this.token.align[i] };
17803 cell += this.renderer.tablecell(
17804 this.inline.output(this.token.header[i]),
17805 { header: true, align: this.token.align[i] }
17808 header += this.renderer.tablerow(cell);
17810 for (i = 0; i < this.token.cells.length; i++) {
17811 row = this.token.cells[i];
17814 for (j = 0; j < row.length; j++) {
17815 cell += this.renderer.tablecell(
17816 this.inline.output(row[j]),
17817 { header: false, align: this.token.align[j] }
17821 body += this.renderer.tablerow(cell);
17823 return this.renderer.table(header, body);
17825 case 'blockquote_start': {
17828 while (this.next().type !== 'blockquote_end') {
17829 body += this.tok();
17832 return this.renderer.blockquote(body);
17834 case 'list_start': {
17836 , ordered = this.token.ordered;
17838 while (this.next().type !== 'list_end') {
17839 body += this.tok();
17842 return this.renderer.list(body, ordered);
17844 case 'list_item_start': {
17847 while (this.next().type !== 'list_item_end') {
17848 body += this.token.type === 'text'
17853 return this.renderer.listitem(body);
17855 case 'loose_item_start': {
17858 while (this.next().type !== 'list_item_end') {
17859 body += this.tok();
17862 return this.renderer.listitem(body);
17865 var html = !this.token.pre && !this.options.pedantic
17866 ? this.inline.output(this.token.text)
17868 return this.renderer.html(html);
17870 case 'paragraph': {
17871 return this.renderer.paragraph(this.inline.output(this.token.text));
17874 return this.renderer.paragraph(this.parseText());
17883 function escape(html, encode) {
17885 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17886 .replace(/</g, '<')
17887 .replace(/>/g, '>')
17888 .replace(/"/g, '"')
17889 .replace(/'/g, ''');
17892 function unescape(html) {
17893 // explicitly match decimal, hex, and named HTML entities
17894 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17895 n = n.toLowerCase();
17896 if (n === 'colon') { return ':'; }
17897 if (n.charAt(0) === '#') {
17898 return n.charAt(1) === 'x'
17899 ? String.fromCharCode(parseInt(n.substring(2), 16))
17900 : String.fromCharCode(+n.substring(1));
17906 function replace(regex, opt) {
17907 regex = regex.source;
17909 return function self(name, val) {
17910 if (!name) { return new RegExp(regex, opt); }
17911 val = val.source || val;
17912 val = val.replace(/(^|[^\[])\^/g, '$1');
17913 regex = regex.replace(name, val);
17921 function merge(obj) {
17926 for (; i < arguments.length; i++) {
17927 target = arguments[i];
17928 for (key in target) {
17929 if (Object.prototype.hasOwnProperty.call(target, key)) {
17930 obj[key] = target[key];
17943 function marked(src, opt, callback) {
17944 if (callback || typeof opt === 'function') {
17950 opt = merge({}, marked.defaults, opt || {});
17952 var highlight = opt.highlight
17958 tokens = Lexer.lex(src, opt)
17960 return callback(e);
17963 pending = tokens.length;
17965 var done = function(err) {
17967 opt.highlight = highlight;
17968 return callback(err);
17974 out = Parser.parse(tokens, opt);
17979 opt.highlight = highlight;
17983 : callback(null, out);
17986 if (!highlight || highlight.length < 3) {
17990 delete opt.highlight;
17992 if (!pending) { return done(); }
17994 for (; i < tokens.length; i++) {
17996 if (token.type !== 'code') {
17997 return --pending || done();
17999 return highlight(token.text, token.lang, function(err, code) {
18000 if (err) { return done(err); }
18001 if (code == null || code === token.text) {
18002 return --pending || done();
18005 token.escaped = true;
18006 --pending || done();
18014 if (opt) { opt = merge({}, marked.defaults, opt); }
18015 return Parser.parse(Lexer.lex(src, opt), opt);
18017 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18018 if ((opt || marked.defaults).silent) {
18019 return '<p>An error occured:</p><pre>'
18020 + escape(e.message + '', true)
18032 marked.setOptions = function(opt) {
18033 merge(marked.defaults, opt);
18037 marked.defaults = {
18048 langPrefix: 'lang-',
18049 smartypants: false,
18051 renderer: new Renderer,
18059 marked.Parser = Parser;
18060 marked.parser = Parser.parse;
18062 marked.Renderer = Renderer;
18064 marked.Lexer = Lexer;
18065 marked.lexer = Lexer.lex;
18067 marked.InlineLexer = InlineLexer;
18068 marked.inlineLexer = InlineLexer.output;
18070 marked.parse = marked;
18072 Roo.Markdown.marked = marked;
18076 * Ext JS Library 1.1.1
18077 * Copyright(c) 2006-2007, Ext JS, LLC.
18079 * Originally Released Under LGPL - original licence link has changed is not relivant.
18082 * <script type="text/javascript">
18088 * These classes are derivatives of the similarly named classes in the YUI Library.
18089 * The original license:
18090 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18091 * Code licensed under the BSD License:
18092 * http://developer.yahoo.net/yui/license.txt
18097 var Event=Roo.EventManager;
18098 var Dom=Roo.lib.Dom;
18101 * @class Roo.dd.DragDrop
18102 * @extends Roo.util.Observable
18103 * Defines the interface and base operation of items that that can be
18104 * dragged or can be drop targets. It was designed to be extended, overriding
18105 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18106 * Up to three html elements can be associated with a DragDrop instance:
18108 * <li>linked element: the element that is passed into the constructor.
18109 * This is the element which defines the boundaries for interaction with
18110 * other DragDrop objects.</li>
18111 * <li>handle element(s): The drag operation only occurs if the element that
18112 * was clicked matches a handle element. By default this is the linked
18113 * element, but there are times that you will want only a portion of the
18114 * linked element to initiate the drag operation, and the setHandleElId()
18115 * method provides a way to define this.</li>
18116 * <li>drag element: this represents the element that would be moved along
18117 * with the cursor during a drag operation. By default, this is the linked
18118 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18119 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18122 * This class should not be instantiated until the onload event to ensure that
18123 * the associated elements are available.
18124 * The following would define a DragDrop obj that would interact with any
18125 * other DragDrop obj in the "group1" group:
18127 * dd = new Roo.dd.DragDrop("div1", "group1");
18129 * Since none of the event handlers have been implemented, nothing would
18130 * actually happen if you were to run the code above. Normally you would
18131 * override this class or one of the default implementations, but you can
18132 * also override the methods you want on an instance of the class...
18134 * dd.onDragDrop = function(e, id) {
18135 * alert("dd was dropped on " + id);
18139 * @param {String} id of the element that is linked to this instance
18140 * @param {String} sGroup the group of related DragDrop objects
18141 * @param {object} config an object containing configurable attributes
18142 * Valid properties for DragDrop:
18143 * padding, isTarget, maintainOffset, primaryButtonOnly
18145 Roo.dd.DragDrop = function(id, sGroup, config) {
18147 this.init(id, sGroup, config);
18152 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18155 * The id of the element associated with this object. This is what we
18156 * refer to as the "linked element" because the size and position of
18157 * this element is used to determine when the drag and drop objects have
18165 * Configuration attributes passed into the constructor
18172 * The id of the element that will be dragged. By default this is same
18173 * as the linked element , but could be changed to another element. Ex:
18175 * @property dragElId
18182 * the id of the element that initiates the drag operation. By default
18183 * this is the linked element, but could be changed to be a child of this
18184 * element. This lets us do things like only starting the drag when the
18185 * header element within the linked html element is clicked.
18186 * @property handleElId
18193 * An associative array of HTML tags that will be ignored if clicked.
18194 * @property invalidHandleTypes
18195 * @type {string: string}
18197 invalidHandleTypes: null,
18200 * An associative array of ids for elements that will be ignored if clicked
18201 * @property invalidHandleIds
18202 * @type {string: string}
18204 invalidHandleIds: null,
18207 * An indexted array of css class names for elements that will be ignored
18209 * @property invalidHandleClasses
18212 invalidHandleClasses: null,
18215 * The linked element's absolute X position at the time the drag was
18217 * @property startPageX
18224 * The linked element's absolute X position at the time the drag was
18226 * @property startPageY
18233 * The group defines a logical collection of DragDrop objects that are
18234 * related. Instances only get events when interacting with other
18235 * DragDrop object in the same group. This lets us define multiple
18236 * groups using a single DragDrop subclass if we want.
18238 * @type {string: string}
18243 * Individual drag/drop instances can be locked. This will prevent
18244 * onmousedown start drag.
18252 * Lock this instance
18255 lock: function() { this.locked = true; },
18258 * Unlock this instace
18261 unlock: function() { this.locked = false; },
18264 * By default, all insances can be a drop target. This can be disabled by
18265 * setting isTarget to false.
18272 * The padding configured for this drag and drop object for calculating
18273 * the drop zone intersection with this object.
18280 * Cached reference to the linked element
18281 * @property _domRef
18287 * Internal typeof flag
18288 * @property __ygDragDrop
18291 __ygDragDrop: true,
18294 * Set to true when horizontal contraints are applied
18295 * @property constrainX
18302 * Set to true when vertical contraints are applied
18303 * @property constrainY
18310 * The left constraint
18318 * The right constraint
18326 * The up constraint
18335 * The down constraint
18343 * Maintain offsets when we resetconstraints. Set to true when you want
18344 * the position of the element relative to its parent to stay the same
18345 * when the page changes
18347 * @property maintainOffset
18350 maintainOffset: false,
18353 * Array of pixel locations the element will snap to if we specified a
18354 * horizontal graduation/interval. This array is generated automatically
18355 * when you define a tick interval.
18362 * Array of pixel locations the element will snap to if we specified a
18363 * vertical graduation/interval. This array is generated automatically
18364 * when you define a tick interval.
18371 * By default the drag and drop instance will only respond to the primary
18372 * button click (left button for a right-handed mouse). Set to true to
18373 * allow drag and drop to start with any mouse click that is propogated
18375 * @property primaryButtonOnly
18378 primaryButtonOnly: true,
18381 * The availabe property is false until the linked dom element is accessible.
18382 * @property available
18388 * By default, drags can only be initiated if the mousedown occurs in the
18389 * region the linked element is. This is done in part to work around a
18390 * bug in some browsers that mis-report the mousedown if the previous
18391 * mouseup happened outside of the window. This property is set to true
18392 * if outer handles are defined.
18394 * @property hasOuterHandles
18398 hasOuterHandles: false,
18401 * Code that executes immediately before the startDrag event
18402 * @method b4StartDrag
18405 b4StartDrag: function(x, y) { },
18408 * Abstract method called after a drag/drop object is clicked
18409 * and the drag or mousedown time thresholds have beeen met.
18410 * @method startDrag
18411 * @param {int} X click location
18412 * @param {int} Y click location
18414 startDrag: function(x, y) { /* override this */ },
18417 * Code that executes immediately before the onDrag event
18421 b4Drag: function(e) { },
18424 * Abstract method called during the onMouseMove event while dragging an
18427 * @param {Event} e the mousemove event
18429 onDrag: function(e) { /* override this */ },
18432 * Abstract method called when this element fist begins hovering over
18433 * another DragDrop obj
18434 * @method onDragEnter
18435 * @param {Event} e the mousemove event
18436 * @param {String|DragDrop[]} id In POINT mode, the element
18437 * id this is hovering over. In INTERSECT mode, an array of one or more
18438 * dragdrop items being hovered over.
18440 onDragEnter: function(e, id) { /* override this */ },
18443 * Code that executes immediately before the onDragOver event
18444 * @method b4DragOver
18447 b4DragOver: function(e) { },
18450 * Abstract method called when this element is hovering over another
18452 * @method onDragOver
18453 * @param {Event} e the mousemove event
18454 * @param {String|DragDrop[]} id In POINT mode, the element
18455 * id this is hovering over. In INTERSECT mode, an array of dd items
18456 * being hovered over.
18458 onDragOver: function(e, id) { /* override this */ },
18461 * Code that executes immediately before the onDragOut event
18462 * @method b4DragOut
18465 b4DragOut: function(e) { },
18468 * Abstract method called when we are no longer hovering over an element
18469 * @method onDragOut
18470 * @param {Event} e the mousemove event
18471 * @param {String|DragDrop[]} id In POINT mode, the element
18472 * id this was hovering over. In INTERSECT mode, an array of dd items
18473 * that the mouse is no longer over.
18475 onDragOut: function(e, id) { /* override this */ },
18478 * Code that executes immediately before the onDragDrop event
18479 * @method b4DragDrop
18482 b4DragDrop: function(e) { },
18485 * Abstract method called when this item is dropped on another DragDrop
18487 * @method onDragDrop
18488 * @param {Event} e the mouseup event
18489 * @param {String|DragDrop[]} id In POINT mode, the element
18490 * id this was dropped on. In INTERSECT mode, an array of dd items this
18493 onDragDrop: function(e, id) { /* override this */ },
18496 * Abstract method called when this item is dropped on an area with no
18498 * @method onInvalidDrop
18499 * @param {Event} e the mouseup event
18501 onInvalidDrop: function(e) { /* override this */ },
18504 * Code that executes immediately before the endDrag event
18505 * @method b4EndDrag
18508 b4EndDrag: function(e) { },
18511 * Fired when we are done dragging the object
18513 * @param {Event} e the mouseup event
18515 endDrag: function(e) { /* override this */ },
18518 * Code executed immediately before the onMouseDown event
18519 * @method b4MouseDown
18520 * @param {Event} e the mousedown event
18523 b4MouseDown: function(e) { },
18526 * Event handler that fires when a drag/drop obj gets a mousedown
18527 * @method onMouseDown
18528 * @param {Event} e the mousedown event
18530 onMouseDown: function(e) { /* override this */ },
18533 * Event handler that fires when a drag/drop obj gets a mouseup
18534 * @method onMouseUp
18535 * @param {Event} e the mouseup event
18537 onMouseUp: function(e) { /* override this */ },
18540 * Override the onAvailable method to do what is needed after the initial
18541 * position was determined.
18542 * @method onAvailable
18544 onAvailable: function () {
18548 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18551 defaultPadding : {left:0, right:0, top:0, bottom:0},
18554 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18558 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18559 { dragElId: "existingProxyDiv" });
18560 dd.startDrag = function(){
18561 this.constrainTo("parent-id");
18564 * Or you can initalize it using the {@link Roo.Element} object:
18566 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18567 startDrag : function(){
18568 this.constrainTo("parent-id");
18572 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18573 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18574 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18575 * an object containing the sides to pad. For example: {right:10, bottom:10}
18576 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18578 constrainTo : function(constrainTo, pad, inContent){
18579 if(typeof pad == "number"){
18580 pad = {left: pad, right:pad, top:pad, bottom:pad};
18582 pad = pad || this.defaultPadding;
18583 var b = Roo.get(this.getEl()).getBox();
18584 var ce = Roo.get(constrainTo);
18585 var s = ce.getScroll();
18586 var c, cd = ce.dom;
18587 if(cd == document.body){
18588 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18591 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18595 var topSpace = b.y - c.y;
18596 var leftSpace = b.x - c.x;
18598 this.resetConstraints();
18599 this.setXConstraint(leftSpace - (pad.left||0), // left
18600 c.width - leftSpace - b.width - (pad.right||0) //right
18602 this.setYConstraint(topSpace - (pad.top||0), //top
18603 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18608 * Returns a reference to the linked element
18610 * @return {HTMLElement} the html element
18612 getEl: function() {
18613 if (!this._domRef) {
18614 this._domRef = Roo.getDom(this.id);
18617 return this._domRef;
18621 * Returns a reference to the actual element to drag. By default this is
18622 * the same as the html element, but it can be assigned to another
18623 * element. An example of this can be found in Roo.dd.DDProxy
18624 * @method getDragEl
18625 * @return {HTMLElement} the html element
18627 getDragEl: function() {
18628 return Roo.getDom(this.dragElId);
18632 * Sets up the DragDrop object. Must be called in the constructor of any
18633 * Roo.dd.DragDrop subclass
18635 * @param id the id of the linked element
18636 * @param {String} sGroup the group of related items
18637 * @param {object} config configuration attributes
18639 init: function(id, sGroup, config) {
18640 this.initTarget(id, sGroup, config);
18641 if (!Roo.isTouch) {
18642 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18644 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18645 // Event.on(this.id, "selectstart", Event.preventDefault);
18649 * Initializes Targeting functionality only... the object does not
18650 * get a mousedown handler.
18651 * @method initTarget
18652 * @param id the id of the linked element
18653 * @param {String} sGroup the group of related items
18654 * @param {object} config configuration attributes
18656 initTarget: function(id, sGroup, config) {
18658 // configuration attributes
18659 this.config = config || {};
18661 // create a local reference to the drag and drop manager
18662 this.DDM = Roo.dd.DDM;
18663 // initialize the groups array
18666 // assume that we have an element reference instead of an id if the
18667 // parameter is not a string
18668 if (typeof id !== "string") {
18675 // add to an interaction group
18676 this.addToGroup((sGroup) ? sGroup : "default");
18678 // We don't want to register this as the handle with the manager
18679 // so we just set the id rather than calling the setter.
18680 this.handleElId = id;
18682 // the linked element is the element that gets dragged by default
18683 this.setDragElId(id);
18685 // by default, clicked anchors will not start drag operations.
18686 this.invalidHandleTypes = { A: "A" };
18687 this.invalidHandleIds = {};
18688 this.invalidHandleClasses = [];
18690 this.applyConfig();
18692 this.handleOnAvailable();
18696 * Applies the configuration parameters that were passed into the constructor.
18697 * This is supposed to happen at each level through the inheritance chain. So
18698 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18699 * DragDrop in order to get all of the parameters that are available in
18701 * @method applyConfig
18703 applyConfig: function() {
18705 // configurable properties:
18706 // padding, isTarget, maintainOffset, primaryButtonOnly
18707 this.padding = this.config.padding || [0, 0, 0, 0];
18708 this.isTarget = (this.config.isTarget !== false);
18709 this.maintainOffset = (this.config.maintainOffset);
18710 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18715 * Executed when the linked element is available
18716 * @method handleOnAvailable
18719 handleOnAvailable: function() {
18720 this.available = true;
18721 this.resetConstraints();
18722 this.onAvailable();
18726 * Configures the padding for the target zone in px. Effectively expands
18727 * (or reduces) the virtual object size for targeting calculations.
18728 * Supports css-style shorthand; if only one parameter is passed, all sides
18729 * will have that padding, and if only two are passed, the top and bottom
18730 * will have the first param, the left and right the second.
18731 * @method setPadding
18732 * @param {int} iTop Top pad
18733 * @param {int} iRight Right pad
18734 * @param {int} iBot Bot pad
18735 * @param {int} iLeft Left pad
18737 setPadding: function(iTop, iRight, iBot, iLeft) {
18738 // this.padding = [iLeft, iRight, iTop, iBot];
18739 if (!iRight && 0 !== iRight) {
18740 this.padding = [iTop, iTop, iTop, iTop];
18741 } else if (!iBot && 0 !== iBot) {
18742 this.padding = [iTop, iRight, iTop, iRight];
18744 this.padding = [iTop, iRight, iBot, iLeft];
18749 * Stores the initial placement of the linked element.
18750 * @method setInitialPosition
18751 * @param {int} diffX the X offset, default 0
18752 * @param {int} diffY the Y offset, default 0
18754 setInitPosition: function(diffX, diffY) {
18755 var el = this.getEl();
18757 if (!this.DDM.verifyEl(el)) {
18761 var dx = diffX || 0;
18762 var dy = diffY || 0;
18764 var p = Dom.getXY( el );
18766 this.initPageX = p[0] - dx;
18767 this.initPageY = p[1] - dy;
18769 this.lastPageX = p[0];
18770 this.lastPageY = p[1];
18773 this.setStartPosition(p);
18777 * Sets the start position of the element. This is set when the obj
18778 * is initialized, the reset when a drag is started.
18779 * @method setStartPosition
18780 * @param pos current position (from previous lookup)
18783 setStartPosition: function(pos) {
18784 var p = pos || Dom.getXY( this.getEl() );
18785 this.deltaSetXY = null;
18787 this.startPageX = p[0];
18788 this.startPageY = p[1];
18792 * Add this instance to a group of related drag/drop objects. All
18793 * instances belong to at least one group, and can belong to as many
18794 * groups as needed.
18795 * @method addToGroup
18796 * @param sGroup {string} the name of the group
18798 addToGroup: function(sGroup) {
18799 this.groups[sGroup] = true;
18800 this.DDM.regDragDrop(this, sGroup);
18804 * Remove's this instance from the supplied interaction group
18805 * @method removeFromGroup
18806 * @param {string} sGroup The group to drop
18808 removeFromGroup: function(sGroup) {
18809 if (this.groups[sGroup]) {
18810 delete this.groups[sGroup];
18813 this.DDM.removeDDFromGroup(this, sGroup);
18817 * Allows you to specify that an element other than the linked element
18818 * will be moved with the cursor during a drag
18819 * @method setDragElId
18820 * @param id {string} the id of the element that will be used to initiate the drag
18822 setDragElId: function(id) {
18823 this.dragElId = id;
18827 * Allows you to specify a child of the linked element that should be
18828 * used to initiate the drag operation. An example of this would be if
18829 * you have a content div with text and links. Clicking anywhere in the
18830 * content area would normally start the drag operation. Use this method
18831 * to specify that an element inside of the content div is the element
18832 * that starts the drag operation.
18833 * @method setHandleElId
18834 * @param id {string} the id of the element that will be used to
18835 * initiate the drag.
18837 setHandleElId: function(id) {
18838 if (typeof id !== "string") {
18841 this.handleElId = id;
18842 this.DDM.regHandle(this.id, id);
18846 * Allows you to set an element outside of the linked element as a drag
18848 * @method setOuterHandleElId
18849 * @param id the id of the element that will be used to initiate the drag
18851 setOuterHandleElId: function(id) {
18852 if (typeof id !== "string") {
18855 Event.on(id, "mousedown",
18856 this.handleMouseDown, this);
18857 this.setHandleElId(id);
18859 this.hasOuterHandles = true;
18863 * Remove all drag and drop hooks for this element
18866 unreg: function() {
18867 Event.un(this.id, "mousedown",
18868 this.handleMouseDown);
18869 Event.un(this.id, "touchstart",
18870 this.handleMouseDown);
18871 this._domRef = null;
18872 this.DDM._remove(this);
18875 destroy : function(){
18880 * Returns true if this instance is locked, or the drag drop mgr is locked
18881 * (meaning that all drag/drop is disabled on the page.)
18883 * @return {boolean} true if this obj or all drag/drop is locked, else
18886 isLocked: function() {
18887 return (this.DDM.isLocked() || this.locked);
18891 * Fired when this object is clicked
18892 * @method handleMouseDown
18894 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18897 handleMouseDown: function(e, oDD){
18899 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18900 //Roo.log('not touch/ button !=0');
18903 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18904 return; // double touch..
18908 if (this.isLocked()) {
18909 //Roo.log('locked');
18913 this.DDM.refreshCache(this.groups);
18914 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18915 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18916 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18917 //Roo.log('no outer handes or not over target');
18920 // Roo.log('check validator');
18921 if (this.clickValidator(e)) {
18922 // Roo.log('validate success');
18923 // set the initial element position
18924 this.setStartPosition();
18927 this.b4MouseDown(e);
18928 this.onMouseDown(e);
18930 this.DDM.handleMouseDown(e, this);
18932 this.DDM.stopEvent(e);
18940 clickValidator: function(e) {
18941 var target = e.getTarget();
18942 return ( this.isValidHandleChild(target) &&
18943 (this.id == this.handleElId ||
18944 this.DDM.handleWasClicked(target, this.id)) );
18948 * Allows you to specify a tag name that should not start a drag operation
18949 * when clicked. This is designed to facilitate embedding links within a
18950 * drag handle that do something other than start the drag.
18951 * @method addInvalidHandleType
18952 * @param {string} tagName the type of element to exclude
18954 addInvalidHandleType: function(tagName) {
18955 var type = tagName.toUpperCase();
18956 this.invalidHandleTypes[type] = type;
18960 * Lets you to specify an element id for a child of a drag handle
18961 * that should not initiate a drag
18962 * @method addInvalidHandleId
18963 * @param {string} id the element id of the element you wish to ignore
18965 addInvalidHandleId: function(id) {
18966 if (typeof id !== "string") {
18969 this.invalidHandleIds[id] = id;
18973 * Lets you specify a css class of elements that will not initiate a drag
18974 * @method addInvalidHandleClass
18975 * @param {string} cssClass the class of the elements you wish to ignore
18977 addInvalidHandleClass: function(cssClass) {
18978 this.invalidHandleClasses.push(cssClass);
18982 * Unsets an excluded tag name set by addInvalidHandleType
18983 * @method removeInvalidHandleType
18984 * @param {string} tagName the type of element to unexclude
18986 removeInvalidHandleType: function(tagName) {
18987 var type = tagName.toUpperCase();
18988 // this.invalidHandleTypes[type] = null;
18989 delete this.invalidHandleTypes[type];
18993 * Unsets an invalid handle id
18994 * @method removeInvalidHandleId
18995 * @param {string} id the id of the element to re-enable
18997 removeInvalidHandleId: function(id) {
18998 if (typeof id !== "string") {
19001 delete this.invalidHandleIds[id];
19005 * Unsets an invalid css class
19006 * @method removeInvalidHandleClass
19007 * @param {string} cssClass the class of the element(s) you wish to
19010 removeInvalidHandleClass: function(cssClass) {
19011 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19012 if (this.invalidHandleClasses[i] == cssClass) {
19013 delete this.invalidHandleClasses[i];
19019 * Checks the tag exclusion list to see if this click should be ignored
19020 * @method isValidHandleChild
19021 * @param {HTMLElement} node the HTMLElement to evaluate
19022 * @return {boolean} true if this is a valid tag type, false if not
19024 isValidHandleChild: function(node) {
19027 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19030 nodeName = node.nodeName.toUpperCase();
19032 nodeName = node.nodeName;
19034 valid = valid && !this.invalidHandleTypes[nodeName];
19035 valid = valid && !this.invalidHandleIds[node.id];
19037 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19038 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19047 * Create the array of horizontal tick marks if an interval was specified
19048 * in setXConstraint().
19049 * @method setXTicks
19052 setXTicks: function(iStartX, iTickSize) {
19054 this.xTickSize = iTickSize;
19058 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19060 this.xTicks[this.xTicks.length] = i;
19065 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19067 this.xTicks[this.xTicks.length] = i;
19072 this.xTicks.sort(this.DDM.numericSort) ;
19076 * Create the array of vertical tick marks if an interval was specified in
19077 * setYConstraint().
19078 * @method setYTicks
19081 setYTicks: function(iStartY, iTickSize) {
19083 this.yTickSize = iTickSize;
19087 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19089 this.yTicks[this.yTicks.length] = i;
19094 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19096 this.yTicks[this.yTicks.length] = i;
19101 this.yTicks.sort(this.DDM.numericSort) ;
19105 * By default, the element can be dragged any place on the screen. Use
19106 * this method to limit the horizontal travel of the element. Pass in
19107 * 0,0 for the parameters if you want to lock the drag to the y axis.
19108 * @method setXConstraint
19109 * @param {int} iLeft the number of pixels the element can move to the left
19110 * @param {int} iRight the number of pixels the element can move to the
19112 * @param {int} iTickSize optional parameter for specifying that the
19114 * should move iTickSize pixels at a time.
19116 setXConstraint: function(iLeft, iRight, iTickSize) {
19117 this.leftConstraint = iLeft;
19118 this.rightConstraint = iRight;
19120 this.minX = this.initPageX - iLeft;
19121 this.maxX = this.initPageX + iRight;
19122 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19124 this.constrainX = true;
19128 * Clears any constraints applied to this instance. Also clears ticks
19129 * since they can't exist independent of a constraint at this time.
19130 * @method clearConstraints
19132 clearConstraints: function() {
19133 this.constrainX = false;
19134 this.constrainY = false;
19139 * Clears any tick interval defined for this instance
19140 * @method clearTicks
19142 clearTicks: function() {
19143 this.xTicks = null;
19144 this.yTicks = null;
19145 this.xTickSize = 0;
19146 this.yTickSize = 0;
19150 * By default, the element can be dragged any place on the screen. Set
19151 * this to limit the vertical travel of the element. Pass in 0,0 for the
19152 * parameters if you want to lock the drag to the x axis.
19153 * @method setYConstraint
19154 * @param {int} iUp the number of pixels the element can move up
19155 * @param {int} iDown the number of pixels the element can move down
19156 * @param {int} iTickSize optional parameter for specifying that the
19157 * element should move iTickSize pixels at a time.
19159 setYConstraint: function(iUp, iDown, iTickSize) {
19160 this.topConstraint = iUp;
19161 this.bottomConstraint = iDown;
19163 this.minY = this.initPageY - iUp;
19164 this.maxY = this.initPageY + iDown;
19165 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19167 this.constrainY = true;
19172 * resetConstraints must be called if you manually reposition a dd element.
19173 * @method resetConstraints
19174 * @param {boolean} maintainOffset
19176 resetConstraints: function() {
19179 // Maintain offsets if necessary
19180 if (this.initPageX || this.initPageX === 0) {
19181 // figure out how much this thing has moved
19182 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19183 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19185 this.setInitPosition(dx, dy);
19187 // This is the first time we have detected the element's position
19189 this.setInitPosition();
19192 if (this.constrainX) {
19193 this.setXConstraint( this.leftConstraint,
19194 this.rightConstraint,
19198 if (this.constrainY) {
19199 this.setYConstraint( this.topConstraint,
19200 this.bottomConstraint,
19206 * Normally the drag element is moved pixel by pixel, but we can specify
19207 * that it move a number of pixels at a time. This method resolves the
19208 * location when we have it set up like this.
19210 * @param {int} val where we want to place the object
19211 * @param {int[]} tickArray sorted array of valid points
19212 * @return {int} the closest tick
19215 getTick: function(val, tickArray) {
19218 // If tick interval is not defined, it is effectively 1 pixel,
19219 // so we return the value passed to us.
19221 } else if (tickArray[0] >= val) {
19222 // The value is lower than the first tick, so we return the first
19224 return tickArray[0];
19226 for (var i=0, len=tickArray.length; i<len; ++i) {
19228 if (tickArray[next] && tickArray[next] >= val) {
19229 var diff1 = val - tickArray[i];
19230 var diff2 = tickArray[next] - val;
19231 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19235 // The value is larger than the last tick, so we return the last
19237 return tickArray[tickArray.length - 1];
19244 * @return {string} string representation of the dd obj
19246 toString: function() {
19247 return ("DragDrop " + this.id);
19255 * Ext JS Library 1.1.1
19256 * Copyright(c) 2006-2007, Ext JS, LLC.
19258 * Originally Released Under LGPL - original licence link has changed is not relivant.
19261 * <script type="text/javascript">
19266 * The drag and drop utility provides a framework for building drag and drop
19267 * applications. In addition to enabling drag and drop for specific elements,
19268 * the drag and drop elements are tracked by the manager class, and the
19269 * interactions between the various elements are tracked during the drag and
19270 * the implementing code is notified about these important moments.
19273 // Only load the library once. Rewriting the manager class would orphan
19274 // existing drag and drop instances.
19275 if (!Roo.dd.DragDropMgr) {
19278 * @class Roo.dd.DragDropMgr
19279 * DragDropMgr is a singleton that tracks the element interaction for
19280 * all DragDrop items in the window. Generally, you will not call
19281 * this class directly, but it does have helper methods that could
19282 * be useful in your DragDrop implementations.
19285 Roo.dd.DragDropMgr = function() {
19287 var Event = Roo.EventManager;
19292 * Two dimensional Array of registered DragDrop objects. The first
19293 * dimension is the DragDrop item group, the second the DragDrop
19296 * @type {string: string}
19303 * Array of element ids defined as drag handles. Used to determine
19304 * if the element that generated the mousedown event is actually the
19305 * handle and not the html element itself.
19306 * @property handleIds
19307 * @type {string: string}
19314 * the DragDrop object that is currently being dragged
19315 * @property dragCurrent
19323 * the DragDrop object(s) that are being hovered over
19324 * @property dragOvers
19332 * the X distance between the cursor and the object being dragged
19341 * the Y distance between the cursor and the object being dragged
19350 * Flag to determine if we should prevent the default behavior of the
19351 * events we define. By default this is true, but this can be set to
19352 * false if you need the default behavior (not recommended)
19353 * @property preventDefault
19357 preventDefault: true,
19360 * Flag to determine if we should stop the propagation of the events
19361 * we generate. This is true by default but you may want to set it to
19362 * false if the html element contains other features that require the
19364 * @property stopPropagation
19368 stopPropagation: true,
19371 * Internal flag that is set to true when drag and drop has been
19373 * @property initialized
19380 * All drag and drop can be disabled.
19388 * Called the first time an element is registered.
19394 this.initialized = true;
19398 * In point mode, drag and drop interaction is defined by the
19399 * location of the cursor during the drag/drop
19407 * In intersect mode, drag and drop interactio nis defined by the
19408 * overlap of two or more drag and drop objects.
19409 * @property INTERSECT
19416 * The current drag and drop mode. Default: POINT
19424 * Runs method on all drag and drop objects
19425 * @method _execOnAll
19429 _execOnAll: function(sMethod, args) {
19430 for (var i in this.ids) {
19431 for (var j in this.ids[i]) {
19432 var oDD = this.ids[i][j];
19433 if (! this.isTypeOfDD(oDD)) {
19436 oDD[sMethod].apply(oDD, args);
19442 * Drag and drop initialization. Sets up the global event handlers
19447 _onLoad: function() {
19451 if (!Roo.isTouch) {
19452 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19453 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19455 Event.on(document, "touchend", this.handleMouseUp, this, true);
19456 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19458 Event.on(window, "unload", this._onUnload, this, true);
19459 Event.on(window, "resize", this._onResize, this, true);
19460 // Event.on(window, "mouseout", this._test);
19465 * Reset constraints on all drag and drop objs
19466 * @method _onResize
19470 _onResize: function(e) {
19471 this._execOnAll("resetConstraints", []);
19475 * Lock all drag and drop functionality
19479 lock: function() { this.locked = true; },
19482 * Unlock all drag and drop functionality
19486 unlock: function() { this.locked = false; },
19489 * Is drag and drop locked?
19491 * @return {boolean} True if drag and drop is locked, false otherwise.
19494 isLocked: function() { return this.locked; },
19497 * Location cache that is set for all drag drop objects when a drag is
19498 * initiated, cleared when the drag is finished.
19499 * @property locationCache
19506 * Set useCache to false if you want to force object the lookup of each
19507 * drag and drop linked element constantly during a drag.
19508 * @property useCache
19515 * The number of pixels that the mouse needs to move after the
19516 * mousedown before the drag is initiated. Default=3;
19517 * @property clickPixelThresh
19521 clickPixelThresh: 3,
19524 * The number of milliseconds after the mousedown event to initiate the
19525 * drag if we don't get a mouseup event. Default=1000
19526 * @property clickTimeThresh
19530 clickTimeThresh: 350,
19533 * Flag that indicates that either the drag pixel threshold or the
19534 * mousdown time threshold has been met
19535 * @property dragThreshMet
19540 dragThreshMet: false,
19543 * Timeout used for the click time threshold
19544 * @property clickTimeout
19549 clickTimeout: null,
19552 * The X position of the mousedown event stored for later use when a
19553 * drag threshold is met.
19562 * The Y position of the mousedown event stored for later use when a
19563 * drag threshold is met.
19572 * Each DragDrop instance must be registered with the DragDropMgr.
19573 * This is executed in DragDrop.init()
19574 * @method regDragDrop
19575 * @param {DragDrop} oDD the DragDrop object to register
19576 * @param {String} sGroup the name of the group this element belongs to
19579 regDragDrop: function(oDD, sGroup) {
19580 if (!this.initialized) { this.init(); }
19582 if (!this.ids[sGroup]) {
19583 this.ids[sGroup] = {};
19585 this.ids[sGroup][oDD.id] = oDD;
19589 * Removes the supplied dd instance from the supplied group. Executed
19590 * by DragDrop.removeFromGroup, so don't call this function directly.
19591 * @method removeDDFromGroup
19595 removeDDFromGroup: function(oDD, sGroup) {
19596 if (!this.ids[sGroup]) {
19597 this.ids[sGroup] = {};
19600 var obj = this.ids[sGroup];
19601 if (obj && obj[oDD.id]) {
19602 delete obj[oDD.id];
19607 * Unregisters a drag and drop item. This is executed in
19608 * DragDrop.unreg, use that method instead of calling this directly.
19613 _remove: function(oDD) {
19614 for (var g in oDD.groups) {
19615 if (g && this.ids[g][oDD.id]) {
19616 delete this.ids[g][oDD.id];
19619 delete this.handleIds[oDD.id];
19623 * Each DragDrop handle element must be registered. This is done
19624 * automatically when executing DragDrop.setHandleElId()
19625 * @method regHandle
19626 * @param {String} sDDId the DragDrop id this element is a handle for
19627 * @param {String} sHandleId the id of the element that is the drag
19631 regHandle: function(sDDId, sHandleId) {
19632 if (!this.handleIds[sDDId]) {
19633 this.handleIds[sDDId] = {};
19635 this.handleIds[sDDId][sHandleId] = sHandleId;
19639 * Utility function to determine if a given element has been
19640 * registered as a drag drop item.
19641 * @method isDragDrop
19642 * @param {String} id the element id to check
19643 * @return {boolean} true if this element is a DragDrop item,
19647 isDragDrop: function(id) {
19648 return ( this.getDDById(id) ) ? true : false;
19652 * Returns the drag and drop instances that are in all groups the
19653 * passed in instance belongs to.
19654 * @method getRelated
19655 * @param {DragDrop} p_oDD the obj to get related data for
19656 * @param {boolean} bTargetsOnly if true, only return targetable objs
19657 * @return {DragDrop[]} the related instances
19660 getRelated: function(p_oDD, bTargetsOnly) {
19662 for (var i in p_oDD.groups) {
19663 for (j in this.ids[i]) {
19664 var dd = this.ids[i][j];
19665 if (! this.isTypeOfDD(dd)) {
19668 if (!bTargetsOnly || dd.isTarget) {
19669 oDDs[oDDs.length] = dd;
19678 * Returns true if the specified dd target is a legal target for
19679 * the specifice drag obj
19680 * @method isLegalTarget
19681 * @param {DragDrop} the drag obj
19682 * @param {DragDrop} the target
19683 * @return {boolean} true if the target is a legal target for the
19687 isLegalTarget: function (oDD, oTargetDD) {
19688 var targets = this.getRelated(oDD, true);
19689 for (var i=0, len=targets.length;i<len;++i) {
19690 if (targets[i].id == oTargetDD.id) {
19699 * My goal is to be able to transparently determine if an object is
19700 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19701 * returns "object", oDD.constructor.toString() always returns
19702 * "DragDrop" and not the name of the subclass. So for now it just
19703 * evaluates a well-known variable in DragDrop.
19704 * @method isTypeOfDD
19705 * @param {Object} the object to evaluate
19706 * @return {boolean} true if typeof oDD = DragDrop
19709 isTypeOfDD: function (oDD) {
19710 return (oDD && oDD.__ygDragDrop);
19714 * Utility function to determine if a given element has been
19715 * registered as a drag drop handle for the given Drag Drop object.
19717 * @param {String} id the element id to check
19718 * @return {boolean} true if this element is a DragDrop handle, false
19722 isHandle: function(sDDId, sHandleId) {
19723 return ( this.handleIds[sDDId] &&
19724 this.handleIds[sDDId][sHandleId] );
19728 * Returns the DragDrop instance for a given id
19729 * @method getDDById
19730 * @param {String} id the id of the DragDrop object
19731 * @return {DragDrop} the drag drop object, null if it is not found
19734 getDDById: function(id) {
19735 for (var i in this.ids) {
19736 if (this.ids[i][id]) {
19737 return this.ids[i][id];
19744 * Fired after a registered DragDrop object gets the mousedown event.
19745 * Sets up the events required to track the object being dragged
19746 * @method handleMouseDown
19747 * @param {Event} e the event
19748 * @param oDD the DragDrop object being dragged
19752 handleMouseDown: function(e, oDD) {
19754 Roo.QuickTips.disable();
19756 this.currentTarget = e.getTarget();
19758 this.dragCurrent = oDD;
19760 var el = oDD.getEl();
19762 // track start position
19763 this.startX = e.getPageX();
19764 this.startY = e.getPageY();
19766 this.deltaX = this.startX - el.offsetLeft;
19767 this.deltaY = this.startY - el.offsetTop;
19769 this.dragThreshMet = false;
19771 this.clickTimeout = setTimeout(
19773 var DDM = Roo.dd.DDM;
19774 DDM.startDrag(DDM.startX, DDM.startY);
19776 this.clickTimeThresh );
19780 * Fired when either the drag pixel threshol or the mousedown hold
19781 * time threshold has been met.
19782 * @method startDrag
19783 * @param x {int} the X position of the original mousedown
19784 * @param y {int} the Y position of the original mousedown
19787 startDrag: function(x, y) {
19788 clearTimeout(this.clickTimeout);
19789 if (this.dragCurrent) {
19790 this.dragCurrent.b4StartDrag(x, y);
19791 this.dragCurrent.startDrag(x, y);
19793 this.dragThreshMet = true;
19797 * Internal function to handle the mouseup event. Will be invoked
19798 * from the context of the document.
19799 * @method handleMouseUp
19800 * @param {Event} e the event
19804 handleMouseUp: function(e) {
19807 Roo.QuickTips.enable();
19809 if (! this.dragCurrent) {
19813 clearTimeout(this.clickTimeout);
19815 if (this.dragThreshMet) {
19816 this.fireEvents(e, true);
19826 * Utility to stop event propagation and event default, if these
19827 * features are turned on.
19828 * @method stopEvent
19829 * @param {Event} e the event as returned by this.getEvent()
19832 stopEvent: function(e){
19833 if(this.stopPropagation) {
19834 e.stopPropagation();
19837 if (this.preventDefault) {
19838 e.preventDefault();
19843 * Internal function to clean up event handlers after the drag
19844 * operation is complete
19846 * @param {Event} e the event
19850 stopDrag: function(e) {
19851 // Fire the drag end event for the item that was dragged
19852 if (this.dragCurrent) {
19853 if (this.dragThreshMet) {
19854 this.dragCurrent.b4EndDrag(e);
19855 this.dragCurrent.endDrag(e);
19858 this.dragCurrent.onMouseUp(e);
19861 this.dragCurrent = null;
19862 this.dragOvers = {};
19866 * Internal function to handle the mousemove event. Will be invoked
19867 * from the context of the html element.
19869 * @TODO figure out what we can do about mouse events lost when the
19870 * user drags objects beyond the window boundary. Currently we can
19871 * detect this in internet explorer by verifying that the mouse is
19872 * down during the mousemove event. Firefox doesn't give us the
19873 * button state on the mousemove event.
19874 * @method handleMouseMove
19875 * @param {Event} e the event
19879 handleMouseMove: function(e) {
19880 if (! this.dragCurrent) {
19884 // var button = e.which || e.button;
19886 // check for IE mouseup outside of page boundary
19887 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19889 return this.handleMouseUp(e);
19892 if (!this.dragThreshMet) {
19893 var diffX = Math.abs(this.startX - e.getPageX());
19894 var diffY = Math.abs(this.startY - e.getPageY());
19895 if (diffX > this.clickPixelThresh ||
19896 diffY > this.clickPixelThresh) {
19897 this.startDrag(this.startX, this.startY);
19901 if (this.dragThreshMet) {
19902 this.dragCurrent.b4Drag(e);
19903 this.dragCurrent.onDrag(e);
19904 if(!this.dragCurrent.moveOnly){
19905 this.fireEvents(e, false);
19915 * Iterates over all of the DragDrop elements to find ones we are
19916 * hovering over or dropping on
19917 * @method fireEvents
19918 * @param {Event} e the event
19919 * @param {boolean} isDrop is this a drop op or a mouseover op?
19923 fireEvents: function(e, isDrop) {
19924 var dc = this.dragCurrent;
19926 // If the user did the mouse up outside of the window, we could
19927 // get here even though we have ended the drag.
19928 if (!dc || dc.isLocked()) {
19932 var pt = e.getPoint();
19934 // cache the previous dragOver array
19940 var enterEvts = [];
19942 // Check to see if the object(s) we were hovering over is no longer
19943 // being hovered over so we can fire the onDragOut event
19944 for (var i in this.dragOvers) {
19946 var ddo = this.dragOvers[i];
19948 if (! this.isTypeOfDD(ddo)) {
19952 if (! this.isOverTarget(pt, ddo, this.mode)) {
19953 outEvts.push( ddo );
19956 oldOvers[i] = true;
19957 delete this.dragOvers[i];
19960 for (var sGroup in dc.groups) {
19962 if ("string" != typeof sGroup) {
19966 for (i in this.ids[sGroup]) {
19967 var oDD = this.ids[sGroup][i];
19968 if (! this.isTypeOfDD(oDD)) {
19972 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19973 if (this.isOverTarget(pt, oDD, this.mode)) {
19974 // look for drop interactions
19976 dropEvts.push( oDD );
19977 // look for drag enter and drag over interactions
19980 // initial drag over: dragEnter fires
19981 if (!oldOvers[oDD.id]) {
19982 enterEvts.push( oDD );
19983 // subsequent drag overs: dragOver fires
19985 overEvts.push( oDD );
19988 this.dragOvers[oDD.id] = oDD;
19996 if (outEvts.length) {
19997 dc.b4DragOut(e, outEvts);
19998 dc.onDragOut(e, outEvts);
20001 if (enterEvts.length) {
20002 dc.onDragEnter(e, enterEvts);
20005 if (overEvts.length) {
20006 dc.b4DragOver(e, overEvts);
20007 dc.onDragOver(e, overEvts);
20010 if (dropEvts.length) {
20011 dc.b4DragDrop(e, dropEvts);
20012 dc.onDragDrop(e, dropEvts);
20016 // fire dragout events
20018 for (i=0, len=outEvts.length; i<len; ++i) {
20019 dc.b4DragOut(e, outEvts[i].id);
20020 dc.onDragOut(e, outEvts[i].id);
20023 // fire enter events
20024 for (i=0,len=enterEvts.length; i<len; ++i) {
20025 // dc.b4DragEnter(e, oDD.id);
20026 dc.onDragEnter(e, enterEvts[i].id);
20029 // fire over events
20030 for (i=0,len=overEvts.length; i<len; ++i) {
20031 dc.b4DragOver(e, overEvts[i].id);
20032 dc.onDragOver(e, overEvts[i].id);
20035 // fire drop events
20036 for (i=0, len=dropEvts.length; i<len; ++i) {
20037 dc.b4DragDrop(e, dropEvts[i].id);
20038 dc.onDragDrop(e, dropEvts[i].id);
20043 // notify about a drop that did not find a target
20044 if (isDrop && !dropEvts.length) {
20045 dc.onInvalidDrop(e);
20051 * Helper function for getting the best match from the list of drag
20052 * and drop objects returned by the drag and drop events when we are
20053 * in INTERSECT mode. It returns either the first object that the
20054 * cursor is over, or the object that has the greatest overlap with
20055 * the dragged element.
20056 * @method getBestMatch
20057 * @param {DragDrop[]} dds The array of drag and drop objects
20059 * @return {DragDrop} The best single match
20062 getBestMatch: function(dds) {
20064 // Return null if the input is not what we expect
20065 //if (!dds || !dds.length || dds.length == 0) {
20067 // If there is only one item, it wins
20068 //} else if (dds.length == 1) {
20070 var len = dds.length;
20075 // Loop through the targeted items
20076 for (var i=0; i<len; ++i) {
20078 // If the cursor is over the object, it wins. If the
20079 // cursor is over multiple matches, the first one we come
20081 if (dd.cursorIsOver) {
20084 // Otherwise the object with the most overlap wins
20087 winner.overlap.getArea() < dd.overlap.getArea()) {
20098 * Refreshes the cache of the top-left and bottom-right points of the
20099 * drag and drop objects in the specified group(s). This is in the
20100 * format that is stored in the drag and drop instance, so typical
20103 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20107 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20109 * @TODO this really should be an indexed array. Alternatively this
20110 * method could accept both.
20111 * @method refreshCache
20112 * @param {Object} groups an associative array of groups to refresh
20115 refreshCache: function(groups) {
20116 for (var sGroup in groups) {
20117 if ("string" != typeof sGroup) {
20120 for (var i in this.ids[sGroup]) {
20121 var oDD = this.ids[sGroup][i];
20123 if (this.isTypeOfDD(oDD)) {
20124 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20125 var loc = this.getLocation(oDD);
20127 this.locationCache[oDD.id] = loc;
20129 delete this.locationCache[oDD.id];
20130 // this will unregister the drag and drop object if
20131 // the element is not in a usable state
20140 * This checks to make sure an element exists and is in the DOM. The
20141 * main purpose is to handle cases where innerHTML is used to remove
20142 * drag and drop objects from the DOM. IE provides an 'unspecified
20143 * error' when trying to access the offsetParent of such an element
20145 * @param {HTMLElement} el the element to check
20146 * @return {boolean} true if the element looks usable
20149 verifyEl: function(el) {
20154 parent = el.offsetParent;
20157 parent = el.offsetParent;
20168 * Returns a Region object containing the drag and drop element's position
20169 * and size, including the padding configured for it
20170 * @method getLocation
20171 * @param {DragDrop} oDD the drag and drop object to get the
20173 * @return {Roo.lib.Region} a Region object representing the total area
20174 * the element occupies, including any padding
20175 * the instance is configured for.
20178 getLocation: function(oDD) {
20179 if (! this.isTypeOfDD(oDD)) {
20183 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20186 pos= Roo.lib.Dom.getXY(el);
20194 x2 = x1 + el.offsetWidth;
20196 y2 = y1 + el.offsetHeight;
20198 t = y1 - oDD.padding[0];
20199 r = x2 + oDD.padding[1];
20200 b = y2 + oDD.padding[2];
20201 l = x1 - oDD.padding[3];
20203 return new Roo.lib.Region( t, r, b, l );
20207 * Checks the cursor location to see if it over the target
20208 * @method isOverTarget
20209 * @param {Roo.lib.Point} pt The point to evaluate
20210 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20211 * @return {boolean} true if the mouse is over the target
20215 isOverTarget: function(pt, oTarget, intersect) {
20216 // use cache if available
20217 var loc = this.locationCache[oTarget.id];
20218 if (!loc || !this.useCache) {
20219 loc = this.getLocation(oTarget);
20220 this.locationCache[oTarget.id] = loc;
20228 oTarget.cursorIsOver = loc.contains( pt );
20230 // DragDrop is using this as a sanity check for the initial mousedown
20231 // in this case we are done. In POINT mode, if the drag obj has no
20232 // contraints, we are also done. Otherwise we need to evaluate the
20233 // location of the target as related to the actual location of the
20234 // dragged element.
20235 var dc = this.dragCurrent;
20236 if (!dc || !dc.getTargetCoord ||
20237 (!intersect && !dc.constrainX && !dc.constrainY)) {
20238 return oTarget.cursorIsOver;
20241 oTarget.overlap = null;
20243 // Get the current location of the drag element, this is the
20244 // location of the mouse event less the delta that represents
20245 // where the original mousedown happened on the element. We
20246 // need to consider constraints and ticks as well.
20247 var pos = dc.getTargetCoord(pt.x, pt.y);
20249 var el = dc.getDragEl();
20250 var curRegion = new Roo.lib.Region( pos.y,
20251 pos.x + el.offsetWidth,
20252 pos.y + el.offsetHeight,
20255 var overlap = curRegion.intersect(loc);
20258 oTarget.overlap = overlap;
20259 return (intersect) ? true : oTarget.cursorIsOver;
20266 * unload event handler
20267 * @method _onUnload
20271 _onUnload: function(e, me) {
20272 Roo.dd.DragDropMgr.unregAll();
20276 * Cleans up the drag and drop events and objects.
20281 unregAll: function() {
20283 if (this.dragCurrent) {
20285 this.dragCurrent = null;
20288 this._execOnAll("unreg", []);
20290 for (i in this.elementCache) {
20291 delete this.elementCache[i];
20294 this.elementCache = {};
20299 * A cache of DOM elements
20300 * @property elementCache
20307 * Get the wrapper for the DOM element specified
20308 * @method getElWrapper
20309 * @param {String} id the id of the element to get
20310 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20312 * @deprecated This wrapper isn't that useful
20315 getElWrapper: function(id) {
20316 var oWrapper = this.elementCache[id];
20317 if (!oWrapper || !oWrapper.el) {
20318 oWrapper = this.elementCache[id] =
20319 new this.ElementWrapper(Roo.getDom(id));
20325 * Returns the actual DOM element
20326 * @method getElement
20327 * @param {String} id the id of the elment to get
20328 * @return {Object} The element
20329 * @deprecated use Roo.getDom instead
20332 getElement: function(id) {
20333 return Roo.getDom(id);
20337 * Returns the style property for the DOM element (i.e.,
20338 * document.getElById(id).style)
20340 * @param {String} id the id of the elment to get
20341 * @return {Object} The style property of the element
20342 * @deprecated use Roo.getDom instead
20345 getCss: function(id) {
20346 var el = Roo.getDom(id);
20347 return (el) ? el.style : null;
20351 * Inner class for cached elements
20352 * @class DragDropMgr.ElementWrapper
20357 ElementWrapper: function(el) {
20362 this.el = el || null;
20367 this.id = this.el && el.id;
20369 * A reference to the style property
20372 this.css = this.el && el.style;
20376 * Returns the X position of an html element
20378 * @param el the element for which to get the position
20379 * @return {int} the X coordinate
20381 * @deprecated use Roo.lib.Dom.getX instead
20384 getPosX: function(el) {
20385 return Roo.lib.Dom.getX(el);
20389 * Returns the Y position of an html element
20391 * @param el the element for which to get the position
20392 * @return {int} the Y coordinate
20393 * @deprecated use Roo.lib.Dom.getY instead
20396 getPosY: function(el) {
20397 return Roo.lib.Dom.getY(el);
20401 * Swap two nodes. In IE, we use the native method, for others we
20402 * emulate the IE behavior
20404 * @param n1 the first node to swap
20405 * @param n2 the other node to swap
20408 swapNode: function(n1, n2) {
20412 var p = n2.parentNode;
20413 var s = n2.nextSibling;
20416 p.insertBefore(n1, n2);
20417 } else if (n2 == n1.nextSibling) {
20418 p.insertBefore(n2, n1);
20420 n1.parentNode.replaceChild(n2, n1);
20421 p.insertBefore(n1, s);
20427 * Returns the current scroll position
20428 * @method getScroll
20432 getScroll: function () {
20433 var t, l, dde=document.documentElement, db=document.body;
20434 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20436 l = dde.scrollLeft;
20443 return { top: t, left: l };
20447 * Returns the specified element style property
20449 * @param {HTMLElement} el the element
20450 * @param {string} styleProp the style property
20451 * @return {string} The value of the style property
20452 * @deprecated use Roo.lib.Dom.getStyle
20455 getStyle: function(el, styleProp) {
20456 return Roo.fly(el).getStyle(styleProp);
20460 * Gets the scrollTop
20461 * @method getScrollTop
20462 * @return {int} the document's scrollTop
20465 getScrollTop: function () { return this.getScroll().top; },
20468 * Gets the scrollLeft
20469 * @method getScrollLeft
20470 * @return {int} the document's scrollTop
20473 getScrollLeft: function () { return this.getScroll().left; },
20476 * Sets the x/y position of an element to the location of the
20479 * @param {HTMLElement} moveEl The element to move
20480 * @param {HTMLElement} targetEl The position reference element
20483 moveToEl: function (moveEl, targetEl) {
20484 var aCoord = Roo.lib.Dom.getXY(targetEl);
20485 Roo.lib.Dom.setXY(moveEl, aCoord);
20489 * Numeric array sort function
20490 * @method numericSort
20493 numericSort: function(a, b) { return (a - b); },
20497 * @property _timeoutCount
20504 * Trying to make the load order less important. Without this we get
20505 * an error if this file is loaded before the Event Utility.
20506 * @method _addListeners
20510 _addListeners: function() {
20511 var DDM = Roo.dd.DDM;
20512 if ( Roo.lib.Event && document ) {
20515 if (DDM._timeoutCount > 2000) {
20517 setTimeout(DDM._addListeners, 10);
20518 if (document && document.body) {
20519 DDM._timeoutCount += 1;
20526 * Recursively searches the immediate parent and all child nodes for
20527 * the handle element in order to determine wheter or not it was
20529 * @method handleWasClicked
20530 * @param node the html element to inspect
20533 handleWasClicked: function(node, id) {
20534 if (this.isHandle(id, node.id)) {
20537 // check to see if this is a text node child of the one we want
20538 var p = node.parentNode;
20541 if (this.isHandle(id, p.id)) {
20556 // shorter alias, save a few bytes
20557 Roo.dd.DDM = Roo.dd.DragDropMgr;
20558 Roo.dd.DDM._addListeners();
20562 * Ext JS Library 1.1.1
20563 * Copyright(c) 2006-2007, Ext JS, LLC.
20565 * Originally Released Under LGPL - original licence link has changed is not relivant.
20568 * <script type="text/javascript">
20573 * A DragDrop implementation where the linked element follows the
20574 * mouse cursor during a drag.
20575 * @extends Roo.dd.DragDrop
20577 * @param {String} id the id of the linked element
20578 * @param {String} sGroup the group of related DragDrop items
20579 * @param {object} config an object containing configurable attributes
20580 * Valid properties for DD:
20583 Roo.dd.DD = function(id, sGroup, config) {
20585 this.init(id, sGroup, config);
20589 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20592 * When set to true, the utility automatically tries to scroll the browser
20593 * window wehn a drag and drop element is dragged near the viewport boundary.
20594 * Defaults to true.
20601 * Sets the pointer offset to the distance between the linked element's top
20602 * left corner and the location the element was clicked
20603 * @method autoOffset
20604 * @param {int} iPageX the X coordinate of the click
20605 * @param {int} iPageY the Y coordinate of the click
20607 autoOffset: function(iPageX, iPageY) {
20608 var x = iPageX - this.startPageX;
20609 var y = iPageY - this.startPageY;
20610 this.setDelta(x, y);
20614 * Sets the pointer offset. You can call this directly to force the
20615 * offset to be in a particular location (e.g., pass in 0,0 to set it
20616 * to the center of the object)
20618 * @param {int} iDeltaX the distance from the left
20619 * @param {int} iDeltaY the distance from the top
20621 setDelta: function(iDeltaX, iDeltaY) {
20622 this.deltaX = iDeltaX;
20623 this.deltaY = iDeltaY;
20627 * Sets the drag element to the location of the mousedown or click event,
20628 * maintaining the cursor location relative to the location on the element
20629 * that was clicked. Override this if you want to place the element in a
20630 * location other than where the cursor is.
20631 * @method setDragElPos
20632 * @param {int} iPageX the X coordinate of the mousedown or drag event
20633 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20635 setDragElPos: function(iPageX, iPageY) {
20636 // the first time we do this, we are going to check to make sure
20637 // the element has css positioning
20639 var el = this.getDragEl();
20640 this.alignElWithMouse(el, iPageX, iPageY);
20644 * Sets the element to the location of the mousedown or click event,
20645 * maintaining the cursor location relative to the location on the element
20646 * that was clicked. Override this if you want to place the element in a
20647 * location other than where the cursor is.
20648 * @method alignElWithMouse
20649 * @param {HTMLElement} el the element to move
20650 * @param {int} iPageX the X coordinate of the mousedown or drag event
20651 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20653 alignElWithMouse: function(el, iPageX, iPageY) {
20654 var oCoord = this.getTargetCoord(iPageX, iPageY);
20655 var fly = el.dom ? el : Roo.fly(el);
20656 if (!this.deltaSetXY) {
20657 var aCoord = [oCoord.x, oCoord.y];
20659 var newLeft = fly.getLeft(true);
20660 var newTop = fly.getTop(true);
20661 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20663 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20666 this.cachePosition(oCoord.x, oCoord.y);
20667 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20672 * Saves the most recent position so that we can reset the constraints and
20673 * tick marks on-demand. We need to know this so that we can calculate the
20674 * number of pixels the element is offset from its original position.
20675 * @method cachePosition
20676 * @param iPageX the current x position (optional, this just makes it so we
20677 * don't have to look it up again)
20678 * @param iPageY the current y position (optional, this just makes it so we
20679 * don't have to look it up again)
20681 cachePosition: function(iPageX, iPageY) {
20683 this.lastPageX = iPageX;
20684 this.lastPageY = iPageY;
20686 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20687 this.lastPageX = aCoord[0];
20688 this.lastPageY = aCoord[1];
20693 * Auto-scroll the window if the dragged object has been moved beyond the
20694 * visible window boundary.
20695 * @method autoScroll
20696 * @param {int} x the drag element's x position
20697 * @param {int} y the drag element's y position
20698 * @param {int} h the height of the drag element
20699 * @param {int} w the width of the drag element
20702 autoScroll: function(x, y, h, w) {
20705 // The client height
20706 var clientH = Roo.lib.Dom.getViewWidth();
20708 // The client width
20709 var clientW = Roo.lib.Dom.getViewHeight();
20711 // The amt scrolled down
20712 var st = this.DDM.getScrollTop();
20714 // The amt scrolled right
20715 var sl = this.DDM.getScrollLeft();
20717 // Location of the bottom of the element
20720 // Location of the right of the element
20723 // The distance from the cursor to the bottom of the visible area,
20724 // adjusted so that we don't scroll if the cursor is beyond the
20725 // element drag constraints
20726 var toBot = (clientH + st - y - this.deltaY);
20728 // The distance from the cursor to the right of the visible area
20729 var toRight = (clientW + sl - x - this.deltaX);
20732 // How close to the edge the cursor must be before we scroll
20733 // var thresh = (document.all) ? 100 : 40;
20736 // How many pixels to scroll per autoscroll op. This helps to reduce
20737 // clunky scrolling. IE is more sensitive about this ... it needs this
20738 // value to be higher.
20739 var scrAmt = (document.all) ? 80 : 30;
20741 // Scroll down if we are near the bottom of the visible page and the
20742 // obj extends below the crease
20743 if ( bot > clientH && toBot < thresh ) {
20744 window.scrollTo(sl, st + scrAmt);
20747 // Scroll up if the window is scrolled down and the top of the object
20748 // goes above the top border
20749 if ( y < st && st > 0 && y - st < thresh ) {
20750 window.scrollTo(sl, st - scrAmt);
20753 // Scroll right if the obj is beyond the right border and the cursor is
20754 // near the border.
20755 if ( right > clientW && toRight < thresh ) {
20756 window.scrollTo(sl + scrAmt, st);
20759 // Scroll left if the window has been scrolled to the right and the obj
20760 // extends past the left border
20761 if ( x < sl && sl > 0 && x - sl < thresh ) {
20762 window.scrollTo(sl - scrAmt, st);
20768 * Finds the location the element should be placed if we want to move
20769 * it to where the mouse location less the click offset would place us.
20770 * @method getTargetCoord
20771 * @param {int} iPageX the X coordinate of the click
20772 * @param {int} iPageY the Y coordinate of the click
20773 * @return an object that contains the coordinates (Object.x and Object.y)
20776 getTargetCoord: function(iPageX, iPageY) {
20779 var x = iPageX - this.deltaX;
20780 var y = iPageY - this.deltaY;
20782 if (this.constrainX) {
20783 if (x < this.minX) { x = this.minX; }
20784 if (x > this.maxX) { x = this.maxX; }
20787 if (this.constrainY) {
20788 if (y < this.minY) { y = this.minY; }
20789 if (y > this.maxY) { y = this.maxY; }
20792 x = this.getTick(x, this.xTicks);
20793 y = this.getTick(y, this.yTicks);
20800 * Sets up config options specific to this class. Overrides
20801 * Roo.dd.DragDrop, but all versions of this method through the
20802 * inheritance chain are called
20804 applyConfig: function() {
20805 Roo.dd.DD.superclass.applyConfig.call(this);
20806 this.scroll = (this.config.scroll !== false);
20810 * Event that fires prior to the onMouseDown event. Overrides
20813 b4MouseDown: function(e) {
20814 // this.resetConstraints();
20815 this.autoOffset(e.getPageX(),
20820 * Event that fires prior to the onDrag event. Overrides
20823 b4Drag: function(e) {
20824 this.setDragElPos(e.getPageX(),
20828 toString: function() {
20829 return ("DD " + this.id);
20832 //////////////////////////////////////////////////////////////////////////
20833 // Debugging ygDragDrop events that can be overridden
20834 //////////////////////////////////////////////////////////////////////////
20836 startDrag: function(x, y) {
20839 onDrag: function(e) {
20842 onDragEnter: function(e, id) {
20845 onDragOver: function(e, id) {
20848 onDragOut: function(e, id) {
20851 onDragDrop: function(e, id) {
20854 endDrag: function(e) {
20861 * Ext JS Library 1.1.1
20862 * Copyright(c) 2006-2007, Ext JS, LLC.
20864 * Originally Released Under LGPL - original licence link has changed is not relivant.
20867 * <script type="text/javascript">
20871 * @class Roo.dd.DDProxy
20872 * A DragDrop implementation that inserts an empty, bordered div into
20873 * the document that follows the cursor during drag operations. At the time of
20874 * the click, the frame div is resized to the dimensions of the linked html
20875 * element, and moved to the exact location of the linked element.
20877 * References to the "frame" element refer to the single proxy element that
20878 * was created to be dragged in place of all DDProxy elements on the
20881 * @extends Roo.dd.DD
20883 * @param {String} id the id of the linked html element
20884 * @param {String} sGroup the group of related DragDrop objects
20885 * @param {object} config an object containing configurable attributes
20886 * Valid properties for DDProxy in addition to those in DragDrop:
20887 * resizeFrame, centerFrame, dragElId
20889 Roo.dd.DDProxy = function(id, sGroup, config) {
20891 this.init(id, sGroup, config);
20897 * The default drag frame div id
20898 * @property Roo.dd.DDProxy.dragElId
20902 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20904 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20907 * By default we resize the drag frame to be the same size as the element
20908 * we want to drag (this is to get the frame effect). We can turn it off
20909 * if we want a different behavior.
20910 * @property resizeFrame
20916 * By default the frame is positioned exactly where the drag element is, so
20917 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20918 * you do not have constraints on the obj is to have the drag frame centered
20919 * around the cursor. Set centerFrame to true for this effect.
20920 * @property centerFrame
20923 centerFrame: false,
20926 * Creates the proxy element if it does not yet exist
20927 * @method createFrame
20929 createFrame: function() {
20931 var body = document.body;
20933 if (!body || !body.firstChild) {
20934 setTimeout( function() { self.createFrame(); }, 50 );
20938 var div = this.getDragEl();
20941 div = document.createElement("div");
20942 div.id = this.dragElId;
20945 s.position = "absolute";
20946 s.visibility = "hidden";
20948 s.border = "2px solid #aaa";
20951 // appendChild can blow up IE if invoked prior to the window load event
20952 // while rendering a table. It is possible there are other scenarios
20953 // that would cause this to happen as well.
20954 body.insertBefore(div, body.firstChild);
20959 * Initialization for the drag frame element. Must be called in the
20960 * constructor of all subclasses
20961 * @method initFrame
20963 initFrame: function() {
20964 this.createFrame();
20967 applyConfig: function() {
20968 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20970 this.resizeFrame = (this.config.resizeFrame !== false);
20971 this.centerFrame = (this.config.centerFrame);
20972 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20976 * Resizes the drag frame to the dimensions of the clicked object, positions
20977 * it over the object, and finally displays it
20978 * @method showFrame
20979 * @param {int} iPageX X click position
20980 * @param {int} iPageY Y click position
20983 showFrame: function(iPageX, iPageY) {
20984 var el = this.getEl();
20985 var dragEl = this.getDragEl();
20986 var s = dragEl.style;
20988 this._resizeProxy();
20990 if (this.centerFrame) {
20991 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20992 Math.round(parseInt(s.height, 10)/2) );
20995 this.setDragElPos(iPageX, iPageY);
20997 Roo.fly(dragEl).show();
21001 * The proxy is automatically resized to the dimensions of the linked
21002 * element when a drag is initiated, unless resizeFrame is set to false
21003 * @method _resizeProxy
21006 _resizeProxy: function() {
21007 if (this.resizeFrame) {
21008 var el = this.getEl();
21009 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21013 // overrides Roo.dd.DragDrop
21014 b4MouseDown: function(e) {
21015 var x = e.getPageX();
21016 var y = e.getPageY();
21017 this.autoOffset(x, y);
21018 this.setDragElPos(x, y);
21021 // overrides Roo.dd.DragDrop
21022 b4StartDrag: function(x, y) {
21023 // show the drag frame
21024 this.showFrame(x, y);
21027 // overrides Roo.dd.DragDrop
21028 b4EndDrag: function(e) {
21029 Roo.fly(this.getDragEl()).hide();
21032 // overrides Roo.dd.DragDrop
21033 // By default we try to move the element to the last location of the frame.
21034 // This is so that the default behavior mirrors that of Roo.dd.DD.
21035 endDrag: function(e) {
21037 var lel = this.getEl();
21038 var del = this.getDragEl();
21040 // Show the drag frame briefly so we can get its position
21041 del.style.visibility = "";
21044 // Hide the linked element before the move to get around a Safari
21046 lel.style.visibility = "hidden";
21047 Roo.dd.DDM.moveToEl(lel, del);
21048 del.style.visibility = "hidden";
21049 lel.style.visibility = "";
21054 beforeMove : function(){
21058 afterDrag : function(){
21062 toString: function() {
21063 return ("DDProxy " + this.id);
21069 * Ext JS Library 1.1.1
21070 * Copyright(c) 2006-2007, Ext JS, LLC.
21072 * Originally Released Under LGPL - original licence link has changed is not relivant.
21075 * <script type="text/javascript">
21079 * @class Roo.dd.DDTarget
21080 * A DragDrop implementation that does not move, but can be a drop
21081 * target. You would get the same result by simply omitting implementation
21082 * for the event callbacks, but this way we reduce the processing cost of the
21083 * event listener and the callbacks.
21084 * @extends Roo.dd.DragDrop
21086 * @param {String} id the id of the element that is a drop target
21087 * @param {String} sGroup the group of related DragDrop objects
21088 * @param {object} config an object containing configurable attributes
21089 * Valid properties for DDTarget in addition to those in
21093 Roo.dd.DDTarget = function(id, sGroup, config) {
21095 this.initTarget(id, sGroup, config);
21097 if (config.listeners || config.events) {
21098 Roo.dd.DragDrop.superclass.constructor.call(this, {
21099 listeners : config.listeners || {},
21100 events : config.events || {}
21105 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21106 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21107 toString: function() {
21108 return ("DDTarget " + this.id);
21113 * Ext JS Library 1.1.1
21114 * Copyright(c) 2006-2007, Ext JS, LLC.
21116 * Originally Released Under LGPL - original licence link has changed is not relivant.
21119 * <script type="text/javascript">
21124 * @class Roo.dd.ScrollManager
21125 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21126 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21129 Roo.dd.ScrollManager = function(){
21130 var ddm = Roo.dd.DragDropMgr;
21137 var onStop = function(e){
21142 var triggerRefresh = function(){
21143 if(ddm.dragCurrent){
21144 ddm.refreshCache(ddm.dragCurrent.groups);
21148 var doScroll = function(){
21149 if(ddm.dragCurrent){
21150 var dds = Roo.dd.ScrollManager;
21152 if(proc.el.scroll(proc.dir, dds.increment)){
21156 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21161 var clearProc = function(){
21163 clearInterval(proc.id);
21170 var startProc = function(el, dir){
21171 Roo.log('scroll startproc');
21175 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21178 var onFire = function(e, isDrop){
21180 if(isDrop || !ddm.dragCurrent){ return; }
21181 var dds = Roo.dd.ScrollManager;
21182 if(!dragEl || dragEl != ddm.dragCurrent){
21183 dragEl = ddm.dragCurrent;
21184 // refresh regions on drag start
21185 dds.refreshCache();
21188 var xy = Roo.lib.Event.getXY(e);
21189 var pt = new Roo.lib.Point(xy[0], xy[1]);
21190 for(var id in els){
21191 var el = els[id], r = el._region;
21192 if(r && r.contains(pt) && el.isScrollable()){
21193 if(r.bottom - pt.y <= dds.thresh){
21195 startProc(el, "down");
21198 }else if(r.right - pt.x <= dds.thresh){
21200 startProc(el, "left");
21203 }else if(pt.y - r.top <= dds.thresh){
21205 startProc(el, "up");
21208 }else if(pt.x - r.left <= dds.thresh){
21210 startProc(el, "right");
21219 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21220 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21224 * Registers new overflow element(s) to auto scroll
21225 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21227 register : function(el){
21228 if(el instanceof Array){
21229 for(var i = 0, len = el.length; i < len; i++) {
21230 this.register(el[i]);
21236 Roo.dd.ScrollManager.els = els;
21240 * Unregisters overflow element(s) so they are no longer scrolled
21241 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21243 unregister : function(el){
21244 if(el instanceof Array){
21245 for(var i = 0, len = el.length; i < len; i++) {
21246 this.unregister(el[i]);
21255 * The number of pixels from the edge of a container the pointer needs to be to
21256 * trigger scrolling (defaults to 25)
21262 * The number of pixels to scroll in each scroll increment (defaults to 50)
21268 * The frequency of scrolls in milliseconds (defaults to 500)
21274 * True to animate the scroll (defaults to true)
21280 * The animation duration in seconds -
21281 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21287 * Manually trigger a cache refresh.
21289 refreshCache : function(){
21290 for(var id in els){
21291 if(typeof els[id] == 'object'){ // for people extending the object prototype
21292 els[id]._region = els[id].getRegion();
21299 * Ext JS Library 1.1.1
21300 * Copyright(c) 2006-2007, Ext JS, LLC.
21302 * Originally Released Under LGPL - original licence link has changed is not relivant.
21305 * <script type="text/javascript">
21310 * @class Roo.dd.Registry
21311 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21312 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21315 Roo.dd.Registry = function(){
21318 var autoIdSeed = 0;
21320 var getId = function(el, autogen){
21321 if(typeof el == "string"){
21325 if(!id && autogen !== false){
21326 id = "roodd-" + (++autoIdSeed);
21334 * Register a drag drop element
21335 * @param {String|HTMLElement} element The id or DOM node to register
21336 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21337 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21338 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21339 * populated in the data object (if applicable):
21341 Value Description<br />
21342 --------- ------------------------------------------<br />
21343 handles Array of DOM nodes that trigger dragging<br />
21344 for the element being registered<br />
21345 isHandle True if the element passed in triggers<br />
21346 dragging itself, else false
21349 register : function(el, data){
21351 if(typeof el == "string"){
21352 el = document.getElementById(el);
21355 elements[getId(el)] = data;
21356 if(data.isHandle !== false){
21357 handles[data.ddel.id] = data;
21360 var hs = data.handles;
21361 for(var i = 0, len = hs.length; i < len; i++){
21362 handles[getId(hs[i])] = data;
21368 * Unregister a drag drop element
21369 * @param {String|HTMLElement} element The id or DOM node to unregister
21371 unregister : function(el){
21372 var id = getId(el, false);
21373 var data = elements[id];
21375 delete elements[id];
21377 var hs = data.handles;
21378 for(var i = 0, len = hs.length; i < len; i++){
21379 delete handles[getId(hs[i], false)];
21386 * Returns the handle registered for a DOM Node by id
21387 * @param {String|HTMLElement} id The DOM node or id to look up
21388 * @return {Object} handle The custom handle data
21390 getHandle : function(id){
21391 if(typeof id != "string"){ // must be element?
21394 return handles[id];
21398 * Returns the handle that is registered for the DOM node that is the target of the event
21399 * @param {Event} e The event
21400 * @return {Object} handle The custom handle data
21402 getHandleFromEvent : function(e){
21403 var t = Roo.lib.Event.getTarget(e);
21404 return t ? handles[t.id] : null;
21408 * Returns a custom data object that is registered for a DOM node by id
21409 * @param {String|HTMLElement} id The DOM node or id to look up
21410 * @return {Object} data The custom data
21412 getTarget : function(id){
21413 if(typeof id != "string"){ // must be element?
21416 return elements[id];
21420 * Returns a custom data object that is registered for the DOM node that is the target of the event
21421 * @param {Event} e The event
21422 * @return {Object} data The custom data
21424 getTargetFromEvent : function(e){
21425 var t = Roo.lib.Event.getTarget(e);
21426 return t ? elements[t.id] || handles[t.id] : null;
21431 * Ext JS Library 1.1.1
21432 * Copyright(c) 2006-2007, Ext JS, LLC.
21434 * Originally Released Under LGPL - original licence link has changed is not relivant.
21437 * <script type="text/javascript">
21442 * @class Roo.dd.StatusProxy
21443 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21444 * default drag proxy used by all Roo.dd components.
21446 * @param {Object} config
21448 Roo.dd.StatusProxy = function(config){
21449 Roo.apply(this, config);
21450 this.id = this.id || Roo.id();
21451 this.el = new Roo.Layer({
21453 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21454 {tag: "div", cls: "x-dd-drop-icon"},
21455 {tag: "div", cls: "x-dd-drag-ghost"}
21458 shadow: !config || config.shadow !== false
21460 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21461 this.dropStatus = this.dropNotAllowed;
21464 Roo.dd.StatusProxy.prototype = {
21466 * @cfg {String} dropAllowed
21467 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21469 dropAllowed : "x-dd-drop-ok",
21471 * @cfg {String} dropNotAllowed
21472 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21474 dropNotAllowed : "x-dd-drop-nodrop",
21477 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21478 * over the current target element.
21479 * @param {String} cssClass The css class for the new drop status indicator image
21481 setStatus : function(cssClass){
21482 cssClass = cssClass || this.dropNotAllowed;
21483 if(this.dropStatus != cssClass){
21484 this.el.replaceClass(this.dropStatus, cssClass);
21485 this.dropStatus = cssClass;
21490 * Resets the status indicator to the default dropNotAllowed value
21491 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21493 reset : function(clearGhost){
21494 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21495 this.dropStatus = this.dropNotAllowed;
21497 this.ghost.update("");
21502 * Updates the contents of the ghost element
21503 * @param {String} html The html that will replace the current innerHTML of the ghost element
21505 update : function(html){
21506 if(typeof html == "string"){
21507 this.ghost.update(html);
21509 this.ghost.update("");
21510 html.style.margin = "0";
21511 this.ghost.dom.appendChild(html);
21513 // ensure float = none set?? cant remember why though.
21514 var el = this.ghost.dom.firstChild;
21516 Roo.fly(el).setStyle('float', 'none');
21521 * Returns the underlying proxy {@link Roo.Layer}
21522 * @return {Roo.Layer} el
21524 getEl : function(){
21529 * Returns the ghost element
21530 * @return {Roo.Element} el
21532 getGhost : function(){
21538 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21540 hide : function(clear){
21548 * Stops the repair animation if it's currently running
21551 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21557 * Displays this proxy
21564 * Force the Layer to sync its shadow and shim positions to the element
21571 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21572 * invalid drop operation by the item being dragged.
21573 * @param {Array} xy The XY position of the element ([x, y])
21574 * @param {Function} callback The function to call after the repair is complete
21575 * @param {Object} scope The scope in which to execute the callback
21577 repair : function(xy, callback, scope){
21578 this.callback = callback;
21579 this.scope = scope;
21580 if(xy && this.animRepair !== false){
21581 this.el.addClass("x-dd-drag-repair");
21582 this.el.hideUnders(true);
21583 this.anim = this.el.shift({
21584 duration: this.repairDuration || .5,
21588 callback: this.afterRepair,
21592 this.afterRepair();
21597 afterRepair : function(){
21599 if(typeof this.callback == "function"){
21600 this.callback.call(this.scope || this);
21602 this.callback = null;
21607 * Ext JS Library 1.1.1
21608 * Copyright(c) 2006-2007, Ext JS, LLC.
21610 * Originally Released Under LGPL - original licence link has changed is not relivant.
21613 * <script type="text/javascript">
21617 * @class Roo.dd.DragSource
21618 * @extends Roo.dd.DDProxy
21619 * A simple class that provides the basic implementation needed to make any element draggable.
21621 * @param {String/HTMLElement/Element} el The container element
21622 * @param {Object} config
21624 Roo.dd.DragSource = function(el, config){
21625 this.el = Roo.get(el);
21626 this.dragData = {};
21628 Roo.apply(this, config);
21631 this.proxy = new Roo.dd.StatusProxy();
21634 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21635 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21637 this.dragging = false;
21640 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21642 * @cfg {String} dropAllowed
21643 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21645 dropAllowed : "x-dd-drop-ok",
21647 * @cfg {String} dropNotAllowed
21648 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21650 dropNotAllowed : "x-dd-drop-nodrop",
21653 * Returns the data object associated with this drag source
21654 * @return {Object} data An object containing arbitrary data
21656 getDragData : function(e){
21657 return this.dragData;
21661 onDragEnter : function(e, id){
21662 var target = Roo.dd.DragDropMgr.getDDById(id);
21663 this.cachedTarget = target;
21664 if(this.beforeDragEnter(target, e, id) !== false){
21665 if(target.isNotifyTarget){
21666 var status = target.notifyEnter(this, e, this.dragData);
21667 this.proxy.setStatus(status);
21669 this.proxy.setStatus(this.dropAllowed);
21672 if(this.afterDragEnter){
21674 * An empty function by default, but provided so that you can perform a custom action
21675 * when the dragged item enters the drop target by providing an implementation.
21676 * @param {Roo.dd.DragDrop} target The drop target
21677 * @param {Event} e The event object
21678 * @param {String} id The id of the dragged element
21679 * @method afterDragEnter
21681 this.afterDragEnter(target, e, id);
21687 * An empty function by default, but provided so that you can perform a custom action
21688 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21689 * @param {Roo.dd.DragDrop} target The drop target
21690 * @param {Event} e The event object
21691 * @param {String} id The id of the dragged element
21692 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21694 beforeDragEnter : function(target, e, id){
21699 alignElWithMouse: function() {
21700 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21705 onDragOver : function(e, id){
21706 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21707 if(this.beforeDragOver(target, e, id) !== false){
21708 if(target.isNotifyTarget){
21709 var status = target.notifyOver(this, e, this.dragData);
21710 this.proxy.setStatus(status);
21713 if(this.afterDragOver){
21715 * An empty function by default, but provided so that you can perform a custom action
21716 * while the dragged item is over the drop target by providing an implementation.
21717 * @param {Roo.dd.DragDrop} target The drop target
21718 * @param {Event} e The event object
21719 * @param {String} id The id of the dragged element
21720 * @method afterDragOver
21722 this.afterDragOver(target, e, id);
21728 * An empty function by default, but provided so that you can perform a custom action
21729 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21730 * @param {Roo.dd.DragDrop} target The drop target
21731 * @param {Event} e The event object
21732 * @param {String} id The id of the dragged element
21733 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21735 beforeDragOver : function(target, e, id){
21740 onDragOut : function(e, id){
21741 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21742 if(this.beforeDragOut(target, e, id) !== false){
21743 if(target.isNotifyTarget){
21744 target.notifyOut(this, e, this.dragData);
21746 this.proxy.reset();
21747 if(this.afterDragOut){
21749 * An empty function by default, but provided so that you can perform a custom action
21750 * after the dragged item is dragged out of the target without dropping.
21751 * @param {Roo.dd.DragDrop} target The drop target
21752 * @param {Event} e The event object
21753 * @param {String} id The id of the dragged element
21754 * @method afterDragOut
21756 this.afterDragOut(target, e, id);
21759 this.cachedTarget = null;
21763 * An empty function by default, but provided so that you can perform a custom action before the dragged
21764 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21765 * @param {Roo.dd.DragDrop} target The drop target
21766 * @param {Event} e The event object
21767 * @param {String} id The id of the dragged element
21768 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21770 beforeDragOut : function(target, e, id){
21775 onDragDrop : function(e, id){
21776 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21777 if(this.beforeDragDrop(target, e, id) !== false){
21778 if(target.isNotifyTarget){
21779 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21780 this.onValidDrop(target, e, id);
21782 this.onInvalidDrop(target, e, id);
21785 this.onValidDrop(target, e, id);
21788 if(this.afterDragDrop){
21790 * An empty function by default, but provided so that you can perform a custom action
21791 * after a valid drag drop has occurred by providing an implementation.
21792 * @param {Roo.dd.DragDrop} target The drop target
21793 * @param {Event} e The event object
21794 * @param {String} id The id of the dropped element
21795 * @method afterDragDrop
21797 this.afterDragDrop(target, e, id);
21800 delete this.cachedTarget;
21804 * An empty function by default, but provided so that you can perform a custom action before the dragged
21805 * item is dropped onto the target and optionally cancel the onDragDrop.
21806 * @param {Roo.dd.DragDrop} target The drop target
21807 * @param {Event} e The event object
21808 * @param {String} id The id of the dragged element
21809 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21811 beforeDragDrop : function(target, e, id){
21816 onValidDrop : function(target, e, id){
21818 if(this.afterValidDrop){
21820 * An empty function by default, but provided so that you can perform a custom action
21821 * after a valid drop has occurred by providing an implementation.
21822 * @param {Object} target The target DD
21823 * @param {Event} e The event object
21824 * @param {String} id The id of the dropped element
21825 * @method afterInvalidDrop
21827 this.afterValidDrop(target, e, id);
21832 getRepairXY : function(e, data){
21833 return this.el.getXY();
21837 onInvalidDrop : function(target, e, id){
21838 this.beforeInvalidDrop(target, e, id);
21839 if(this.cachedTarget){
21840 if(this.cachedTarget.isNotifyTarget){
21841 this.cachedTarget.notifyOut(this, e, this.dragData);
21843 this.cacheTarget = null;
21845 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21847 if(this.afterInvalidDrop){
21849 * An empty function by default, but provided so that you can perform a custom action
21850 * after an invalid drop has occurred by providing an implementation.
21851 * @param {Event} e The event object
21852 * @param {String} id The id of the dropped element
21853 * @method afterInvalidDrop
21855 this.afterInvalidDrop(e, id);
21860 afterRepair : function(){
21862 this.el.highlight(this.hlColor || "c3daf9");
21864 this.dragging = false;
21868 * An empty function by default, but provided so that you can perform a custom action after an invalid
21869 * drop has occurred.
21870 * @param {Roo.dd.DragDrop} target The drop target
21871 * @param {Event} e The event object
21872 * @param {String} id The id of the dragged element
21873 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21875 beforeInvalidDrop : function(target, e, id){
21880 handleMouseDown : function(e){
21881 if(this.dragging) {
21884 var data = this.getDragData(e);
21885 if(data && this.onBeforeDrag(data, e) !== false){
21886 this.dragData = data;
21888 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21893 * An empty function by default, but provided so that you can perform a custom action before the initial
21894 * drag event begins and optionally cancel it.
21895 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21896 * @param {Event} e The event object
21897 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21899 onBeforeDrag : function(data, e){
21904 * An empty function by default, but provided so that you can perform a custom action once the initial
21905 * drag event has begun. The drag cannot be canceled from this function.
21906 * @param {Number} x The x position of the click on the dragged object
21907 * @param {Number} y The y position of the click on the dragged object
21909 onStartDrag : Roo.emptyFn,
21911 // private - YUI override
21912 startDrag : function(x, y){
21913 this.proxy.reset();
21914 this.dragging = true;
21915 this.proxy.update("");
21916 this.onInitDrag(x, y);
21921 onInitDrag : function(x, y){
21922 var clone = this.el.dom.cloneNode(true);
21923 clone.id = Roo.id(); // prevent duplicate ids
21924 this.proxy.update(clone);
21925 this.onStartDrag(x, y);
21930 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21931 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21933 getProxy : function(){
21938 * Hides the drag source's {@link Roo.dd.StatusProxy}
21940 hideProxy : function(){
21942 this.proxy.reset(true);
21943 this.dragging = false;
21947 triggerCacheRefresh : function(){
21948 Roo.dd.DDM.refreshCache(this.groups);
21951 // private - override to prevent hiding
21952 b4EndDrag: function(e) {
21955 // private - override to prevent moving
21956 endDrag : function(e){
21957 this.onEndDrag(this.dragData, e);
21961 onEndDrag : function(data, e){
21964 // private - pin to cursor
21965 autoOffset : function(x, y) {
21966 this.setDelta(-12, -20);
21970 * Ext JS Library 1.1.1
21971 * Copyright(c) 2006-2007, Ext JS, LLC.
21973 * Originally Released Under LGPL - original licence link has changed is not relivant.
21976 * <script type="text/javascript">
21981 * @class Roo.dd.DropTarget
21982 * @extends Roo.dd.DDTarget
21983 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21984 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21986 * @param {String/HTMLElement/Element} el The container element
21987 * @param {Object} config
21989 Roo.dd.DropTarget = function(el, config){
21990 this.el = Roo.get(el);
21992 var listeners = false; ;
21993 if (config && config.listeners) {
21994 listeners= config.listeners;
21995 delete config.listeners;
21997 Roo.apply(this, config);
21999 if(this.containerScroll){
22000 Roo.dd.ScrollManager.register(this.el);
22004 * @scope Roo.dd.DropTarget
22009 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22010 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22011 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22013 * IMPORTANT : it should set this.overClass and this.dropAllowed
22015 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22016 * @param {Event} e The event
22017 * @param {Object} data An object containing arbitrary data supplied by the drag source
22023 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22024 * This method will be called on every mouse movement while the drag source is over the drop target.
22025 * This default implementation simply returns the dropAllowed config value.
22027 * IMPORTANT : it should set this.dropAllowed
22029 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22030 * @param {Event} e The event
22031 * @param {Object} data An object containing arbitrary data supplied by the drag source
22037 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22038 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22039 * overClass (if any) from the drop element.
22041 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22042 * @param {Event} e The event
22043 * @param {Object} data An object containing arbitrary data supplied by the drag source
22049 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22050 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22051 * implementation that does something to process the drop event and returns true so that the drag source's
22052 * repair action does not run.
22054 * IMPORTANT : it should set this.success
22056 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22057 * @param {Event} e The event
22058 * @param {Object} data An object containing arbitrary data supplied by the drag source
22064 Roo.dd.DropTarget.superclass.constructor.call( this,
22066 this.ddGroup || this.group,
22069 listeners : listeners || {}
22077 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22079 * @cfg {String} overClass
22080 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22083 * @cfg {String} ddGroup
22084 * The drag drop group to handle drop events for
22088 * @cfg {String} dropAllowed
22089 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22091 dropAllowed : "x-dd-drop-ok",
22093 * @cfg {String} dropNotAllowed
22094 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22096 dropNotAllowed : "x-dd-drop-nodrop",
22098 * @cfg {boolean} success
22099 * set this after drop listener..
22103 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22104 * if the drop point is valid for over/enter..
22111 isNotifyTarget : true,
22116 notifyEnter : function(dd, e, data)
22119 this.fireEvent('enter', dd, e, data);
22120 if(this.overClass){
22121 this.el.addClass(this.overClass);
22123 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22124 this.valid ? this.dropAllowed : this.dropNotAllowed
22131 notifyOver : function(dd, e, data)
22134 this.fireEvent('over', dd, e, data);
22135 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22136 this.valid ? this.dropAllowed : this.dropNotAllowed
22143 notifyOut : function(dd, e, data)
22145 this.fireEvent('out', dd, e, data);
22146 if(this.overClass){
22147 this.el.removeClass(this.overClass);
22154 notifyDrop : function(dd, e, data)
22156 this.success = false;
22157 this.fireEvent('drop', dd, e, data);
22158 return this.success;
22162 * Ext JS Library 1.1.1
22163 * Copyright(c) 2006-2007, Ext JS, LLC.
22165 * Originally Released Under LGPL - original licence link has changed is not relivant.
22168 * <script type="text/javascript">
22173 * @class Roo.dd.DragZone
22174 * @extends Roo.dd.DragSource
22175 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22176 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22178 * @param {String/HTMLElement/Element} el The container element
22179 * @param {Object} config
22181 Roo.dd.DragZone = function(el, config){
22182 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22183 if(this.containerScroll){
22184 Roo.dd.ScrollManager.register(this.el);
22188 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22190 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22191 * for auto scrolling during drag operations.
22194 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22195 * method after a failed drop (defaults to "c3daf9" - light blue)
22199 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22200 * for a valid target to drag based on the mouse down. Override this method
22201 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22202 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22203 * @param {EventObject} e The mouse down event
22204 * @return {Object} The dragData
22206 getDragData : function(e){
22207 return Roo.dd.Registry.getHandleFromEvent(e);
22211 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22212 * this.dragData.ddel
22213 * @param {Number} x The x position of the click on the dragged object
22214 * @param {Number} y The y position of the click on the dragged object
22215 * @return {Boolean} true to continue the drag, false to cancel
22217 onInitDrag : function(x, y){
22218 this.proxy.update(this.dragData.ddel.cloneNode(true));
22219 this.onStartDrag(x, y);
22224 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22226 afterRepair : function(){
22228 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22230 this.dragging = false;
22234 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22235 * the XY of this.dragData.ddel
22236 * @param {EventObject} e The mouse up event
22237 * @return {Array} The xy location (e.g. [100, 200])
22239 getRepairXY : function(e){
22240 return Roo.Element.fly(this.dragData.ddel).getXY();
22244 * Ext JS Library 1.1.1
22245 * Copyright(c) 2006-2007, Ext JS, LLC.
22247 * Originally Released Under LGPL - original licence link has changed is not relivant.
22250 * <script type="text/javascript">
22253 * @class Roo.dd.DropZone
22254 * @extends Roo.dd.DropTarget
22255 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22256 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22258 * @param {String/HTMLElement/Element} el The container element
22259 * @param {Object} config
22261 Roo.dd.DropZone = function(el, config){
22262 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22265 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22267 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22268 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22269 * provide your own custom lookup.
22270 * @param {Event} e The event
22271 * @return {Object} data The custom data
22273 getTargetFromEvent : function(e){
22274 return Roo.dd.Registry.getTargetFromEvent(e);
22278 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22279 * that it has registered. This method has no default implementation and should be overridden to provide
22280 * node-specific processing if necessary.
22281 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22282 * {@link #getTargetFromEvent} for this node)
22283 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22284 * @param {Event} e The event
22285 * @param {Object} data An object containing arbitrary data supplied by the drag source
22287 onNodeEnter : function(n, dd, e, data){
22292 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22293 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22294 * overridden to provide the proper feedback.
22295 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22296 * {@link #getTargetFromEvent} for this node)
22297 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22298 * @param {Event} e The event
22299 * @param {Object} data An object containing arbitrary data supplied by the drag source
22300 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22301 * underlying {@link Roo.dd.StatusProxy} can be updated
22303 onNodeOver : function(n, dd, e, data){
22304 return this.dropAllowed;
22308 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22309 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22310 * node-specific processing if necessary.
22311 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22312 * {@link #getTargetFromEvent} for this node)
22313 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22314 * @param {Event} e The event
22315 * @param {Object} data An object containing arbitrary data supplied by the drag source
22317 onNodeOut : function(n, dd, e, data){
22322 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22323 * the drop node. The default implementation returns false, so it should be overridden to provide the
22324 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22325 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22326 * {@link #getTargetFromEvent} for this node)
22327 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22328 * @param {Event} e The event
22329 * @param {Object} data An object containing arbitrary data supplied by the drag source
22330 * @return {Boolean} True if the drop was valid, else false
22332 onNodeDrop : function(n, dd, e, data){
22337 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22338 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22339 * it should be overridden to provide the proper feedback if necessary.
22340 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22341 * @param {Event} e The event
22342 * @param {Object} data An object containing arbitrary data supplied by the drag source
22343 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22344 * underlying {@link Roo.dd.StatusProxy} can be updated
22346 onContainerOver : function(dd, e, data){
22347 return this.dropNotAllowed;
22351 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22352 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22353 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22354 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22355 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22356 * @param {Event} e The event
22357 * @param {Object} data An object containing arbitrary data supplied by the drag source
22358 * @return {Boolean} True if the drop was valid, else false
22360 onContainerDrop : function(dd, e, data){
22365 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22366 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22367 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22368 * you should override this method and provide a custom implementation.
22369 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22370 * @param {Event} e The event
22371 * @param {Object} data An object containing arbitrary data supplied by the drag source
22372 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22373 * underlying {@link Roo.dd.StatusProxy} can be updated
22375 notifyEnter : function(dd, e, data){
22376 return this.dropNotAllowed;
22380 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22381 * This method will be called on every mouse movement while the drag source is over the drop zone.
22382 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22383 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22384 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22385 * registered node, it will call {@link #onContainerOver}.
22386 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22387 * @param {Event} e The event
22388 * @param {Object} data An object containing arbitrary data supplied by the drag source
22389 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22390 * underlying {@link Roo.dd.StatusProxy} can be updated
22392 notifyOver : function(dd, e, data){
22393 var n = this.getTargetFromEvent(e);
22394 if(!n){ // not over valid drop target
22395 if(this.lastOverNode){
22396 this.onNodeOut(this.lastOverNode, dd, e, data);
22397 this.lastOverNode = null;
22399 return this.onContainerOver(dd, e, data);
22401 if(this.lastOverNode != n){
22402 if(this.lastOverNode){
22403 this.onNodeOut(this.lastOverNode, dd, e, data);
22405 this.onNodeEnter(n, dd, e, data);
22406 this.lastOverNode = n;
22408 return this.onNodeOver(n, dd, e, data);
22412 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22413 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22414 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22415 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22416 * @param {Event} e The event
22417 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22419 notifyOut : function(dd, e, data){
22420 if(this.lastOverNode){
22421 this.onNodeOut(this.lastOverNode, dd, e, data);
22422 this.lastOverNode = null;
22427 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22428 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22429 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22430 * otherwise it will call {@link #onContainerDrop}.
22431 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22432 * @param {Event} e The event
22433 * @param {Object} data An object containing arbitrary data supplied by the drag source
22434 * @return {Boolean} True if the drop was valid, else false
22436 notifyDrop : function(dd, e, data){
22437 if(this.lastOverNode){
22438 this.onNodeOut(this.lastOverNode, dd, e, data);
22439 this.lastOverNode = null;
22441 var n = this.getTargetFromEvent(e);
22443 this.onNodeDrop(n, dd, e, data) :
22444 this.onContainerDrop(dd, e, data);
22448 triggerCacheRefresh : function(){
22449 Roo.dd.DDM.refreshCache(this.groups);
22453 * Ext JS Library 1.1.1
22454 * Copyright(c) 2006-2007, Ext JS, LLC.
22456 * Originally Released Under LGPL - original licence link has changed is not relivant.
22459 * <script type="text/javascript">
22464 * @class Roo.data.SortTypes
22466 * Defines the default sorting (casting?) comparison functions used when sorting data.
22468 Roo.data.SortTypes = {
22470 * Default sort that does nothing
22471 * @param {Mixed} s The value being converted
22472 * @return {Mixed} The comparison value
22474 none : function(s){
22479 * The regular expression used to strip tags
22483 stripTagsRE : /<\/?[^>]+>/gi,
22486 * Strips all HTML tags to sort on text only
22487 * @param {Mixed} s The value being converted
22488 * @return {String} The comparison value
22490 asText : function(s){
22491 return String(s).replace(this.stripTagsRE, "");
22495 * Strips all HTML tags to sort on text only - Case insensitive
22496 * @param {Mixed} s The value being converted
22497 * @return {String} The comparison value
22499 asUCText : function(s){
22500 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22504 * Case insensitive string
22505 * @param {Mixed} s The value being converted
22506 * @return {String} The comparison value
22508 asUCString : function(s) {
22509 return String(s).toUpperCase();
22514 * @param {Mixed} s The value being converted
22515 * @return {Number} The comparison value
22517 asDate : function(s) {
22521 if(s instanceof Date){
22522 return s.getTime();
22524 return Date.parse(String(s));
22529 * @param {Mixed} s The value being converted
22530 * @return {Float} The comparison value
22532 asFloat : function(s) {
22533 var val = parseFloat(String(s).replace(/,/g, ""));
22542 * @param {Mixed} s The value being converted
22543 * @return {Number} The comparison value
22545 asInt : function(s) {
22546 var val = parseInt(String(s).replace(/,/g, ""));
22554 * Ext JS Library 1.1.1
22555 * Copyright(c) 2006-2007, Ext JS, LLC.
22557 * Originally Released Under LGPL - original licence link has changed is not relivant.
22560 * <script type="text/javascript">
22564 * @class Roo.data.Record
22565 * Instances of this class encapsulate both record <em>definition</em> information, and record
22566 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22567 * to access Records cached in an {@link Roo.data.Store} object.<br>
22569 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22570 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22573 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22575 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22576 * {@link #create}. The parameters are the same.
22577 * @param {Array} data An associative Array of data values keyed by the field name.
22578 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22579 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22580 * not specified an integer id is generated.
22582 Roo.data.Record = function(data, id){
22583 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22588 * Generate a constructor for a specific record layout.
22589 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22590 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22591 * Each field definition object may contain the following properties: <ul>
22592 * <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,
22593 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22594 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22595 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22596 * is being used, then this is a string containing the javascript expression to reference the data relative to
22597 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22598 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22599 * this may be omitted.</p></li>
22600 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22601 * <ul><li>auto (Default, implies no conversion)</li>
22606 * <li>date</li></ul></p></li>
22607 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22608 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22609 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22610 * by the Reader into an object that will be stored in the Record. It is passed the
22611 * following parameters:<ul>
22612 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22614 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22616 * <br>usage:<br><pre><code>
22617 var TopicRecord = Roo.data.Record.create(
22618 {name: 'title', mapping: 'topic_title'},
22619 {name: 'author', mapping: 'username'},
22620 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22621 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22622 {name: 'lastPoster', mapping: 'user2'},
22623 {name: 'excerpt', mapping: 'post_text'}
22626 var myNewRecord = new TopicRecord({
22627 title: 'Do my job please',
22630 lastPost: new Date(),
22631 lastPoster: 'Animal',
22632 excerpt: 'No way dude!'
22634 myStore.add(myNewRecord);
22639 Roo.data.Record.create = function(o){
22640 var f = function(){
22641 f.superclass.constructor.apply(this, arguments);
22643 Roo.extend(f, Roo.data.Record);
22644 var p = f.prototype;
22645 p.fields = new Roo.util.MixedCollection(false, function(field){
22648 for(var i = 0, len = o.length; i < len; i++){
22649 p.fields.add(new Roo.data.Field(o[i]));
22651 f.getField = function(name){
22652 return p.fields.get(name);
22657 Roo.data.Record.AUTO_ID = 1000;
22658 Roo.data.Record.EDIT = 'edit';
22659 Roo.data.Record.REJECT = 'reject';
22660 Roo.data.Record.COMMIT = 'commit';
22662 Roo.data.Record.prototype = {
22664 * Readonly flag - true if this record has been modified.
22673 join : function(store){
22674 this.store = store;
22678 * Set the named field to the specified value.
22679 * @param {String} name The name of the field to set.
22680 * @param {Object} value The value to set the field to.
22682 set : function(name, value){
22683 if(this.data[name] == value){
22687 if(!this.modified){
22688 this.modified = {};
22690 if(typeof this.modified[name] == 'undefined'){
22691 this.modified[name] = this.data[name];
22693 this.data[name] = value;
22694 if(!this.editing && this.store){
22695 this.store.afterEdit(this);
22700 * Get the value of the named field.
22701 * @param {String} name The name of the field to get the value of.
22702 * @return {Object} The value of the field.
22704 get : function(name){
22705 return this.data[name];
22709 beginEdit : function(){
22710 this.editing = true;
22711 this.modified = {};
22715 cancelEdit : function(){
22716 this.editing = false;
22717 delete this.modified;
22721 endEdit : function(){
22722 this.editing = false;
22723 if(this.dirty && this.store){
22724 this.store.afterEdit(this);
22729 * Usually called by the {@link Roo.data.Store} which owns the Record.
22730 * Rejects all changes made to the Record since either creation, or the last commit operation.
22731 * Modified fields are reverted to their original values.
22733 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22734 * of reject operations.
22736 reject : function(){
22737 var m = this.modified;
22739 if(typeof m[n] != "function"){
22740 this.data[n] = m[n];
22743 this.dirty = false;
22744 delete this.modified;
22745 this.editing = false;
22747 this.store.afterReject(this);
22752 * Usually called by the {@link Roo.data.Store} which owns the Record.
22753 * Commits all changes made to the Record since either creation, or the last commit operation.
22755 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22756 * of commit operations.
22758 commit : function(){
22759 this.dirty = false;
22760 delete this.modified;
22761 this.editing = false;
22763 this.store.afterCommit(this);
22768 hasError : function(){
22769 return this.error != null;
22773 clearError : function(){
22778 * Creates a copy of this record.
22779 * @param {String} id (optional) A new record id if you don't want to use this record's id
22782 copy : function(newId) {
22783 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22787 * Ext JS Library 1.1.1
22788 * Copyright(c) 2006-2007, Ext JS, LLC.
22790 * Originally Released Under LGPL - original licence link has changed is not relivant.
22793 * <script type="text/javascript">
22799 * @class Roo.data.Store
22800 * @extends Roo.util.Observable
22801 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22802 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22804 * 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
22805 * has no knowledge of the format of the data returned by the Proxy.<br>
22807 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22808 * instances from the data object. These records are cached and made available through accessor functions.
22810 * Creates a new Store.
22811 * @param {Object} config A config object containing the objects needed for the Store to access data,
22812 * and read the data into Records.
22814 Roo.data.Store = function(config){
22815 this.data = new Roo.util.MixedCollection(false);
22816 this.data.getKey = function(o){
22819 this.baseParams = {};
22821 this.paramNames = {
22826 "multisort" : "_multisort"
22829 if(config && config.data){
22830 this.inlineData = config.data;
22831 delete config.data;
22834 Roo.apply(this, config);
22836 if(this.reader){ // reader passed
22837 this.reader = Roo.factory(this.reader, Roo.data);
22838 this.reader.xmodule = this.xmodule || false;
22839 if(!this.recordType){
22840 this.recordType = this.reader.recordType;
22842 if(this.reader.onMetaChange){
22843 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22847 if(this.recordType){
22848 this.fields = this.recordType.prototype.fields;
22850 this.modified = [];
22854 * @event datachanged
22855 * Fires when the data cache has changed, and a widget which is using this Store
22856 * as a Record cache should refresh its view.
22857 * @param {Store} this
22859 datachanged : true,
22861 * @event metachange
22862 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22863 * @param {Store} this
22864 * @param {Object} meta The JSON metadata
22869 * Fires when Records have been added to the Store
22870 * @param {Store} this
22871 * @param {Roo.data.Record[]} records The array of Records added
22872 * @param {Number} index The index at which the record(s) were added
22877 * Fires when a Record has been removed from the Store
22878 * @param {Store} this
22879 * @param {Roo.data.Record} record The Record that was removed
22880 * @param {Number} index The index at which the record was removed
22885 * Fires when a Record has been updated
22886 * @param {Store} this
22887 * @param {Roo.data.Record} record The Record that was updated
22888 * @param {String} operation The update operation being performed. Value may be one of:
22890 Roo.data.Record.EDIT
22891 Roo.data.Record.REJECT
22892 Roo.data.Record.COMMIT
22898 * Fires when the data cache has been cleared.
22899 * @param {Store} this
22903 * @event beforeload
22904 * Fires before a request is made for a new data object. If the beforeload handler returns false
22905 * the load action will be canceled.
22906 * @param {Store} this
22907 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22911 * @event beforeloadadd
22912 * Fires after a new set of Records has been loaded.
22913 * @param {Store} this
22914 * @param {Roo.data.Record[]} records The Records that were loaded
22915 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22917 beforeloadadd : true,
22920 * Fires after a new set of Records has been loaded, before they are added to the store.
22921 * @param {Store} this
22922 * @param {Roo.data.Record[]} records The Records that were loaded
22923 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22924 * @params {Object} return from reader
22928 * @event loadexception
22929 * Fires if an exception occurs in the Proxy during loading.
22930 * Called with the signature of the Proxy's "loadexception" event.
22931 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22934 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22935 * @param {Object} load options
22936 * @param {Object} jsonData from your request (normally this contains the Exception)
22938 loadexception : true
22942 this.proxy = Roo.factory(this.proxy, Roo.data);
22943 this.proxy.xmodule = this.xmodule || false;
22944 this.relayEvents(this.proxy, ["loadexception"]);
22946 this.sortToggle = {};
22947 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22949 Roo.data.Store.superclass.constructor.call(this);
22951 if(this.inlineData){
22952 this.loadData(this.inlineData);
22953 delete this.inlineData;
22957 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22959 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22960 * without a remote query - used by combo/forms at present.
22964 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22967 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22970 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22971 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22974 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22975 * on any HTTP request
22978 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22981 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22985 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22986 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22988 remoteSort : false,
22991 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22992 * loaded or when a record is removed. (defaults to false).
22994 pruneModifiedRecords : false,
22997 lastOptions : null,
23000 * Add Records to the Store and fires the add event.
23001 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23003 add : function(records){
23004 records = [].concat(records);
23005 for(var i = 0, len = records.length; i < len; i++){
23006 records[i].join(this);
23008 var index = this.data.length;
23009 this.data.addAll(records);
23010 this.fireEvent("add", this, records, index);
23014 * Remove a Record from the Store and fires the remove event.
23015 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23017 remove : function(record){
23018 var index = this.data.indexOf(record);
23019 this.data.removeAt(index);
23021 if(this.pruneModifiedRecords){
23022 this.modified.remove(record);
23024 this.fireEvent("remove", this, record, index);
23028 * Remove all Records from the Store and fires the clear event.
23030 removeAll : function(){
23032 if(this.pruneModifiedRecords){
23033 this.modified = [];
23035 this.fireEvent("clear", this);
23039 * Inserts Records to the Store at the given index and fires the add event.
23040 * @param {Number} index The start index at which to insert the passed Records.
23041 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23043 insert : function(index, records){
23044 records = [].concat(records);
23045 for(var i = 0, len = records.length; i < len; i++){
23046 this.data.insert(index, records[i]);
23047 records[i].join(this);
23049 this.fireEvent("add", this, records, index);
23053 * Get the index within the cache of the passed Record.
23054 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23055 * @return {Number} The index of the passed Record. Returns -1 if not found.
23057 indexOf : function(record){
23058 return this.data.indexOf(record);
23062 * Get the index within the cache of the Record with the passed id.
23063 * @param {String} id The id of the Record to find.
23064 * @return {Number} The index of the Record. Returns -1 if not found.
23066 indexOfId : function(id){
23067 return this.data.indexOfKey(id);
23071 * Get the Record with the specified id.
23072 * @param {String} id The id of the Record to find.
23073 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23075 getById : function(id){
23076 return this.data.key(id);
23080 * Get the Record at the specified index.
23081 * @param {Number} index The index of the Record to find.
23082 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23084 getAt : function(index){
23085 return this.data.itemAt(index);
23089 * Returns a range of Records between specified indices.
23090 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23091 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23092 * @return {Roo.data.Record[]} An array of Records
23094 getRange : function(start, end){
23095 return this.data.getRange(start, end);
23099 storeOptions : function(o){
23100 o = Roo.apply({}, o);
23103 this.lastOptions = o;
23107 * Loads the Record cache from the configured Proxy using the configured Reader.
23109 * If using remote paging, then the first load call must specify the <em>start</em>
23110 * and <em>limit</em> properties in the options.params property to establish the initial
23111 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23113 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23114 * and this call will return before the new data has been loaded. Perform any post-processing
23115 * in a callback function, or in a "load" event handler.</strong>
23117 * @param {Object} options An object containing properties which control loading options:<ul>
23118 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23119 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23120 * passed the following arguments:<ul>
23121 * <li>r : Roo.data.Record[]</li>
23122 * <li>options: Options object from the load call</li>
23123 * <li>success: Boolean success indicator</li></ul></li>
23124 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23125 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23128 load : function(options){
23129 options = options || {};
23130 if(this.fireEvent("beforeload", this, options) !== false){
23131 this.storeOptions(options);
23132 var p = Roo.apply(options.params || {}, this.baseParams);
23133 // if meta was not loaded from remote source.. try requesting it.
23134 if (!this.reader.metaFromRemote) {
23135 p._requestMeta = 1;
23137 if(this.sortInfo && this.remoteSort){
23138 var pn = this.paramNames;
23139 p[pn["sort"]] = this.sortInfo.field;
23140 p[pn["dir"]] = this.sortInfo.direction;
23142 if (this.multiSort) {
23143 var pn = this.paramNames;
23144 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23147 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23152 * Reloads the Record cache from the configured Proxy using the configured Reader and
23153 * the options from the last load operation performed.
23154 * @param {Object} options (optional) An object containing properties which may override the options
23155 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23156 * the most recently used options are reused).
23158 reload : function(options){
23159 this.load(Roo.applyIf(options||{}, this.lastOptions));
23163 // Called as a callback by the Reader during a load operation.
23164 loadRecords : function(o, options, success){
23165 if(!o || success === false){
23166 if(success !== false){
23167 this.fireEvent("load", this, [], options, o);
23169 if(options.callback){
23170 options.callback.call(options.scope || this, [], options, false);
23174 // if data returned failure - throw an exception.
23175 if (o.success === false) {
23176 // show a message if no listener is registered.
23177 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23178 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23180 // loadmask wil be hooked into this..
23181 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23184 var r = o.records, t = o.totalRecords || r.length;
23186 this.fireEvent("beforeloadadd", this, r, options, o);
23188 if(!options || options.add !== true){
23189 if(this.pruneModifiedRecords){
23190 this.modified = [];
23192 for(var i = 0, len = r.length; i < len; i++){
23196 this.data = this.snapshot;
23197 delete this.snapshot;
23200 this.data.addAll(r);
23201 this.totalLength = t;
23203 this.fireEvent("datachanged", this);
23205 this.totalLength = Math.max(t, this.data.length+r.length);
23209 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23211 var e = new Roo.data.Record({});
23213 e.set(this.parent.displayField, this.parent.emptyTitle);
23214 e.set(this.parent.valueField, '');
23219 this.fireEvent("load", this, r, options, o);
23220 if(options.callback){
23221 options.callback.call(options.scope || this, r, options, true);
23227 * Loads data from a passed data block. A Reader which understands the format of the data
23228 * must have been configured in the constructor.
23229 * @param {Object} data The data block from which to read the Records. The format of the data expected
23230 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23231 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23233 loadData : function(o, append){
23234 var r = this.reader.readRecords(o);
23235 this.loadRecords(r, {add: append}, true);
23239 * Gets the number of cached records.
23241 * <em>If using paging, this may not be the total size of the dataset. If the data object
23242 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23243 * the data set size</em>
23245 getCount : function(){
23246 return this.data.length || 0;
23250 * Gets the total number of records in the dataset as returned by the server.
23252 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23253 * the dataset size</em>
23255 getTotalCount : function(){
23256 return this.totalLength || 0;
23260 * Returns the sort state of the Store as an object with two properties:
23262 field {String} The name of the field by which the Records are sorted
23263 direction {String} The sort order, "ASC" or "DESC"
23266 getSortState : function(){
23267 return this.sortInfo;
23271 applySort : function(){
23272 if(this.sortInfo && !this.remoteSort){
23273 var s = this.sortInfo, f = s.field;
23274 var st = this.fields.get(f).sortType;
23275 var fn = function(r1, r2){
23276 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23277 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23279 this.data.sort(s.direction, fn);
23280 if(this.snapshot && this.snapshot != this.data){
23281 this.snapshot.sort(s.direction, fn);
23287 * Sets the default sort column and order to be used by the next load operation.
23288 * @param {String} fieldName The name of the field to sort by.
23289 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23291 setDefaultSort : function(field, dir){
23292 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23296 * Sort the Records.
23297 * If remote sorting is used, the sort is performed on the server, and the cache is
23298 * reloaded. If local sorting is used, the cache is sorted internally.
23299 * @param {String} fieldName The name of the field to sort by.
23300 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23302 sort : function(fieldName, dir){
23303 var f = this.fields.get(fieldName);
23305 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23307 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23308 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23313 this.sortToggle[f.name] = dir;
23314 this.sortInfo = {field: f.name, direction: dir};
23315 if(!this.remoteSort){
23317 this.fireEvent("datachanged", this);
23319 this.load(this.lastOptions);
23324 * Calls the specified function for each of the Records in the cache.
23325 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23326 * Returning <em>false</em> aborts and exits the iteration.
23327 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23329 each : function(fn, scope){
23330 this.data.each(fn, scope);
23334 * Gets all records modified since the last commit. Modified records are persisted across load operations
23335 * (e.g., during paging).
23336 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23338 getModifiedRecords : function(){
23339 return this.modified;
23343 createFilterFn : function(property, value, anyMatch){
23344 if(!value.exec){ // not a regex
23345 value = String(value);
23346 if(value.length == 0){
23349 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23351 return function(r){
23352 return value.test(r.data[property]);
23357 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23358 * @param {String} property A field on your records
23359 * @param {Number} start The record index to start at (defaults to 0)
23360 * @param {Number} end The last record index to include (defaults to length - 1)
23361 * @return {Number} The sum
23363 sum : function(property, start, end){
23364 var rs = this.data.items, v = 0;
23365 start = start || 0;
23366 end = (end || end === 0) ? end : rs.length-1;
23368 for(var i = start; i <= end; i++){
23369 v += (rs[i].data[property] || 0);
23375 * Filter the records by a specified property.
23376 * @param {String} field A field on your records
23377 * @param {String/RegExp} value Either a string that the field
23378 * should start with or a RegExp to test against the field
23379 * @param {Boolean} anyMatch True to match any part not just the beginning
23381 filter : function(property, value, anyMatch){
23382 var fn = this.createFilterFn(property, value, anyMatch);
23383 return fn ? this.filterBy(fn) : this.clearFilter();
23387 * Filter by a function. The specified function will be called with each
23388 * record in this data source. If the function returns true the record is included,
23389 * otherwise it is filtered.
23390 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23391 * @param {Object} scope (optional) The scope of the function (defaults to this)
23393 filterBy : function(fn, scope){
23394 this.snapshot = this.snapshot || this.data;
23395 this.data = this.queryBy(fn, scope||this);
23396 this.fireEvent("datachanged", this);
23400 * Query the records by a specified property.
23401 * @param {String} field A field on your records
23402 * @param {String/RegExp} value Either a string that the field
23403 * should start with or a RegExp to test against the field
23404 * @param {Boolean} anyMatch True to match any part not just the beginning
23405 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23407 query : function(property, value, anyMatch){
23408 var fn = this.createFilterFn(property, value, anyMatch);
23409 return fn ? this.queryBy(fn) : this.data.clone();
23413 * Query by a function. The specified function will be called with each
23414 * record in this data source. If the function returns true the record is included
23416 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23417 * @param {Object} scope (optional) The scope of the function (defaults to this)
23418 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23420 queryBy : function(fn, scope){
23421 var data = this.snapshot || this.data;
23422 return data.filterBy(fn, scope||this);
23426 * Collects unique values for a particular dataIndex from this store.
23427 * @param {String} dataIndex The property to collect
23428 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23429 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23430 * @return {Array} An array of the unique values
23432 collect : function(dataIndex, allowNull, bypassFilter){
23433 var d = (bypassFilter === true && this.snapshot) ?
23434 this.snapshot.items : this.data.items;
23435 var v, sv, r = [], l = {};
23436 for(var i = 0, len = d.length; i < len; i++){
23437 v = d[i].data[dataIndex];
23439 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23448 * Revert to a view of the Record cache with no filtering applied.
23449 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23451 clearFilter : function(suppressEvent){
23452 if(this.snapshot && this.snapshot != this.data){
23453 this.data = this.snapshot;
23454 delete this.snapshot;
23455 if(suppressEvent !== true){
23456 this.fireEvent("datachanged", this);
23462 afterEdit : function(record){
23463 if(this.modified.indexOf(record) == -1){
23464 this.modified.push(record);
23466 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23470 afterReject : function(record){
23471 this.modified.remove(record);
23472 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23476 afterCommit : function(record){
23477 this.modified.remove(record);
23478 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23482 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23483 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23485 commitChanges : function(){
23486 var m = this.modified.slice(0);
23487 this.modified = [];
23488 for(var i = 0, len = m.length; i < len; i++){
23494 * Cancel outstanding changes on all changed records.
23496 rejectChanges : function(){
23497 var m = this.modified.slice(0);
23498 this.modified = [];
23499 for(var i = 0, len = m.length; i < len; i++){
23504 onMetaChange : function(meta, rtype, o){
23505 this.recordType = rtype;
23506 this.fields = rtype.prototype.fields;
23507 delete this.snapshot;
23508 this.sortInfo = meta.sortInfo || this.sortInfo;
23509 this.modified = [];
23510 this.fireEvent('metachange', this, this.reader.meta);
23513 moveIndex : function(data, type)
23515 var index = this.indexOf(data);
23517 var newIndex = index + type;
23521 this.insert(newIndex, data);
23526 * Ext JS Library 1.1.1
23527 * Copyright(c) 2006-2007, Ext JS, LLC.
23529 * Originally Released Under LGPL - original licence link has changed is not relivant.
23532 * <script type="text/javascript">
23536 * @class Roo.data.SimpleStore
23537 * @extends Roo.data.Store
23538 * Small helper class to make creating Stores from Array data easier.
23539 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23540 * @cfg {Array} fields An array of field definition objects, or field name strings.
23541 * @cfg {Array} data The multi-dimensional array of data
23543 * @param {Object} config
23545 Roo.data.SimpleStore = function(config){
23546 Roo.data.SimpleStore.superclass.constructor.call(this, {
23548 reader: new Roo.data.ArrayReader({
23551 Roo.data.Record.create(config.fields)
23553 proxy : new Roo.data.MemoryProxy(config.data)
23557 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23559 * Ext JS Library 1.1.1
23560 * Copyright(c) 2006-2007, Ext JS, LLC.
23562 * Originally Released Under LGPL - original licence link has changed is not relivant.
23565 * <script type="text/javascript">
23570 * @extends Roo.data.Store
23571 * @class Roo.data.JsonStore
23572 * Small helper class to make creating Stores for JSON data easier. <br/>
23574 var store = new Roo.data.JsonStore({
23575 url: 'get-images.php',
23577 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23580 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23581 * JsonReader and HttpProxy (unless inline data is provided).</b>
23582 * @cfg {Array} fields An array of field definition objects, or field name strings.
23584 * @param {Object} config
23586 Roo.data.JsonStore = function(c){
23587 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23588 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23589 reader: new Roo.data.JsonReader(c, c.fields)
23592 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23604 Roo.data.Field = function(config){
23605 if(typeof config == "string"){
23606 config = {name: config};
23608 Roo.apply(this, config);
23611 this.type = "auto";
23614 var st = Roo.data.SortTypes;
23615 // named sortTypes are supported, here we look them up
23616 if(typeof this.sortType == "string"){
23617 this.sortType = st[this.sortType];
23620 // set default sortType for strings and dates
23621 if(!this.sortType){
23624 this.sortType = st.asUCString;
23627 this.sortType = st.asDate;
23630 this.sortType = st.none;
23635 var stripRe = /[\$,%]/g;
23637 // prebuilt conversion function for this field, instead of
23638 // switching every time we're reading a value
23640 var cv, dateFormat = this.dateFormat;
23645 cv = function(v){ return v; };
23648 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23652 return v !== undefined && v !== null && v !== '' ?
23653 parseInt(String(v).replace(stripRe, ""), 10) : '';
23658 return v !== undefined && v !== null && v !== '' ?
23659 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23664 cv = function(v){ return v === true || v === "true" || v == 1; };
23671 if(v instanceof Date){
23675 if(dateFormat == "timestamp"){
23676 return new Date(v*1000);
23678 return Date.parseDate(v, dateFormat);
23680 var parsed = Date.parse(v);
23681 return parsed ? new Date(parsed) : null;
23690 Roo.data.Field.prototype = {
23698 * Ext JS Library 1.1.1
23699 * Copyright(c) 2006-2007, Ext JS, LLC.
23701 * Originally Released Under LGPL - original licence link has changed is not relivant.
23704 * <script type="text/javascript">
23707 // Base class for reading structured data from a data source. This class is intended to be
23708 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23711 * @class Roo.data.DataReader
23712 * Base class for reading structured data from a data source. This class is intended to be
23713 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23716 Roo.data.DataReader = function(meta, recordType){
23720 this.recordType = recordType instanceof Array ?
23721 Roo.data.Record.create(recordType) : recordType;
23724 Roo.data.DataReader.prototype = {
23726 * Create an empty record
23727 * @param {Object} data (optional) - overlay some values
23728 * @return {Roo.data.Record} record created.
23730 newRow : function(d) {
23732 this.recordType.prototype.fields.each(function(c) {
23734 case 'int' : da[c.name] = 0; break;
23735 case 'date' : da[c.name] = new Date(); break;
23736 case 'float' : da[c.name] = 0.0; break;
23737 case 'boolean' : da[c.name] = false; break;
23738 default : da[c.name] = ""; break;
23742 return new this.recordType(Roo.apply(da, d));
23747 * Ext JS Library 1.1.1
23748 * Copyright(c) 2006-2007, Ext JS, LLC.
23750 * Originally Released Under LGPL - original licence link has changed is not relivant.
23753 * <script type="text/javascript">
23757 * @class Roo.data.DataProxy
23758 * @extends Roo.data.Observable
23759 * This class is an abstract base class for implementations which provide retrieval of
23760 * unformatted data objects.<br>
23762 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23763 * (of the appropriate type which knows how to parse the data object) to provide a block of
23764 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23766 * Custom implementations must implement the load method as described in
23767 * {@link Roo.data.HttpProxy#load}.
23769 Roo.data.DataProxy = function(){
23772 * @event beforeload
23773 * Fires before a network request is made to retrieve a data object.
23774 * @param {Object} This DataProxy object.
23775 * @param {Object} params The params parameter to the load function.
23780 * Fires before the load method's callback is called.
23781 * @param {Object} This DataProxy object.
23782 * @param {Object} o The data object.
23783 * @param {Object} arg The callback argument object passed to the load function.
23787 * @event loadexception
23788 * Fires if an Exception occurs during data retrieval.
23789 * @param {Object} This DataProxy object.
23790 * @param {Object} o The data object.
23791 * @param {Object} arg The callback argument object passed to the load function.
23792 * @param {Object} e The Exception.
23794 loadexception : true
23796 Roo.data.DataProxy.superclass.constructor.call(this);
23799 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23802 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23806 * Ext JS Library 1.1.1
23807 * Copyright(c) 2006-2007, Ext JS, LLC.
23809 * Originally Released Under LGPL - original licence link has changed is not relivant.
23812 * <script type="text/javascript">
23815 * @class Roo.data.MemoryProxy
23816 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23817 * to the Reader when its load method is called.
23819 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23821 Roo.data.MemoryProxy = function(data){
23825 Roo.data.MemoryProxy.superclass.constructor.call(this);
23829 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23832 * Load data from the requested source (in this case an in-memory
23833 * data object passed to the constructor), read the data object into
23834 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23835 * process that block using the passed callback.
23836 * @param {Object} params This parameter is not used by the MemoryProxy class.
23837 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23838 * object into a block of Roo.data.Records.
23839 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23840 * The function must be passed <ul>
23841 * <li>The Record block object</li>
23842 * <li>The "arg" argument from the load function</li>
23843 * <li>A boolean success indicator</li>
23845 * @param {Object} scope The scope in which to call the callback
23846 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23848 load : function(params, reader, callback, scope, arg){
23849 params = params || {};
23852 result = reader.readRecords(this.data);
23854 this.fireEvent("loadexception", this, arg, null, e);
23855 callback.call(scope, null, arg, false);
23858 callback.call(scope, result, arg, true);
23862 update : function(params, records){
23867 * Ext JS Library 1.1.1
23868 * Copyright(c) 2006-2007, Ext JS, LLC.
23870 * Originally Released Under LGPL - original licence link has changed is not relivant.
23873 * <script type="text/javascript">
23876 * @class Roo.data.HttpProxy
23877 * @extends Roo.data.DataProxy
23878 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23879 * configured to reference a certain URL.<br><br>
23881 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23882 * from which the running page was served.<br><br>
23884 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23886 * Be aware that to enable the browser to parse an XML document, the server must set
23887 * the Content-Type header in the HTTP response to "text/xml".
23889 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23890 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23891 * will be used to make the request.
23893 Roo.data.HttpProxy = function(conn){
23894 Roo.data.HttpProxy.superclass.constructor.call(this);
23895 // is conn a conn config or a real conn?
23897 this.useAjax = !conn || !conn.events;
23901 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23902 // thse are take from connection...
23905 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23908 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23909 * extra parameters to each request made by this object. (defaults to undefined)
23912 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23913 * to each request made by this object. (defaults to undefined)
23916 * @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)
23919 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23922 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23928 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23932 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23933 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23934 * a finer-grained basis than the DataProxy events.
23936 getConnection : function(){
23937 return this.useAjax ? Roo.Ajax : this.conn;
23941 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23942 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23943 * process that block using the passed callback.
23944 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23945 * for the request to the remote server.
23946 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23947 * object into a block of Roo.data.Records.
23948 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23949 * The function must be passed <ul>
23950 * <li>The Record block object</li>
23951 * <li>The "arg" argument from the load function</li>
23952 * <li>A boolean success indicator</li>
23954 * @param {Object} scope The scope in which to call the callback
23955 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23957 load : function(params, reader, callback, scope, arg){
23958 if(this.fireEvent("beforeload", this, params) !== false){
23960 params : params || {},
23962 callback : callback,
23967 callback : this.loadResponse,
23971 Roo.applyIf(o, this.conn);
23972 if(this.activeRequest){
23973 Roo.Ajax.abort(this.activeRequest);
23975 this.activeRequest = Roo.Ajax.request(o);
23977 this.conn.request(o);
23980 callback.call(scope||this, null, arg, false);
23985 loadResponse : function(o, success, response){
23986 delete this.activeRequest;
23988 this.fireEvent("loadexception", this, o, response);
23989 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23994 result = o.reader.read(response);
23996 this.fireEvent("loadexception", this, o, response, e);
23997 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24001 this.fireEvent("load", this, o, o.request.arg);
24002 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24006 update : function(dataSet){
24011 updateResponse : function(dataSet){
24016 * Ext JS Library 1.1.1
24017 * Copyright(c) 2006-2007, Ext JS, LLC.
24019 * Originally Released Under LGPL - original licence link has changed is not relivant.
24022 * <script type="text/javascript">
24026 * @class Roo.data.ScriptTagProxy
24027 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24028 * other than the originating domain of the running page.<br><br>
24030 * <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
24031 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24033 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24034 * source code that is used as the source inside a <script> tag.<br><br>
24036 * In order for the browser to process the returned data, the server must wrap the data object
24037 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24038 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24039 * depending on whether the callback name was passed:
24042 boolean scriptTag = false;
24043 String cb = request.getParameter("callback");
24046 response.setContentType("text/javascript");
24048 response.setContentType("application/x-json");
24050 Writer out = response.getWriter();
24052 out.write(cb + "(");
24054 out.print(dataBlock.toJsonString());
24061 * @param {Object} config A configuration object.
24063 Roo.data.ScriptTagProxy = function(config){
24064 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24065 Roo.apply(this, config);
24066 this.head = document.getElementsByTagName("head")[0];
24069 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24071 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24073 * @cfg {String} url The URL from which to request the data object.
24076 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24080 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24081 * the server the name of the callback function set up by the load call to process the returned data object.
24082 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24083 * javascript output which calls this named function passing the data object as its only parameter.
24085 callbackParam : "callback",
24087 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24088 * name to the request.
24093 * Load data from the configured URL, read the data object into
24094 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24095 * process that block using the passed callback.
24096 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24097 * for the request to the remote server.
24098 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24099 * object into a block of Roo.data.Records.
24100 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24101 * The function must be passed <ul>
24102 * <li>The Record block object</li>
24103 * <li>The "arg" argument from the load function</li>
24104 * <li>A boolean success indicator</li>
24106 * @param {Object} scope The scope in which to call the callback
24107 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24109 load : function(params, reader, callback, scope, arg){
24110 if(this.fireEvent("beforeload", this, params) !== false){
24112 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24114 var url = this.url;
24115 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24117 url += "&_dc=" + (new Date().getTime());
24119 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24122 cb : "stcCallback"+transId,
24123 scriptId : "stcScript"+transId,
24127 callback : callback,
24133 window[trans.cb] = function(o){
24134 conn.handleResponse(o, trans);
24137 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24139 if(this.autoAbort !== false){
24143 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24145 var script = document.createElement("script");
24146 script.setAttribute("src", url);
24147 script.setAttribute("type", "text/javascript");
24148 script.setAttribute("id", trans.scriptId);
24149 this.head.appendChild(script);
24151 this.trans = trans;
24153 callback.call(scope||this, null, arg, false);
24158 isLoading : function(){
24159 return this.trans ? true : false;
24163 * Abort the current server request.
24165 abort : function(){
24166 if(this.isLoading()){
24167 this.destroyTrans(this.trans);
24172 destroyTrans : function(trans, isLoaded){
24173 this.head.removeChild(document.getElementById(trans.scriptId));
24174 clearTimeout(trans.timeoutId);
24176 window[trans.cb] = undefined;
24178 delete window[trans.cb];
24181 // if hasn't been loaded, wait for load to remove it to prevent script error
24182 window[trans.cb] = function(){
24183 window[trans.cb] = undefined;
24185 delete window[trans.cb];
24192 handleResponse : function(o, trans){
24193 this.trans = false;
24194 this.destroyTrans(trans, true);
24197 result = trans.reader.readRecords(o);
24199 this.fireEvent("loadexception", this, o, trans.arg, e);
24200 trans.callback.call(trans.scope||window, null, trans.arg, false);
24203 this.fireEvent("load", this, o, trans.arg);
24204 trans.callback.call(trans.scope||window, result, trans.arg, true);
24208 handleFailure : function(trans){
24209 this.trans = false;
24210 this.destroyTrans(trans, false);
24211 this.fireEvent("loadexception", this, null, trans.arg);
24212 trans.callback.call(trans.scope||window, null, trans.arg, false);
24216 * Ext JS Library 1.1.1
24217 * Copyright(c) 2006-2007, Ext JS, LLC.
24219 * Originally Released Under LGPL - original licence link has changed is not relivant.
24222 * <script type="text/javascript">
24226 * @class Roo.data.JsonReader
24227 * @extends Roo.data.DataReader
24228 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24229 * based on mappings in a provided Roo.data.Record constructor.
24231 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24232 * in the reply previously.
24237 var RecordDef = Roo.data.Record.create([
24238 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24239 {name: 'occupation'} // This field will use "occupation" as the mapping.
24241 var myReader = new Roo.data.JsonReader({
24242 totalProperty: "results", // The property which contains the total dataset size (optional)
24243 root: "rows", // The property which contains an Array of row objects
24244 id: "id" // The property within each row object that provides an ID for the record (optional)
24248 * This would consume a JSON file like this:
24250 { 'results': 2, 'rows': [
24251 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24252 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24255 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24256 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24257 * paged from the remote server.
24258 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24259 * @cfg {String} root name of the property which contains the Array of row objects.
24260 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24261 * @cfg {Array} fields Array of field definition objects
24263 * Create a new JsonReader
24264 * @param {Object} meta Metadata configuration options
24265 * @param {Object} recordType Either an Array of field definition objects,
24266 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24268 Roo.data.JsonReader = function(meta, recordType){
24271 // set some defaults:
24272 Roo.applyIf(meta, {
24273 totalProperty: 'total',
24274 successProperty : 'success',
24279 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24281 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24284 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24285 * Used by Store query builder to append _requestMeta to params.
24288 metaFromRemote : false,
24290 * This method is only used by a DataProxy which has retrieved data from a remote server.
24291 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24292 * @return {Object} data A data block which is used by an Roo.data.Store object as
24293 * a cache of Roo.data.Records.
24295 read : function(response){
24296 var json = response.responseText;
24298 var o = /* eval:var:o */ eval("("+json+")");
24300 throw {message: "JsonReader.read: Json object not found"};
24306 this.metaFromRemote = true;
24307 this.meta = o.metaData;
24308 this.recordType = Roo.data.Record.create(o.metaData.fields);
24309 this.onMetaChange(this.meta, this.recordType, o);
24311 return this.readRecords(o);
24314 // private function a store will implement
24315 onMetaChange : function(meta, recordType, o){
24322 simpleAccess: function(obj, subsc) {
24329 getJsonAccessor: function(){
24331 return function(expr) {
24333 return(re.test(expr))
24334 ? new Function("obj", "return obj." + expr)
24339 return Roo.emptyFn;
24344 * Create a data block containing Roo.data.Records from an XML document.
24345 * @param {Object} o An object which contains an Array of row objects in the property specified
24346 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24347 * which contains the total size of the dataset.
24348 * @return {Object} data A data block which is used by an Roo.data.Store object as
24349 * a cache of Roo.data.Records.
24351 readRecords : function(o){
24353 * After any data loads, the raw JSON data is available for further custom processing.
24357 var s = this.meta, Record = this.recordType,
24358 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24360 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24362 if(s.totalProperty) {
24363 this.getTotal = this.getJsonAccessor(s.totalProperty);
24365 if(s.successProperty) {
24366 this.getSuccess = this.getJsonAccessor(s.successProperty);
24368 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24370 var g = this.getJsonAccessor(s.id);
24371 this.getId = function(rec) {
24373 return (r === undefined || r === "") ? null : r;
24376 this.getId = function(){return null;};
24379 for(var jj = 0; jj < fl; jj++){
24381 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24382 this.ef[jj] = this.getJsonAccessor(map);
24386 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24387 if(s.totalProperty){
24388 var vt = parseInt(this.getTotal(o), 10);
24393 if(s.successProperty){
24394 var vs = this.getSuccess(o);
24395 if(vs === false || vs === 'false'){
24400 for(var i = 0; i < c; i++){
24403 var id = this.getId(n);
24404 for(var j = 0; j < fl; j++){
24406 var v = this.ef[j](n);
24408 Roo.log('missing convert for ' + f.name);
24412 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24414 var record = new Record(values, id);
24416 records[i] = record;
24422 totalRecords : totalRecords
24427 * Ext JS Library 1.1.1
24428 * Copyright(c) 2006-2007, Ext JS, LLC.
24430 * Originally Released Under LGPL - original licence link has changed is not relivant.
24433 * <script type="text/javascript">
24437 * @class Roo.data.XmlReader
24438 * @extends Roo.data.DataReader
24439 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24440 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24442 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24443 * header in the HTTP response must be set to "text/xml".</em>
24447 var RecordDef = Roo.data.Record.create([
24448 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24449 {name: 'occupation'} // This field will use "occupation" as the mapping.
24451 var myReader = new Roo.data.XmlReader({
24452 totalRecords: "results", // The element which contains the total dataset size (optional)
24453 record: "row", // The repeated element which contains row information
24454 id: "id" // The element within the row that provides an ID for the record (optional)
24458 * This would consume an XML file like this:
24462 <results>2</results>
24465 <name>Bill</name>
24466 <occupation>Gardener</occupation>
24470 <name>Ben</name>
24471 <occupation>Horticulturalist</occupation>
24475 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24476 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24477 * paged from the remote server.
24478 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24479 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24480 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24481 * a record identifier value.
24483 * Create a new XmlReader
24484 * @param {Object} meta Metadata configuration options
24485 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24486 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24487 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24489 Roo.data.XmlReader = function(meta, recordType){
24491 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24493 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24495 * This method is only used by a DataProxy which has retrieved data from a remote server.
24496 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24497 * to contain a method called 'responseXML' that returns an XML document object.
24498 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24499 * a cache of Roo.data.Records.
24501 read : function(response){
24502 var doc = response.responseXML;
24504 throw {message: "XmlReader.read: XML Document not available"};
24506 return this.readRecords(doc);
24510 * Create a data block containing Roo.data.Records from an XML document.
24511 * @param {Object} doc A parsed XML document.
24512 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24513 * a cache of Roo.data.Records.
24515 readRecords : function(doc){
24517 * After any data loads/reads, the raw XML Document is available for further custom processing.
24518 * @type XMLDocument
24520 this.xmlData = doc;
24521 var root = doc.documentElement || doc;
24522 var q = Roo.DomQuery;
24523 var recordType = this.recordType, fields = recordType.prototype.fields;
24524 var sid = this.meta.id;
24525 var totalRecords = 0, success = true;
24526 if(this.meta.totalRecords){
24527 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24530 if(this.meta.success){
24531 var sv = q.selectValue(this.meta.success, root, true);
24532 success = sv !== false && sv !== 'false';
24535 var ns = q.select(this.meta.record, root);
24536 for(var i = 0, len = ns.length; i < len; i++) {
24539 var id = sid ? q.selectValue(sid, n) : undefined;
24540 for(var j = 0, jlen = fields.length; j < jlen; j++){
24541 var f = fields.items[j];
24542 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24544 values[f.name] = v;
24546 var record = new recordType(values, id);
24548 records[records.length] = record;
24554 totalRecords : totalRecords || records.length
24559 * Ext JS Library 1.1.1
24560 * Copyright(c) 2006-2007, Ext JS, LLC.
24562 * Originally Released Under LGPL - original licence link has changed is not relivant.
24565 * <script type="text/javascript">
24569 * @class Roo.data.ArrayReader
24570 * @extends Roo.data.DataReader
24571 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24572 * Each element of that Array represents a row of data fields. The
24573 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24574 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24578 var RecordDef = Roo.data.Record.create([
24579 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24580 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24582 var myReader = new Roo.data.ArrayReader({
24583 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24587 * This would consume an Array like this:
24589 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24591 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24593 * Create a new JsonReader
24594 * @param {Object} meta Metadata configuration options.
24595 * @param {Object} recordType Either an Array of field definition objects
24596 * as specified to {@link Roo.data.Record#create},
24597 * or an {@link Roo.data.Record} object
24598 * created using {@link Roo.data.Record#create}.
24600 Roo.data.ArrayReader = function(meta, recordType){
24601 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24604 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24606 * Create a data block containing Roo.data.Records from an XML document.
24607 * @param {Object} o An Array of row objects which represents the dataset.
24608 * @return {Object} data A data block which is used by an Roo.data.Store object as
24609 * a cache of Roo.data.Records.
24611 readRecords : function(o){
24612 var sid = this.meta ? this.meta.id : null;
24613 var recordType = this.recordType, fields = recordType.prototype.fields;
24616 for(var i = 0; i < root.length; i++){
24619 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24620 for(var j = 0, jlen = fields.length; j < jlen; j++){
24621 var f = fields.items[j];
24622 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24623 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24625 values[f.name] = v;
24627 var record = new recordType(values, id);
24629 records[records.length] = record;
24633 totalRecords : records.length
24638 * Ext JS Library 1.1.1
24639 * Copyright(c) 2006-2007, Ext JS, LLC.
24641 * Originally Released Under LGPL - original licence link has changed is not relivant.
24644 * <script type="text/javascript">
24649 * @class Roo.data.Tree
24650 * @extends Roo.util.Observable
24651 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24652 * in the tree have most standard DOM functionality.
24654 * @param {Node} root (optional) The root node
24656 Roo.data.Tree = function(root){
24657 this.nodeHash = {};
24659 * The root node for this tree
24664 this.setRootNode(root);
24669 * Fires when a new child node is appended to a node in this tree.
24670 * @param {Tree} tree The owner tree
24671 * @param {Node} parent The parent node
24672 * @param {Node} node The newly appended node
24673 * @param {Number} index The index of the newly appended node
24678 * Fires when a child node is removed from a node in this tree.
24679 * @param {Tree} tree The owner tree
24680 * @param {Node} parent The parent node
24681 * @param {Node} node The child node removed
24686 * Fires when a node is moved to a new location in the tree
24687 * @param {Tree} tree The owner tree
24688 * @param {Node} node The node moved
24689 * @param {Node} oldParent The old parent of this node
24690 * @param {Node} newParent The new parent of this node
24691 * @param {Number} index The index it was moved to
24696 * Fires when a new child node is inserted in a node in this tree.
24697 * @param {Tree} tree The owner tree
24698 * @param {Node} parent The parent node
24699 * @param {Node} node The child node inserted
24700 * @param {Node} refNode The child node the node was inserted before
24704 * @event beforeappend
24705 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24706 * @param {Tree} tree The owner tree
24707 * @param {Node} parent The parent node
24708 * @param {Node} node The child node to be appended
24710 "beforeappend" : true,
24712 * @event beforeremove
24713 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24714 * @param {Tree} tree The owner tree
24715 * @param {Node} parent The parent node
24716 * @param {Node} node The child node to be removed
24718 "beforeremove" : true,
24720 * @event beforemove
24721 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24722 * @param {Tree} tree The owner tree
24723 * @param {Node} node The node being moved
24724 * @param {Node} oldParent The parent of the node
24725 * @param {Node} newParent The new parent the node is moving to
24726 * @param {Number} index The index it is being moved to
24728 "beforemove" : true,
24730 * @event beforeinsert
24731 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24732 * @param {Tree} tree The owner tree
24733 * @param {Node} parent The parent node
24734 * @param {Node} node The child node to be inserted
24735 * @param {Node} refNode The child node the node is being inserted before
24737 "beforeinsert" : true
24740 Roo.data.Tree.superclass.constructor.call(this);
24743 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24744 pathSeparator: "/",
24746 proxyNodeEvent : function(){
24747 return this.fireEvent.apply(this, arguments);
24751 * Returns the root node for this tree.
24754 getRootNode : function(){
24759 * Sets the root node for this tree.
24760 * @param {Node} node
24763 setRootNode : function(node){
24765 node.ownerTree = this;
24766 node.isRoot = true;
24767 this.registerNode(node);
24772 * Gets a node in this tree by its id.
24773 * @param {String} id
24776 getNodeById : function(id){
24777 return this.nodeHash[id];
24780 registerNode : function(node){
24781 this.nodeHash[node.id] = node;
24784 unregisterNode : function(node){
24785 delete this.nodeHash[node.id];
24788 toString : function(){
24789 return "[Tree"+(this.id?" "+this.id:"")+"]";
24794 * @class Roo.data.Node
24795 * @extends Roo.util.Observable
24796 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24797 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24799 * @param {Object} attributes The attributes/config for the node
24801 Roo.data.Node = function(attributes){
24803 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24806 this.attributes = attributes || {};
24807 this.leaf = this.attributes.leaf;
24809 * The node id. @type String
24811 this.id = this.attributes.id;
24813 this.id = Roo.id(null, "ynode-");
24814 this.attributes.id = this.id;
24819 * All child nodes of this node. @type Array
24821 this.childNodes = [];
24822 if(!this.childNodes.indexOf){ // indexOf is a must
24823 this.childNodes.indexOf = function(o){
24824 for(var i = 0, len = this.length; i < len; i++){
24833 * The parent node for this node. @type Node
24835 this.parentNode = null;
24837 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24839 this.firstChild = null;
24841 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24843 this.lastChild = null;
24845 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24847 this.previousSibling = null;
24849 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24851 this.nextSibling = null;
24856 * Fires when a new child node is appended
24857 * @param {Tree} tree The owner tree
24858 * @param {Node} this This node
24859 * @param {Node} node The newly appended node
24860 * @param {Number} index The index of the newly appended node
24865 * Fires when a child node is removed
24866 * @param {Tree} tree The owner tree
24867 * @param {Node} this This node
24868 * @param {Node} node The removed node
24873 * Fires when this node is moved to a new location in the tree
24874 * @param {Tree} tree The owner tree
24875 * @param {Node} this This node
24876 * @param {Node} oldParent The old parent of this node
24877 * @param {Node} newParent The new parent of this node
24878 * @param {Number} index The index it was moved to
24883 * Fires when a new child node is inserted.
24884 * @param {Tree} tree The owner tree
24885 * @param {Node} this This node
24886 * @param {Node} node The child node inserted
24887 * @param {Node} refNode The child node the node was inserted before
24891 * @event beforeappend
24892 * Fires before a new child is appended, return false to cancel the append.
24893 * @param {Tree} tree The owner tree
24894 * @param {Node} this This node
24895 * @param {Node} node The child node to be appended
24897 "beforeappend" : true,
24899 * @event beforeremove
24900 * Fires before a child is removed, return false to cancel the remove.
24901 * @param {Tree} tree The owner tree
24902 * @param {Node} this This node
24903 * @param {Node} node The child node to be removed
24905 "beforeremove" : true,
24907 * @event beforemove
24908 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24909 * @param {Tree} tree The owner tree
24910 * @param {Node} this This node
24911 * @param {Node} oldParent The parent of this node
24912 * @param {Node} newParent The new parent this node is moving to
24913 * @param {Number} index The index it is being moved to
24915 "beforemove" : true,
24917 * @event beforeinsert
24918 * Fires before a new child is inserted, return false to cancel the insert.
24919 * @param {Tree} tree The owner tree
24920 * @param {Node} this This node
24921 * @param {Node} node The child node to be inserted
24922 * @param {Node} refNode The child node the node is being inserted before
24924 "beforeinsert" : true
24926 this.listeners = this.attributes.listeners;
24927 Roo.data.Node.superclass.constructor.call(this);
24930 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24931 fireEvent : function(evtName){
24932 // first do standard event for this node
24933 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24936 // then bubble it up to the tree if the event wasn't cancelled
24937 var ot = this.getOwnerTree();
24939 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24947 * Returns true if this node is a leaf
24948 * @return {Boolean}
24950 isLeaf : function(){
24951 return this.leaf === true;
24955 setFirstChild : function(node){
24956 this.firstChild = node;
24960 setLastChild : function(node){
24961 this.lastChild = node;
24966 * Returns true if this node is the last child of its parent
24967 * @return {Boolean}
24969 isLast : function(){
24970 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24974 * Returns true if this node is the first child of its parent
24975 * @return {Boolean}
24977 isFirst : function(){
24978 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24981 hasChildNodes : function(){
24982 return !this.isLeaf() && this.childNodes.length > 0;
24986 * Insert node(s) as the last child node of this node.
24987 * @param {Node/Array} node The node or Array of nodes to append
24988 * @return {Node} The appended node if single append, or null if an array was passed
24990 appendChild : function(node){
24992 if(node instanceof Array){
24994 }else if(arguments.length > 1){
24997 // if passed an array or multiple args do them one by one
24999 for(var i = 0, len = multi.length; i < len; i++) {
25000 this.appendChild(multi[i]);
25003 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25006 var index = this.childNodes.length;
25007 var oldParent = node.parentNode;
25008 // it's a move, make sure we move it cleanly
25010 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25013 oldParent.removeChild(node);
25015 index = this.childNodes.length;
25017 this.setFirstChild(node);
25019 this.childNodes.push(node);
25020 node.parentNode = this;
25021 var ps = this.childNodes[index-1];
25023 node.previousSibling = ps;
25024 ps.nextSibling = node;
25026 node.previousSibling = null;
25028 node.nextSibling = null;
25029 this.setLastChild(node);
25030 node.setOwnerTree(this.getOwnerTree());
25031 this.fireEvent("append", this.ownerTree, this, node, index);
25033 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25040 * Removes a child node from this node.
25041 * @param {Node} node The node to remove
25042 * @return {Node} The removed node
25044 removeChild : function(node){
25045 var index = this.childNodes.indexOf(node);
25049 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25053 // remove it from childNodes collection
25054 this.childNodes.splice(index, 1);
25057 if(node.previousSibling){
25058 node.previousSibling.nextSibling = node.nextSibling;
25060 if(node.nextSibling){
25061 node.nextSibling.previousSibling = node.previousSibling;
25064 // update child refs
25065 if(this.firstChild == node){
25066 this.setFirstChild(node.nextSibling);
25068 if(this.lastChild == node){
25069 this.setLastChild(node.previousSibling);
25072 node.setOwnerTree(null);
25073 // clear any references from the node
25074 node.parentNode = null;
25075 node.previousSibling = null;
25076 node.nextSibling = null;
25077 this.fireEvent("remove", this.ownerTree, this, node);
25082 * Inserts the first node before the second node in this nodes childNodes collection.
25083 * @param {Node} node The node to insert
25084 * @param {Node} refNode The node to insert before (if null the node is appended)
25085 * @return {Node} The inserted node
25087 insertBefore : function(node, refNode){
25088 if(!refNode){ // like standard Dom, refNode can be null for append
25089 return this.appendChild(node);
25092 if(node == refNode){
25096 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25099 var index = this.childNodes.indexOf(refNode);
25100 var oldParent = node.parentNode;
25101 var refIndex = index;
25103 // when moving internally, indexes will change after remove
25104 if(oldParent == this && this.childNodes.indexOf(node) < index){
25108 // it's a move, make sure we move it cleanly
25110 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25113 oldParent.removeChild(node);
25116 this.setFirstChild(node);
25118 this.childNodes.splice(refIndex, 0, node);
25119 node.parentNode = this;
25120 var ps = this.childNodes[refIndex-1];
25122 node.previousSibling = ps;
25123 ps.nextSibling = node;
25125 node.previousSibling = null;
25127 node.nextSibling = refNode;
25128 refNode.previousSibling = node;
25129 node.setOwnerTree(this.getOwnerTree());
25130 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25132 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25138 * Returns the child node at the specified index.
25139 * @param {Number} index
25142 item : function(index){
25143 return this.childNodes[index];
25147 * Replaces one child node in this node with another.
25148 * @param {Node} newChild The replacement node
25149 * @param {Node} oldChild The node to replace
25150 * @return {Node} The replaced node
25152 replaceChild : function(newChild, oldChild){
25153 this.insertBefore(newChild, oldChild);
25154 this.removeChild(oldChild);
25159 * Returns the index of a child node
25160 * @param {Node} node
25161 * @return {Number} The index of the node or -1 if it was not found
25163 indexOf : function(child){
25164 return this.childNodes.indexOf(child);
25168 * Returns the tree this node is in.
25171 getOwnerTree : function(){
25172 // if it doesn't have one, look for one
25173 if(!this.ownerTree){
25177 this.ownerTree = p.ownerTree;
25183 return this.ownerTree;
25187 * Returns depth of this node (the root node has a depth of 0)
25190 getDepth : function(){
25193 while(p.parentNode){
25201 setOwnerTree : function(tree){
25202 // if it's move, we need to update everyone
25203 if(tree != this.ownerTree){
25204 if(this.ownerTree){
25205 this.ownerTree.unregisterNode(this);
25207 this.ownerTree = tree;
25208 var cs = this.childNodes;
25209 for(var i = 0, len = cs.length; i < len; i++) {
25210 cs[i].setOwnerTree(tree);
25213 tree.registerNode(this);
25219 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25220 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25221 * @return {String} The path
25223 getPath : function(attr){
25224 attr = attr || "id";
25225 var p = this.parentNode;
25226 var b = [this.attributes[attr]];
25228 b.unshift(p.attributes[attr]);
25231 var sep = this.getOwnerTree().pathSeparator;
25232 return sep + b.join(sep);
25236 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25237 * function call will be the scope provided or the current node. The arguments to the function
25238 * will be the args provided or the current node. If the function returns false at any point,
25239 * the bubble is stopped.
25240 * @param {Function} fn The function to call
25241 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25242 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25244 bubble : function(fn, scope, args){
25247 if(fn.call(scope || p, args || p) === false){
25255 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25256 * function call will be the scope provided or the current node. The arguments to the function
25257 * will be the args provided or the current node. If the function returns false at any point,
25258 * the cascade is stopped on that branch.
25259 * @param {Function} fn The function to call
25260 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25261 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25263 cascade : function(fn, scope, args){
25264 if(fn.call(scope || this, args || this) !== false){
25265 var cs = this.childNodes;
25266 for(var i = 0, len = cs.length; i < len; i++) {
25267 cs[i].cascade(fn, scope, args);
25273 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25274 * function call will be the scope provided or the current node. The arguments to the function
25275 * will be the args provided or the current node. If the function returns false at any point,
25276 * the iteration stops.
25277 * @param {Function} fn The function to call
25278 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25279 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25281 eachChild : function(fn, scope, args){
25282 var cs = this.childNodes;
25283 for(var i = 0, len = cs.length; i < len; i++) {
25284 if(fn.call(scope || this, args || cs[i]) === false){
25291 * Finds the first child that has the attribute with the specified value.
25292 * @param {String} attribute The attribute name
25293 * @param {Mixed} value The value to search for
25294 * @return {Node} The found child or null if none was found
25296 findChild : function(attribute, value){
25297 var cs = this.childNodes;
25298 for(var i = 0, len = cs.length; i < len; i++) {
25299 if(cs[i].attributes[attribute] == value){
25307 * Finds the first child by a custom function. The child matches if the function passed
25309 * @param {Function} fn
25310 * @param {Object} scope (optional)
25311 * @return {Node} The found child or null if none was found
25313 findChildBy : function(fn, scope){
25314 var cs = this.childNodes;
25315 for(var i = 0, len = cs.length; i < len; i++) {
25316 if(fn.call(scope||cs[i], cs[i]) === true){
25324 * Sorts this nodes children using the supplied sort function
25325 * @param {Function} fn
25326 * @param {Object} scope (optional)
25328 sort : function(fn, scope){
25329 var cs = this.childNodes;
25330 var len = cs.length;
25332 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25334 for(var i = 0; i < len; i++){
25336 n.previousSibling = cs[i-1];
25337 n.nextSibling = cs[i+1];
25339 this.setFirstChild(n);
25342 this.setLastChild(n);
25349 * Returns true if this node is an ancestor (at any point) of the passed node.
25350 * @param {Node} node
25351 * @return {Boolean}
25353 contains : function(node){
25354 return node.isAncestor(this);
25358 * Returns true if the passed node is an ancestor (at any point) of this node.
25359 * @param {Node} node
25360 * @return {Boolean}
25362 isAncestor : function(node){
25363 var p = this.parentNode;
25373 toString : function(){
25374 return "[Node"+(this.id?" "+this.id:"")+"]";
25378 * Ext JS Library 1.1.1
25379 * Copyright(c) 2006-2007, Ext JS, LLC.
25381 * Originally Released Under LGPL - original licence link has changed is not relivant.
25384 * <script type="text/javascript">
25389 * @extends Roo.Element
25390 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25391 * automatic maintaining of shadow/shim positions.
25392 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25393 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25394 * you can pass a string with a CSS class name. False turns off the shadow.
25395 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25396 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25397 * @cfg {String} cls CSS class to add to the element
25398 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25399 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25401 * @param {Object} config An object with config options.
25402 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25405 Roo.Layer = function(config, existingEl){
25406 config = config || {};
25407 var dh = Roo.DomHelper;
25408 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25410 this.dom = Roo.getDom(existingEl);
25413 var o = config.dh || {tag: "div", cls: "x-layer"};
25414 this.dom = dh.append(pel, o);
25417 this.addClass(config.cls);
25419 this.constrain = config.constrain !== false;
25420 this.visibilityMode = Roo.Element.VISIBILITY;
25422 this.id = this.dom.id = config.id;
25424 this.id = Roo.id(this.dom);
25426 this.zindex = config.zindex || this.getZIndex();
25427 this.position("absolute", this.zindex);
25429 this.shadowOffset = config.shadowOffset || 4;
25430 this.shadow = new Roo.Shadow({
25431 offset : this.shadowOffset,
25432 mode : config.shadow
25435 this.shadowOffset = 0;
25437 this.useShim = config.shim !== false && Roo.useShims;
25438 this.useDisplay = config.useDisplay;
25442 var supr = Roo.Element.prototype;
25444 // shims are shared among layer to keep from having 100 iframes
25447 Roo.extend(Roo.Layer, Roo.Element, {
25449 getZIndex : function(){
25450 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25453 getShim : function(){
25460 var shim = shims.shift();
25462 shim = this.createShim();
25463 shim.enableDisplayMode('block');
25464 shim.dom.style.display = 'none';
25465 shim.dom.style.visibility = 'visible';
25467 var pn = this.dom.parentNode;
25468 if(shim.dom.parentNode != pn){
25469 pn.insertBefore(shim.dom, this.dom);
25471 shim.setStyle('z-index', this.getZIndex()-2);
25476 hideShim : function(){
25478 this.shim.setDisplayed(false);
25479 shims.push(this.shim);
25484 disableShadow : function(){
25486 this.shadowDisabled = true;
25487 this.shadow.hide();
25488 this.lastShadowOffset = this.shadowOffset;
25489 this.shadowOffset = 0;
25493 enableShadow : function(show){
25495 this.shadowDisabled = false;
25496 this.shadowOffset = this.lastShadowOffset;
25497 delete this.lastShadowOffset;
25505 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25506 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25507 sync : function(doShow){
25508 var sw = this.shadow;
25509 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25510 var sh = this.getShim();
25512 var w = this.getWidth(),
25513 h = this.getHeight();
25515 var l = this.getLeft(true),
25516 t = this.getTop(true);
25518 if(sw && !this.shadowDisabled){
25519 if(doShow && !sw.isVisible()){
25522 sw.realign(l, t, w, h);
25528 // fit the shim behind the shadow, so it is shimmed too
25529 var a = sw.adjusts, s = sh.dom.style;
25530 s.left = (Math.min(l, l+a.l))+"px";
25531 s.top = (Math.min(t, t+a.t))+"px";
25532 s.width = (w+a.w)+"px";
25533 s.height = (h+a.h)+"px";
25540 sh.setLeftTop(l, t);
25547 destroy : function(){
25550 this.shadow.hide();
25552 this.removeAllListeners();
25553 var pn = this.dom.parentNode;
25555 pn.removeChild(this.dom);
25557 Roo.Element.uncache(this.id);
25560 remove : function(){
25565 beginUpdate : function(){
25566 this.updating = true;
25570 endUpdate : function(){
25571 this.updating = false;
25576 hideUnders : function(negOffset){
25578 this.shadow.hide();
25584 constrainXY : function(){
25585 if(this.constrain){
25586 var vw = Roo.lib.Dom.getViewWidth(),
25587 vh = Roo.lib.Dom.getViewHeight();
25588 var s = Roo.get(document).getScroll();
25590 var xy = this.getXY();
25591 var x = xy[0], y = xy[1];
25592 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25593 // only move it if it needs it
25595 // first validate right/bottom
25596 if((x + w) > vw+s.left){
25597 x = vw - w - this.shadowOffset;
25600 if((y + h) > vh+s.top){
25601 y = vh - h - this.shadowOffset;
25604 // then make sure top/left isn't negative
25615 var ay = this.avoidY;
25616 if(y <= ay && (y+h) >= ay){
25622 supr.setXY.call(this, xy);
25628 isVisible : function(){
25629 return this.visible;
25633 showAction : function(){
25634 this.visible = true; // track visibility to prevent getStyle calls
25635 if(this.useDisplay === true){
25636 this.setDisplayed("");
25637 }else if(this.lastXY){
25638 supr.setXY.call(this, this.lastXY);
25639 }else if(this.lastLT){
25640 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25645 hideAction : function(){
25646 this.visible = false;
25647 if(this.useDisplay === true){
25648 this.setDisplayed(false);
25650 this.setLeftTop(-10000,-10000);
25654 // overridden Element method
25655 setVisible : function(v, a, d, c, e){
25660 var cb = function(){
25665 }.createDelegate(this);
25666 supr.setVisible.call(this, true, true, d, cb, e);
25669 this.hideUnders(true);
25678 }.createDelegate(this);
25680 supr.setVisible.call(this, v, a, d, cb, e);
25689 storeXY : function(xy){
25690 delete this.lastLT;
25694 storeLeftTop : function(left, top){
25695 delete this.lastXY;
25696 this.lastLT = [left, top];
25700 beforeFx : function(){
25701 this.beforeAction();
25702 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25706 afterFx : function(){
25707 Roo.Layer.superclass.afterFx.apply(this, arguments);
25708 this.sync(this.isVisible());
25712 beforeAction : function(){
25713 if(!this.updating && this.shadow){
25714 this.shadow.hide();
25718 // overridden Element method
25719 setLeft : function(left){
25720 this.storeLeftTop(left, this.getTop(true));
25721 supr.setLeft.apply(this, arguments);
25725 setTop : function(top){
25726 this.storeLeftTop(this.getLeft(true), top);
25727 supr.setTop.apply(this, arguments);
25731 setLeftTop : function(left, top){
25732 this.storeLeftTop(left, top);
25733 supr.setLeftTop.apply(this, arguments);
25737 setXY : function(xy, a, d, c, e){
25739 this.beforeAction();
25741 var cb = this.createCB(c);
25742 supr.setXY.call(this, xy, a, d, cb, e);
25749 createCB : function(c){
25760 // overridden Element method
25761 setX : function(x, a, d, c, e){
25762 this.setXY([x, this.getY()], a, d, c, e);
25765 // overridden Element method
25766 setY : function(y, a, d, c, e){
25767 this.setXY([this.getX(), y], a, d, c, e);
25770 // overridden Element method
25771 setSize : function(w, h, a, d, c, e){
25772 this.beforeAction();
25773 var cb = this.createCB(c);
25774 supr.setSize.call(this, w, h, a, d, cb, e);
25780 // overridden Element method
25781 setWidth : function(w, a, d, c, e){
25782 this.beforeAction();
25783 var cb = this.createCB(c);
25784 supr.setWidth.call(this, w, a, d, cb, e);
25790 // overridden Element method
25791 setHeight : function(h, a, d, c, e){
25792 this.beforeAction();
25793 var cb = this.createCB(c);
25794 supr.setHeight.call(this, h, a, d, cb, e);
25800 // overridden Element method
25801 setBounds : function(x, y, w, h, a, d, c, e){
25802 this.beforeAction();
25803 var cb = this.createCB(c);
25805 this.storeXY([x, y]);
25806 supr.setXY.call(this, [x, y]);
25807 supr.setSize.call(this, w, h, a, d, cb, e);
25810 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25816 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25817 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25818 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25819 * @param {Number} zindex The new z-index to set
25820 * @return {this} The Layer
25822 setZIndex : function(zindex){
25823 this.zindex = zindex;
25824 this.setStyle("z-index", zindex + 2);
25826 this.shadow.setZIndex(zindex + 1);
25829 this.shim.setStyle("z-index", zindex);
25835 * Ext JS Library 1.1.1
25836 * Copyright(c) 2006-2007, Ext JS, LLC.
25838 * Originally Released Under LGPL - original licence link has changed is not relivant.
25841 * <script type="text/javascript">
25846 * @class Roo.Shadow
25847 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25848 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25849 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25851 * Create a new Shadow
25852 * @param {Object} config The config object
25854 Roo.Shadow = function(config){
25855 Roo.apply(this, config);
25856 if(typeof this.mode != "string"){
25857 this.mode = this.defaultMode;
25859 var o = this.offset, a = {h: 0};
25860 var rad = Math.floor(this.offset/2);
25861 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25867 a.l -= this.offset + rad;
25868 a.t -= this.offset + rad;
25879 a.l -= (this.offset - rad);
25880 a.t -= this.offset + rad;
25882 a.w -= (this.offset - rad)*2;
25893 a.l -= (this.offset - rad);
25894 a.t -= (this.offset - rad);
25896 a.w -= (this.offset + rad + 1);
25897 a.h -= (this.offset + rad);
25906 Roo.Shadow.prototype = {
25908 * @cfg {String} mode
25909 * The shadow display mode. Supports the following options:<br />
25910 * sides: Shadow displays on both sides and bottom only<br />
25911 * frame: Shadow displays equally on all four sides<br />
25912 * drop: Traditional bottom-right drop shadow (default)
25915 * @cfg {String} offset
25916 * The number of pixels to offset the shadow from the element (defaults to 4)
25921 defaultMode: "drop",
25924 * Displays the shadow under the target element
25925 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25927 show : function(target){
25928 target = Roo.get(target);
25930 this.el = Roo.Shadow.Pool.pull();
25931 if(this.el.dom.nextSibling != target.dom){
25932 this.el.insertBefore(target);
25935 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25937 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25940 target.getLeft(true),
25941 target.getTop(true),
25945 this.el.dom.style.display = "block";
25949 * Returns true if the shadow is visible, else false
25951 isVisible : function(){
25952 return this.el ? true : false;
25956 * Direct alignment when values are already available. Show must be called at least once before
25957 * calling this method to ensure it is initialized.
25958 * @param {Number} left The target element left position
25959 * @param {Number} top The target element top position
25960 * @param {Number} width The target element width
25961 * @param {Number} height The target element height
25963 realign : function(l, t, w, h){
25967 var a = this.adjusts, d = this.el.dom, s = d.style;
25969 s.left = (l+a.l)+"px";
25970 s.top = (t+a.t)+"px";
25971 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25973 if(s.width != sws || s.height != shs){
25977 var cn = d.childNodes;
25978 var sww = Math.max(0, (sw-12))+"px";
25979 cn[0].childNodes[1].style.width = sww;
25980 cn[1].childNodes[1].style.width = sww;
25981 cn[2].childNodes[1].style.width = sww;
25982 cn[1].style.height = Math.max(0, (sh-12))+"px";
25988 * Hides this shadow
25992 this.el.dom.style.display = "none";
25993 Roo.Shadow.Pool.push(this.el);
25999 * Adjust the z-index of this shadow
26000 * @param {Number} zindex The new z-index
26002 setZIndex : function(z){
26005 this.el.setStyle("z-index", z);
26010 // Private utility class that manages the internal Shadow cache
26011 Roo.Shadow.Pool = function(){
26013 var markup = Roo.isIE ?
26014 '<div class="x-ie-shadow"></div>' :
26015 '<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>';
26018 var sh = p.shift();
26020 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26021 sh.autoBoxAdjust = false;
26026 push : function(sh){
26032 * Ext JS Library 1.1.1
26033 * Copyright(c) 2006-2007, Ext JS, LLC.
26035 * Originally Released Under LGPL - original licence link has changed is not relivant.
26038 * <script type="text/javascript">
26043 * @class Roo.SplitBar
26044 * @extends Roo.util.Observable
26045 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26049 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26050 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26051 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26052 split.minSize = 100;
26053 split.maxSize = 600;
26054 split.animate = true;
26055 split.on('moved', splitterMoved);
26058 * Create a new SplitBar
26059 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26060 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26061 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26062 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26063 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26064 position of the SplitBar).
26066 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26069 this.el = Roo.get(dragElement, true);
26070 this.el.dom.unselectable = "on";
26072 this.resizingEl = Roo.get(resizingElement, true);
26076 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26077 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26080 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26083 * The minimum size of the resizing element. (Defaults to 0)
26089 * The maximum size of the resizing element. (Defaults to 2000)
26092 this.maxSize = 2000;
26095 * Whether to animate the transition to the new size
26098 this.animate = false;
26101 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26104 this.useShim = false;
26109 if(!existingProxy){
26111 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26113 this.proxy = Roo.get(existingProxy).dom;
26116 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26119 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26122 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26125 this.dragSpecs = {};
26128 * @private The adapter to use to positon and resize elements
26130 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26131 this.adapter.init(this);
26133 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26135 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26136 this.el.addClass("x-splitbar-h");
26139 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26140 this.el.addClass("x-splitbar-v");
26146 * Fires when the splitter is moved (alias for {@link #event-moved})
26147 * @param {Roo.SplitBar} this
26148 * @param {Number} newSize the new width or height
26153 * Fires when the splitter is moved
26154 * @param {Roo.SplitBar} this
26155 * @param {Number} newSize the new width or height
26159 * @event beforeresize
26160 * Fires before the splitter is dragged
26161 * @param {Roo.SplitBar} this
26163 "beforeresize" : true,
26165 "beforeapply" : true
26168 Roo.util.Observable.call(this);
26171 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26172 onStartProxyDrag : function(x, y){
26173 this.fireEvent("beforeresize", this);
26175 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26177 o.enableDisplayMode("block");
26178 // all splitbars share the same overlay
26179 Roo.SplitBar.prototype.overlay = o;
26181 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26182 this.overlay.show();
26183 Roo.get(this.proxy).setDisplayed("block");
26184 var size = this.adapter.getElementSize(this);
26185 this.activeMinSize = this.getMinimumSize();;
26186 this.activeMaxSize = this.getMaximumSize();;
26187 var c1 = size - this.activeMinSize;
26188 var c2 = Math.max(this.activeMaxSize - size, 0);
26189 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26190 this.dd.resetConstraints();
26191 this.dd.setXConstraint(
26192 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26193 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26195 this.dd.setYConstraint(0, 0);
26197 this.dd.resetConstraints();
26198 this.dd.setXConstraint(0, 0);
26199 this.dd.setYConstraint(
26200 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26201 this.placement == Roo.SplitBar.TOP ? c2 : c1
26204 this.dragSpecs.startSize = size;
26205 this.dragSpecs.startPoint = [x, y];
26206 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26210 * @private Called after the drag operation by the DDProxy
26212 onEndProxyDrag : function(e){
26213 Roo.get(this.proxy).setDisplayed(false);
26214 var endPoint = Roo.lib.Event.getXY(e);
26216 this.overlay.hide();
26219 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26220 newSize = this.dragSpecs.startSize +
26221 (this.placement == Roo.SplitBar.LEFT ?
26222 endPoint[0] - this.dragSpecs.startPoint[0] :
26223 this.dragSpecs.startPoint[0] - endPoint[0]
26226 newSize = this.dragSpecs.startSize +
26227 (this.placement == Roo.SplitBar.TOP ?
26228 endPoint[1] - this.dragSpecs.startPoint[1] :
26229 this.dragSpecs.startPoint[1] - endPoint[1]
26232 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26233 if(newSize != this.dragSpecs.startSize){
26234 if(this.fireEvent('beforeapply', this, newSize) !== false){
26235 this.adapter.setElementSize(this, newSize);
26236 this.fireEvent("moved", this, newSize);
26237 this.fireEvent("resize", this, newSize);
26243 * Get the adapter this SplitBar uses
26244 * @return The adapter object
26246 getAdapter : function(){
26247 return this.adapter;
26251 * Set the adapter this SplitBar uses
26252 * @param {Object} adapter A SplitBar adapter object
26254 setAdapter : function(adapter){
26255 this.adapter = adapter;
26256 this.adapter.init(this);
26260 * Gets the minimum size for the resizing element
26261 * @return {Number} The minimum size
26263 getMinimumSize : function(){
26264 return this.minSize;
26268 * Sets the minimum size for the resizing element
26269 * @param {Number} minSize The minimum size
26271 setMinimumSize : function(minSize){
26272 this.minSize = minSize;
26276 * Gets the maximum size for the resizing element
26277 * @return {Number} The maximum size
26279 getMaximumSize : function(){
26280 return this.maxSize;
26284 * Sets the maximum size for the resizing element
26285 * @param {Number} maxSize The maximum size
26287 setMaximumSize : function(maxSize){
26288 this.maxSize = maxSize;
26292 * Sets the initialize size for the resizing element
26293 * @param {Number} size The initial size
26295 setCurrentSize : function(size){
26296 var oldAnimate = this.animate;
26297 this.animate = false;
26298 this.adapter.setElementSize(this, size);
26299 this.animate = oldAnimate;
26303 * Destroy this splitbar.
26304 * @param {Boolean} removeEl True to remove the element
26306 destroy : function(removeEl){
26308 this.shim.remove();
26311 this.proxy.parentNode.removeChild(this.proxy);
26319 * @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.
26321 Roo.SplitBar.createProxy = function(dir){
26322 var proxy = new Roo.Element(document.createElement("div"));
26323 proxy.unselectable();
26324 var cls = 'x-splitbar-proxy';
26325 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26326 document.body.appendChild(proxy.dom);
26331 * @class Roo.SplitBar.BasicLayoutAdapter
26332 * Default Adapter. It assumes the splitter and resizing element are not positioned
26333 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26335 Roo.SplitBar.BasicLayoutAdapter = function(){
26338 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26339 // do nothing for now
26340 init : function(s){
26344 * Called before drag operations to get the current size of the resizing element.
26345 * @param {Roo.SplitBar} s The SplitBar using this adapter
26347 getElementSize : function(s){
26348 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26349 return s.resizingEl.getWidth();
26351 return s.resizingEl.getHeight();
26356 * Called after drag operations to set the size of the resizing element.
26357 * @param {Roo.SplitBar} s The SplitBar using this adapter
26358 * @param {Number} newSize The new size to set
26359 * @param {Function} onComplete A function to be invoked when resizing is complete
26361 setElementSize : function(s, newSize, onComplete){
26362 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26364 s.resizingEl.setWidth(newSize);
26366 onComplete(s, newSize);
26369 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26374 s.resizingEl.setHeight(newSize);
26376 onComplete(s, newSize);
26379 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26386 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26387 * @extends Roo.SplitBar.BasicLayoutAdapter
26388 * Adapter that moves the splitter element to align with the resized sizing element.
26389 * Used with an absolute positioned SplitBar.
26390 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26391 * document.body, make sure you assign an id to the body element.
26393 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26394 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26395 this.container = Roo.get(container);
26398 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26399 init : function(s){
26400 this.basic.init(s);
26403 getElementSize : function(s){
26404 return this.basic.getElementSize(s);
26407 setElementSize : function(s, newSize, onComplete){
26408 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26411 moveSplitter : function(s){
26412 var yes = Roo.SplitBar;
26413 switch(s.placement){
26415 s.el.setX(s.resizingEl.getRight());
26418 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26421 s.el.setY(s.resizingEl.getBottom());
26424 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26431 * Orientation constant - Create a vertical SplitBar
26435 Roo.SplitBar.VERTICAL = 1;
26438 * Orientation constant - Create a horizontal SplitBar
26442 Roo.SplitBar.HORIZONTAL = 2;
26445 * Placement constant - The resizing element is to the left of the splitter element
26449 Roo.SplitBar.LEFT = 1;
26452 * Placement constant - The resizing element is to the right of the splitter element
26456 Roo.SplitBar.RIGHT = 2;
26459 * Placement constant - The resizing element is positioned above the splitter element
26463 Roo.SplitBar.TOP = 3;
26466 * Placement constant - The resizing element is positioned under splitter element
26470 Roo.SplitBar.BOTTOM = 4;
26473 * Ext JS Library 1.1.1
26474 * Copyright(c) 2006-2007, Ext JS, LLC.
26476 * Originally Released Under LGPL - original licence link has changed is not relivant.
26479 * <script type="text/javascript">
26484 * @extends Roo.util.Observable
26485 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26486 * This class also supports single and multi selection modes. <br>
26487 * Create a data model bound view:
26489 var store = new Roo.data.Store(...);
26491 var view = new Roo.View({
26493 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26495 singleSelect: true,
26496 selectedClass: "ydataview-selected",
26500 // listen for node click?
26501 view.on("click", function(vw, index, node, e){
26502 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26506 dataModel.load("foobar.xml");
26508 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26510 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26511 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26513 * Note: old style constructor is still suported (container, template, config)
26516 * Create a new View
26517 * @param {Object} config The config object
26520 Roo.View = function(config, depreciated_tpl, depreciated_config){
26522 this.parent = false;
26524 if (typeof(depreciated_tpl) == 'undefined') {
26525 // new way.. - universal constructor.
26526 Roo.apply(this, config);
26527 this.el = Roo.get(this.el);
26530 this.el = Roo.get(config);
26531 this.tpl = depreciated_tpl;
26532 Roo.apply(this, depreciated_config);
26534 this.wrapEl = this.el.wrap().wrap();
26535 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26538 if(typeof(this.tpl) == "string"){
26539 this.tpl = new Roo.Template(this.tpl);
26541 // support xtype ctors..
26542 this.tpl = new Roo.factory(this.tpl, Roo);
26546 this.tpl.compile();
26551 * @event beforeclick
26552 * Fires before a click is processed. Returns false to cancel the default action.
26553 * @param {Roo.View} this
26554 * @param {Number} index The index of the target node
26555 * @param {HTMLElement} node The target node
26556 * @param {Roo.EventObject} e The raw event object
26558 "beforeclick" : true,
26561 * Fires when a template node is clicked.
26562 * @param {Roo.View} this
26563 * @param {Number} index The index of the target node
26564 * @param {HTMLElement} node The target node
26565 * @param {Roo.EventObject} e The raw event object
26570 * Fires when a template node is double clicked.
26571 * @param {Roo.View} this
26572 * @param {Number} index The index of the target node
26573 * @param {HTMLElement} node The target node
26574 * @param {Roo.EventObject} e The raw event object
26578 * @event contextmenu
26579 * Fires when a template node is right clicked.
26580 * @param {Roo.View} this
26581 * @param {Number} index The index of the target node
26582 * @param {HTMLElement} node The target node
26583 * @param {Roo.EventObject} e The raw event object
26585 "contextmenu" : true,
26587 * @event selectionchange
26588 * Fires when the selected nodes change.
26589 * @param {Roo.View} this
26590 * @param {Array} selections Array of the selected nodes
26592 "selectionchange" : true,
26595 * @event beforeselect
26596 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26597 * @param {Roo.View} this
26598 * @param {HTMLElement} node The node to be selected
26599 * @param {Array} selections Array of currently selected nodes
26601 "beforeselect" : true,
26603 * @event preparedata
26604 * Fires on every row to render, to allow you to change the data.
26605 * @param {Roo.View} this
26606 * @param {Object} data to be rendered (change this)
26608 "preparedata" : true
26616 "click": this.onClick,
26617 "dblclick": this.onDblClick,
26618 "contextmenu": this.onContextMenu,
26622 this.selections = [];
26624 this.cmp = new Roo.CompositeElementLite([]);
26626 this.store = Roo.factory(this.store, Roo.data);
26627 this.setStore(this.store, true);
26630 if ( this.footer && this.footer.xtype) {
26632 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26634 this.footer.dataSource = this.store;
26635 this.footer.container = fctr;
26636 this.footer = Roo.factory(this.footer, Roo);
26637 fctr.insertFirst(this.el);
26639 // this is a bit insane - as the paging toolbar seems to detach the el..
26640 // dom.parentNode.parentNode.parentNode
26641 // they get detached?
26645 Roo.View.superclass.constructor.call(this);
26650 Roo.extend(Roo.View, Roo.util.Observable, {
26653 * @cfg {Roo.data.Store} store Data store to load data from.
26658 * @cfg {String|Roo.Element} el The container element.
26663 * @cfg {String|Roo.Template} tpl The template used by this View
26667 * @cfg {String} dataName the named area of the template to use as the data area
26668 * Works with domtemplates roo-name="name"
26672 * @cfg {String} selectedClass The css class to add to selected nodes
26674 selectedClass : "x-view-selected",
26676 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26681 * @cfg {String} text to display on mask (default Loading)
26685 * @cfg {Boolean} multiSelect Allow multiple selection
26687 multiSelect : false,
26689 * @cfg {Boolean} singleSelect Allow single selection
26691 singleSelect: false,
26694 * @cfg {Boolean} toggleSelect - selecting
26696 toggleSelect : false,
26699 * @cfg {Boolean} tickable - selecting
26704 * Returns the element this view is bound to.
26705 * @return {Roo.Element}
26707 getEl : function(){
26708 return this.wrapEl;
26714 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26716 refresh : function(){
26717 //Roo.log('refresh');
26720 // if we are using something like 'domtemplate', then
26721 // the what gets used is:
26722 // t.applySubtemplate(NAME, data, wrapping data..)
26723 // the outer template then get' applied with
26724 // the store 'extra data'
26725 // and the body get's added to the
26726 // roo-name="data" node?
26727 // <span class='roo-tpl-{name}'></span> ?????
26731 this.clearSelections();
26732 this.el.update("");
26734 var records = this.store.getRange();
26735 if(records.length < 1) {
26737 // is this valid?? = should it render a template??
26739 this.el.update(this.emptyText);
26743 if (this.dataName) {
26744 this.el.update(t.apply(this.store.meta)); //????
26745 el = this.el.child('.roo-tpl-' + this.dataName);
26748 for(var i = 0, len = records.length; i < len; i++){
26749 var data = this.prepareData(records[i].data, i, records[i]);
26750 this.fireEvent("preparedata", this, data, i, records[i]);
26752 var d = Roo.apply({}, data);
26755 Roo.apply(d, {'roo-id' : Roo.id()});
26759 Roo.each(this.parent.item, function(item){
26760 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26763 Roo.apply(d, {'roo-data-checked' : 'checked'});
26767 html[html.length] = Roo.util.Format.trim(
26769 t.applySubtemplate(this.dataName, d, this.store.meta) :
26776 el.update(html.join(""));
26777 this.nodes = el.dom.childNodes;
26778 this.updateIndexes(0);
26783 * Function to override to reformat the data that is sent to
26784 * the template for each node.
26785 * DEPRICATED - use the preparedata event handler.
26786 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26787 * a JSON object for an UpdateManager bound view).
26789 prepareData : function(data, index, record)
26791 this.fireEvent("preparedata", this, data, index, record);
26795 onUpdate : function(ds, record){
26796 // Roo.log('on update');
26797 this.clearSelections();
26798 var index = this.store.indexOf(record);
26799 var n = this.nodes[index];
26800 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26801 n.parentNode.removeChild(n);
26802 this.updateIndexes(index, index);
26808 onAdd : function(ds, records, index)
26810 //Roo.log(['on Add', ds, records, index] );
26811 this.clearSelections();
26812 if(this.nodes.length == 0){
26816 var n = this.nodes[index];
26817 for(var i = 0, len = records.length; i < len; i++){
26818 var d = this.prepareData(records[i].data, i, records[i]);
26820 this.tpl.insertBefore(n, d);
26823 this.tpl.append(this.el, d);
26826 this.updateIndexes(index);
26829 onRemove : function(ds, record, index){
26830 // Roo.log('onRemove');
26831 this.clearSelections();
26832 var el = this.dataName ?
26833 this.el.child('.roo-tpl-' + this.dataName) :
26836 el.dom.removeChild(this.nodes[index]);
26837 this.updateIndexes(index);
26841 * Refresh an individual node.
26842 * @param {Number} index
26844 refreshNode : function(index){
26845 this.onUpdate(this.store, this.store.getAt(index));
26848 updateIndexes : function(startIndex, endIndex){
26849 var ns = this.nodes;
26850 startIndex = startIndex || 0;
26851 endIndex = endIndex || ns.length - 1;
26852 for(var i = startIndex; i <= endIndex; i++){
26853 ns[i].nodeIndex = i;
26858 * Changes the data store this view uses and refresh the view.
26859 * @param {Store} store
26861 setStore : function(store, initial){
26862 if(!initial && this.store){
26863 this.store.un("datachanged", this.refresh);
26864 this.store.un("add", this.onAdd);
26865 this.store.un("remove", this.onRemove);
26866 this.store.un("update", this.onUpdate);
26867 this.store.un("clear", this.refresh);
26868 this.store.un("beforeload", this.onBeforeLoad);
26869 this.store.un("load", this.onLoad);
26870 this.store.un("loadexception", this.onLoad);
26874 store.on("datachanged", this.refresh, this);
26875 store.on("add", this.onAdd, this);
26876 store.on("remove", this.onRemove, this);
26877 store.on("update", this.onUpdate, this);
26878 store.on("clear", this.refresh, this);
26879 store.on("beforeload", this.onBeforeLoad, this);
26880 store.on("load", this.onLoad, this);
26881 store.on("loadexception", this.onLoad, this);
26889 * onbeforeLoad - masks the loading area.
26892 onBeforeLoad : function(store,opts)
26894 //Roo.log('onBeforeLoad');
26896 this.el.update("");
26898 this.el.mask(this.mask ? this.mask : "Loading" );
26900 onLoad : function ()
26907 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26908 * @param {HTMLElement} node
26909 * @return {HTMLElement} The template node
26911 findItemFromChild : function(node){
26912 var el = this.dataName ?
26913 this.el.child('.roo-tpl-' + this.dataName,true) :
26916 if(!node || node.parentNode == el){
26919 var p = node.parentNode;
26920 while(p && p != el){
26921 if(p.parentNode == el){
26930 onClick : function(e){
26931 var item = this.findItemFromChild(e.getTarget());
26933 var index = this.indexOf(item);
26934 if(this.onItemClick(item, index, e) !== false){
26935 this.fireEvent("click", this, index, item, e);
26938 this.clearSelections();
26943 onContextMenu : function(e){
26944 var item = this.findItemFromChild(e.getTarget());
26946 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26951 onDblClick : function(e){
26952 var item = this.findItemFromChild(e.getTarget());
26954 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26958 onItemClick : function(item, index, e)
26960 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26963 if (this.toggleSelect) {
26964 var m = this.isSelected(item) ? 'unselect' : 'select';
26967 _t[m](item, true, false);
26970 if(this.multiSelect || this.singleSelect){
26971 if(this.multiSelect && e.shiftKey && this.lastSelection){
26972 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26974 this.select(item, this.multiSelect && e.ctrlKey);
26975 this.lastSelection = item;
26978 if(!this.tickable){
26979 e.preventDefault();
26987 * Get the number of selected nodes.
26990 getSelectionCount : function(){
26991 return this.selections.length;
26995 * Get the currently selected nodes.
26996 * @return {Array} An array of HTMLElements
26998 getSelectedNodes : function(){
26999 return this.selections;
27003 * Get the indexes of the selected nodes.
27006 getSelectedIndexes : function(){
27007 var indexes = [], s = this.selections;
27008 for(var i = 0, len = s.length; i < len; i++){
27009 indexes.push(s[i].nodeIndex);
27015 * Clear all selections
27016 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27018 clearSelections : function(suppressEvent){
27019 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27020 this.cmp.elements = this.selections;
27021 this.cmp.removeClass(this.selectedClass);
27022 this.selections = [];
27023 if(!suppressEvent){
27024 this.fireEvent("selectionchange", this, this.selections);
27030 * Returns true if the passed node is selected
27031 * @param {HTMLElement/Number} node The node or node index
27032 * @return {Boolean}
27034 isSelected : function(node){
27035 var s = this.selections;
27039 node = this.getNode(node);
27040 return s.indexOf(node) !== -1;
27045 * @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
27046 * @param {Boolean} keepExisting (optional) true to keep existing selections
27047 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27049 select : function(nodeInfo, keepExisting, suppressEvent){
27050 if(nodeInfo instanceof Array){
27052 this.clearSelections(true);
27054 for(var i = 0, len = nodeInfo.length; i < len; i++){
27055 this.select(nodeInfo[i], true, true);
27059 var node = this.getNode(nodeInfo);
27060 if(!node || this.isSelected(node)){
27061 return; // already selected.
27064 this.clearSelections(true);
27067 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27068 Roo.fly(node).addClass(this.selectedClass);
27069 this.selections.push(node);
27070 if(!suppressEvent){
27071 this.fireEvent("selectionchange", this, this.selections);
27079 * @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
27080 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27081 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27083 unselect : function(nodeInfo, keepExisting, suppressEvent)
27085 if(nodeInfo instanceof Array){
27086 Roo.each(this.selections, function(s) {
27087 this.unselect(s, nodeInfo);
27091 var node = this.getNode(nodeInfo);
27092 if(!node || !this.isSelected(node)){
27093 //Roo.log("not selected");
27094 return; // not selected.
27098 Roo.each(this.selections, function(s) {
27100 Roo.fly(node).removeClass(this.selectedClass);
27107 this.selections= ns;
27108 this.fireEvent("selectionchange", this, this.selections);
27112 * Gets a template node.
27113 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27114 * @return {HTMLElement} The node or null if it wasn't found
27116 getNode : function(nodeInfo){
27117 if(typeof nodeInfo == "string"){
27118 return document.getElementById(nodeInfo);
27119 }else if(typeof nodeInfo == "number"){
27120 return this.nodes[nodeInfo];
27126 * Gets a range template nodes.
27127 * @param {Number} startIndex
27128 * @param {Number} endIndex
27129 * @return {Array} An array of nodes
27131 getNodes : function(start, end){
27132 var ns = this.nodes;
27133 start = start || 0;
27134 end = typeof end == "undefined" ? ns.length - 1 : end;
27137 for(var i = start; i <= end; i++){
27141 for(var i = start; i >= end; i--){
27149 * Finds the index of the passed node
27150 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27151 * @return {Number} The index of the node or -1
27153 indexOf : function(node){
27154 node = this.getNode(node);
27155 if(typeof node.nodeIndex == "number"){
27156 return node.nodeIndex;
27158 var ns = this.nodes;
27159 for(var i = 0, len = ns.length; i < len; i++){
27169 * Ext JS Library 1.1.1
27170 * Copyright(c) 2006-2007, Ext JS, LLC.
27172 * Originally Released Under LGPL - original licence link has changed is not relivant.
27175 * <script type="text/javascript">
27179 * @class Roo.JsonView
27180 * @extends Roo.View
27181 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27183 var view = new Roo.JsonView({
27184 container: "my-element",
27185 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27190 // listen for node click?
27191 view.on("click", function(vw, index, node, e){
27192 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27195 // direct load of JSON data
27196 view.load("foobar.php");
27198 // Example from my blog list
27199 var tpl = new Roo.Template(
27200 '<div class="entry">' +
27201 '<a class="entry-title" href="{link}">{title}</a>' +
27202 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27203 "</div><hr />"
27206 var moreView = new Roo.JsonView({
27207 container : "entry-list",
27211 moreView.on("beforerender", this.sortEntries, this);
27213 url: "/blog/get-posts.php",
27214 params: "allposts=true",
27215 text: "Loading Blog Entries..."
27219 * Note: old code is supported with arguments : (container, template, config)
27223 * Create a new JsonView
27225 * @param {Object} config The config object
27228 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27231 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27233 var um = this.el.getUpdateManager();
27234 um.setRenderer(this);
27235 um.on("update", this.onLoad, this);
27236 um.on("failure", this.onLoadException, this);
27239 * @event beforerender
27240 * Fires before rendering of the downloaded JSON data.
27241 * @param {Roo.JsonView} this
27242 * @param {Object} data The JSON data loaded
27246 * Fires when data is loaded.
27247 * @param {Roo.JsonView} this
27248 * @param {Object} data The JSON data loaded
27249 * @param {Object} response The raw Connect response object
27252 * @event loadexception
27253 * Fires when loading fails.
27254 * @param {Roo.JsonView} this
27255 * @param {Object} response The raw Connect response object
27258 'beforerender' : true,
27260 'loadexception' : true
27263 Roo.extend(Roo.JsonView, Roo.View, {
27265 * @type {String} The root property in the loaded JSON object that contains the data
27270 * Refreshes the view.
27272 refresh : function(){
27273 this.clearSelections();
27274 this.el.update("");
27276 var o = this.jsonData;
27277 if(o && o.length > 0){
27278 for(var i = 0, len = o.length; i < len; i++){
27279 var data = this.prepareData(o[i], i, o);
27280 html[html.length] = this.tpl.apply(data);
27283 html.push(this.emptyText);
27285 this.el.update(html.join(""));
27286 this.nodes = this.el.dom.childNodes;
27287 this.updateIndexes(0);
27291 * 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.
27292 * @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:
27295 url: "your-url.php",
27296 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27297 callback: yourFunction,
27298 scope: yourObject, //(optional scope)
27301 text: "Loading...",
27306 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27307 * 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.
27308 * @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}
27309 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27310 * @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.
27313 var um = this.el.getUpdateManager();
27314 um.update.apply(um, arguments);
27317 // note - render is a standard framework call...
27318 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27319 render : function(el, response){
27321 this.clearSelections();
27322 this.el.update("");
27325 if (response != '') {
27326 o = Roo.util.JSON.decode(response.responseText);
27329 o = o[this.jsonRoot];
27335 * The current JSON data or null
27338 this.beforeRender();
27343 * Get the number of records in the current JSON dataset
27346 getCount : function(){
27347 return this.jsonData ? this.jsonData.length : 0;
27351 * Returns the JSON object for the specified node(s)
27352 * @param {HTMLElement/Array} node The node or an array of nodes
27353 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27354 * you get the JSON object for the node
27356 getNodeData : function(node){
27357 if(node instanceof Array){
27359 for(var i = 0, len = node.length; i < len; i++){
27360 data.push(this.getNodeData(node[i]));
27364 return this.jsonData[this.indexOf(node)] || null;
27367 beforeRender : function(){
27368 this.snapshot = this.jsonData;
27370 this.sort.apply(this, this.sortInfo);
27372 this.fireEvent("beforerender", this, this.jsonData);
27375 onLoad : function(el, o){
27376 this.fireEvent("load", this, this.jsonData, o);
27379 onLoadException : function(el, o){
27380 this.fireEvent("loadexception", this, o);
27384 * Filter the data by a specific property.
27385 * @param {String} property A property on your JSON objects
27386 * @param {String/RegExp} value Either string that the property values
27387 * should start with, or a RegExp to test against the property
27389 filter : function(property, value){
27392 var ss = this.snapshot;
27393 if(typeof value == "string"){
27394 var vlen = value.length;
27396 this.clearFilter();
27399 value = value.toLowerCase();
27400 for(var i = 0, len = ss.length; i < len; i++){
27402 if(o[property].substr(0, vlen).toLowerCase() == value){
27406 } else if(value.exec){ // regex?
27407 for(var i = 0, len = ss.length; i < len; i++){
27409 if(value.test(o[property])){
27416 this.jsonData = data;
27422 * Filter by a function. The passed function will be called with each
27423 * object in the current dataset. If the function returns true the value is kept,
27424 * otherwise it is filtered.
27425 * @param {Function} fn
27426 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27428 filterBy : function(fn, scope){
27431 var ss = this.snapshot;
27432 for(var i = 0, len = ss.length; i < len; i++){
27434 if(fn.call(scope || this, o)){
27438 this.jsonData = data;
27444 * Clears the current filter.
27446 clearFilter : function(){
27447 if(this.snapshot && this.jsonData != this.snapshot){
27448 this.jsonData = this.snapshot;
27455 * Sorts the data for this view and refreshes it.
27456 * @param {String} property A property on your JSON objects to sort on
27457 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27458 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27460 sort : function(property, dir, sortType){
27461 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27464 var dsc = dir && dir.toLowerCase() == "desc";
27465 var f = function(o1, o2){
27466 var v1 = sortType ? sortType(o1[p]) : o1[p];
27467 var v2 = sortType ? sortType(o2[p]) : o2[p];
27470 return dsc ? +1 : -1;
27471 } else if(v1 > v2){
27472 return dsc ? -1 : +1;
27477 this.jsonData.sort(f);
27479 if(this.jsonData != this.snapshot){
27480 this.snapshot.sort(f);
27486 * Ext JS Library 1.1.1
27487 * Copyright(c) 2006-2007, Ext JS, LLC.
27489 * Originally Released Under LGPL - original licence link has changed is not relivant.
27492 * <script type="text/javascript">
27497 * @class Roo.ColorPalette
27498 * @extends Roo.Component
27499 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27500 * Here's an example of typical usage:
27502 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27503 cp.render('my-div');
27505 cp.on('select', function(palette, selColor){
27506 // do something with selColor
27510 * Create a new ColorPalette
27511 * @param {Object} config The config object
27513 Roo.ColorPalette = function(config){
27514 Roo.ColorPalette.superclass.constructor.call(this, config);
27518 * Fires when a color is selected
27519 * @param {ColorPalette} this
27520 * @param {String} color The 6-digit color hex code (without the # symbol)
27526 this.on("select", this.handler, this.scope, true);
27529 Roo.extend(Roo.ColorPalette, Roo.Component, {
27531 * @cfg {String} itemCls
27532 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27534 itemCls : "x-color-palette",
27536 * @cfg {String} value
27537 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27538 * the hex codes are case-sensitive.
27541 clickEvent:'click',
27543 ctype: "Roo.ColorPalette",
27546 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27548 allowReselect : false,
27551 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27552 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27553 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27554 * of colors with the width setting until the box is symmetrical.</p>
27555 * <p>You can override individual colors if needed:</p>
27557 var cp = new Roo.ColorPalette();
27558 cp.colors[0] = "FF0000"; // change the first box to red
27561 Or you can provide a custom array of your own for complete control:
27563 var cp = new Roo.ColorPalette();
27564 cp.colors = ["000000", "993300", "333300"];
27569 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27570 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27571 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27572 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27573 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27577 onRender : function(container, position){
27578 var t = new Roo.MasterTemplate(
27579 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27581 var c = this.colors;
27582 for(var i = 0, len = c.length; i < len; i++){
27585 var el = document.createElement("div");
27586 el.className = this.itemCls;
27588 container.dom.insertBefore(el, position);
27589 this.el = Roo.get(el);
27590 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27591 if(this.clickEvent != 'click'){
27592 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27597 afterRender : function(){
27598 Roo.ColorPalette.superclass.afterRender.call(this);
27600 var s = this.value;
27607 handleClick : function(e, t){
27608 e.preventDefault();
27609 if(!this.disabled){
27610 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27611 this.select(c.toUpperCase());
27616 * Selects the specified color in the palette (fires the select event)
27617 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27619 select : function(color){
27620 color = color.replace("#", "");
27621 if(color != this.value || this.allowReselect){
27624 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27626 el.child("a.color-"+color).addClass("x-color-palette-sel");
27627 this.value = color;
27628 this.fireEvent("select", this, color);
27633 * Ext JS Library 1.1.1
27634 * Copyright(c) 2006-2007, Ext JS, LLC.
27636 * Originally Released Under LGPL - original licence link has changed is not relivant.
27639 * <script type="text/javascript">
27643 * @class Roo.DatePicker
27644 * @extends Roo.Component
27645 * Simple date picker class.
27647 * Create a new DatePicker
27648 * @param {Object} config The config object
27650 Roo.DatePicker = function(config){
27651 Roo.DatePicker.superclass.constructor.call(this, config);
27653 this.value = config && config.value ?
27654 config.value.clearTime() : new Date().clearTime();
27659 * Fires when a date is selected
27660 * @param {DatePicker} this
27661 * @param {Date} date The selected date
27665 * @event monthchange
27666 * Fires when the displayed month changes
27667 * @param {DatePicker} this
27668 * @param {Date} date The selected month
27670 'monthchange': true
27674 this.on("select", this.handler, this.scope || this);
27676 // build the disabledDatesRE
27677 if(!this.disabledDatesRE && this.disabledDates){
27678 var dd = this.disabledDates;
27680 for(var i = 0; i < dd.length; i++){
27682 if(i != dd.length-1) {
27686 this.disabledDatesRE = new RegExp(re + ")");
27690 Roo.extend(Roo.DatePicker, Roo.Component, {
27692 * @cfg {String} todayText
27693 * The text to display on the button that selects the current date (defaults to "Today")
27695 todayText : "Today",
27697 * @cfg {String} okText
27698 * The text to display on the ok button
27700 okText : " OK ", //   to give the user extra clicking room
27702 * @cfg {String} cancelText
27703 * The text to display on the cancel button
27705 cancelText : "Cancel",
27707 * @cfg {String} todayTip
27708 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27710 todayTip : "{0} (Spacebar)",
27712 * @cfg {Date} minDate
27713 * Minimum allowable date (JavaScript date object, defaults to null)
27717 * @cfg {Date} maxDate
27718 * Maximum allowable date (JavaScript date object, defaults to null)
27722 * @cfg {String} minText
27723 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27725 minText : "This date is before the minimum date",
27727 * @cfg {String} maxText
27728 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27730 maxText : "This date is after the maximum date",
27732 * @cfg {String} format
27733 * The default date format string which can be overriden for localization support. The format must be
27734 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27738 * @cfg {Array} disabledDays
27739 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27741 disabledDays : null,
27743 * @cfg {String} disabledDaysText
27744 * The tooltip to display when the date falls on a disabled day (defaults to "")
27746 disabledDaysText : "",
27748 * @cfg {RegExp} disabledDatesRE
27749 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27751 disabledDatesRE : null,
27753 * @cfg {String} disabledDatesText
27754 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27756 disabledDatesText : "",
27758 * @cfg {Boolean} constrainToViewport
27759 * True to constrain the date picker to the viewport (defaults to true)
27761 constrainToViewport : true,
27763 * @cfg {Array} monthNames
27764 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27766 monthNames : Date.monthNames,
27768 * @cfg {Array} dayNames
27769 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27771 dayNames : Date.dayNames,
27773 * @cfg {String} nextText
27774 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27776 nextText: 'Next Month (Control+Right)',
27778 * @cfg {String} prevText
27779 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27781 prevText: 'Previous Month (Control+Left)',
27783 * @cfg {String} monthYearText
27784 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27786 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27788 * @cfg {Number} startDay
27789 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27793 * @cfg {Bool} showClear
27794 * Show a clear button (usefull for date form elements that can be blank.)
27800 * Sets the value of the date field
27801 * @param {Date} value The date to set
27803 setValue : function(value){
27804 var old = this.value;
27806 if (typeof(value) == 'string') {
27808 value = Date.parseDate(value, this.format);
27811 value = new Date();
27814 this.value = value.clearTime(true);
27816 this.update(this.value);
27821 * Gets the current selected value of the date field
27822 * @return {Date} The selected date
27824 getValue : function(){
27829 focus : function(){
27831 this.update(this.activeDate);
27836 onRender : function(container, position){
27839 '<table cellspacing="0">',
27840 '<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>',
27841 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27842 var dn = this.dayNames;
27843 for(var i = 0; i < 7; i++){
27844 var d = this.startDay+i;
27848 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27850 m[m.length] = "</tr></thead><tbody><tr>";
27851 for(var i = 0; i < 42; i++) {
27852 if(i % 7 == 0 && i != 0){
27853 m[m.length] = "</tr><tr>";
27855 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27857 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27858 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27860 var el = document.createElement("div");
27861 el.className = "x-date-picker";
27862 el.innerHTML = m.join("");
27864 container.dom.insertBefore(el, position);
27866 this.el = Roo.get(el);
27867 this.eventEl = Roo.get(el.firstChild);
27869 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27870 handler: this.showPrevMonth,
27872 preventDefault:true,
27876 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27877 handler: this.showNextMonth,
27879 preventDefault:true,
27883 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27885 this.monthPicker = this.el.down('div.x-date-mp');
27886 this.monthPicker.enableDisplayMode('block');
27888 var kn = new Roo.KeyNav(this.eventEl, {
27889 "left" : function(e){
27891 this.showPrevMonth() :
27892 this.update(this.activeDate.add("d", -1));
27895 "right" : function(e){
27897 this.showNextMonth() :
27898 this.update(this.activeDate.add("d", 1));
27901 "up" : function(e){
27903 this.showNextYear() :
27904 this.update(this.activeDate.add("d", -7));
27907 "down" : function(e){
27909 this.showPrevYear() :
27910 this.update(this.activeDate.add("d", 7));
27913 "pageUp" : function(e){
27914 this.showNextMonth();
27917 "pageDown" : function(e){
27918 this.showPrevMonth();
27921 "enter" : function(e){
27922 e.stopPropagation();
27929 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27931 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27933 this.el.unselectable();
27935 this.cells = this.el.select("table.x-date-inner tbody td");
27936 this.textNodes = this.el.query("table.x-date-inner tbody span");
27938 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27940 tooltip: this.monthYearText
27943 this.mbtn.on('click', this.showMonthPicker, this);
27944 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27947 var today = (new Date()).dateFormat(this.format);
27949 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27950 if (this.showClear) {
27951 baseTb.add( new Roo.Toolbar.Fill());
27954 text: String.format(this.todayText, today),
27955 tooltip: String.format(this.todayTip, today),
27956 handler: this.selectToday,
27960 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27963 if (this.showClear) {
27965 baseTb.add( new Roo.Toolbar.Fill());
27968 cls: 'x-btn-icon x-btn-clear',
27969 handler: function() {
27971 this.fireEvent("select", this, '');
27981 this.update(this.value);
27984 createMonthPicker : function(){
27985 if(!this.monthPicker.dom.firstChild){
27986 var buf = ['<table border="0" cellspacing="0">'];
27987 for(var i = 0; i < 6; i++){
27989 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27990 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27992 '<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>' :
27993 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27997 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27999 '</button><button type="button" class="x-date-mp-cancel">',
28001 '</button></td></tr>',
28004 this.monthPicker.update(buf.join(''));
28005 this.monthPicker.on('click', this.onMonthClick, this);
28006 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28008 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28009 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28011 this.mpMonths.each(function(m, a, i){
28014 m.dom.xmonth = 5 + Math.round(i * .5);
28016 m.dom.xmonth = Math.round((i-1) * .5);
28022 showMonthPicker : function(){
28023 this.createMonthPicker();
28024 var size = this.el.getSize();
28025 this.monthPicker.setSize(size);
28026 this.monthPicker.child('table').setSize(size);
28028 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28029 this.updateMPMonth(this.mpSelMonth);
28030 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28031 this.updateMPYear(this.mpSelYear);
28033 this.monthPicker.slideIn('t', {duration:.2});
28036 updateMPYear : function(y){
28038 var ys = this.mpYears.elements;
28039 for(var i = 1; i <= 10; i++){
28040 var td = ys[i-1], y2;
28042 y2 = y + Math.round(i * .5);
28043 td.firstChild.innerHTML = y2;
28046 y2 = y - (5-Math.round(i * .5));
28047 td.firstChild.innerHTML = y2;
28050 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28054 updateMPMonth : function(sm){
28055 this.mpMonths.each(function(m, a, i){
28056 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28060 selectMPMonth: function(m){
28064 onMonthClick : function(e, t){
28066 var el = new Roo.Element(t), pn;
28067 if(el.is('button.x-date-mp-cancel')){
28068 this.hideMonthPicker();
28070 else if(el.is('button.x-date-mp-ok')){
28071 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28072 this.hideMonthPicker();
28074 else if(pn = el.up('td.x-date-mp-month', 2)){
28075 this.mpMonths.removeClass('x-date-mp-sel');
28076 pn.addClass('x-date-mp-sel');
28077 this.mpSelMonth = pn.dom.xmonth;
28079 else if(pn = el.up('td.x-date-mp-year', 2)){
28080 this.mpYears.removeClass('x-date-mp-sel');
28081 pn.addClass('x-date-mp-sel');
28082 this.mpSelYear = pn.dom.xyear;
28084 else if(el.is('a.x-date-mp-prev')){
28085 this.updateMPYear(this.mpyear-10);
28087 else if(el.is('a.x-date-mp-next')){
28088 this.updateMPYear(this.mpyear+10);
28092 onMonthDblClick : function(e, t){
28094 var el = new Roo.Element(t), pn;
28095 if(pn = el.up('td.x-date-mp-month', 2)){
28096 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28097 this.hideMonthPicker();
28099 else if(pn = el.up('td.x-date-mp-year', 2)){
28100 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28101 this.hideMonthPicker();
28105 hideMonthPicker : function(disableAnim){
28106 if(this.monthPicker){
28107 if(disableAnim === true){
28108 this.monthPicker.hide();
28110 this.monthPicker.slideOut('t', {duration:.2});
28116 showPrevMonth : function(e){
28117 this.update(this.activeDate.add("mo", -1));
28121 showNextMonth : function(e){
28122 this.update(this.activeDate.add("mo", 1));
28126 showPrevYear : function(){
28127 this.update(this.activeDate.add("y", -1));
28131 showNextYear : function(){
28132 this.update(this.activeDate.add("y", 1));
28136 handleMouseWheel : function(e){
28137 var delta = e.getWheelDelta();
28139 this.showPrevMonth();
28141 } else if(delta < 0){
28142 this.showNextMonth();
28148 handleDateClick : function(e, t){
28150 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28151 this.setValue(new Date(t.dateValue));
28152 this.fireEvent("select", this, this.value);
28157 selectToday : function(){
28158 this.setValue(new Date().clearTime());
28159 this.fireEvent("select", this, this.value);
28163 update : function(date)
28165 var vd = this.activeDate;
28166 this.activeDate = date;
28168 var t = date.getTime();
28169 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28170 this.cells.removeClass("x-date-selected");
28171 this.cells.each(function(c){
28172 if(c.dom.firstChild.dateValue == t){
28173 c.addClass("x-date-selected");
28174 setTimeout(function(){
28175 try{c.dom.firstChild.focus();}catch(e){}
28184 var days = date.getDaysInMonth();
28185 var firstOfMonth = date.getFirstDateOfMonth();
28186 var startingPos = firstOfMonth.getDay()-this.startDay;
28188 if(startingPos <= this.startDay){
28192 var pm = date.add("mo", -1);
28193 var prevStart = pm.getDaysInMonth()-startingPos;
28195 var cells = this.cells.elements;
28196 var textEls = this.textNodes;
28197 days += startingPos;
28199 // convert everything to numbers so it's fast
28200 var day = 86400000;
28201 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28202 var today = new Date().clearTime().getTime();
28203 var sel = date.clearTime().getTime();
28204 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28205 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28206 var ddMatch = this.disabledDatesRE;
28207 var ddText = this.disabledDatesText;
28208 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28209 var ddaysText = this.disabledDaysText;
28210 var format = this.format;
28212 var setCellClass = function(cal, cell){
28214 var t = d.getTime();
28215 cell.firstChild.dateValue = t;
28217 cell.className += " x-date-today";
28218 cell.title = cal.todayText;
28221 cell.className += " x-date-selected";
28222 setTimeout(function(){
28223 try{cell.firstChild.focus();}catch(e){}
28228 cell.className = " x-date-disabled";
28229 cell.title = cal.minText;
28233 cell.className = " x-date-disabled";
28234 cell.title = cal.maxText;
28238 if(ddays.indexOf(d.getDay()) != -1){
28239 cell.title = ddaysText;
28240 cell.className = " x-date-disabled";
28243 if(ddMatch && format){
28244 var fvalue = d.dateFormat(format);
28245 if(ddMatch.test(fvalue)){
28246 cell.title = ddText.replace("%0", fvalue);
28247 cell.className = " x-date-disabled";
28253 for(; i < startingPos; i++) {
28254 textEls[i].innerHTML = (++prevStart);
28255 d.setDate(d.getDate()+1);
28256 cells[i].className = "x-date-prevday";
28257 setCellClass(this, cells[i]);
28259 for(; i < days; i++){
28260 intDay = i - startingPos + 1;
28261 textEls[i].innerHTML = (intDay);
28262 d.setDate(d.getDate()+1);
28263 cells[i].className = "x-date-active";
28264 setCellClass(this, cells[i]);
28267 for(; i < 42; i++) {
28268 textEls[i].innerHTML = (++extraDays);
28269 d.setDate(d.getDate()+1);
28270 cells[i].className = "x-date-nextday";
28271 setCellClass(this, cells[i]);
28274 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28275 this.fireEvent('monthchange', this, date);
28277 if(!this.internalRender){
28278 var main = this.el.dom.firstChild;
28279 var w = main.offsetWidth;
28280 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28281 Roo.fly(main).setWidth(w);
28282 this.internalRender = true;
28283 // opera does not respect the auto grow header center column
28284 // then, after it gets a width opera refuses to recalculate
28285 // without a second pass
28286 if(Roo.isOpera && !this.secondPass){
28287 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28288 this.secondPass = true;
28289 this.update.defer(10, this, [date]);
28297 * Ext JS Library 1.1.1
28298 * Copyright(c) 2006-2007, Ext JS, LLC.
28300 * Originally Released Under LGPL - original licence link has changed is not relivant.
28303 * <script type="text/javascript">
28306 * @class Roo.TabPanel
28307 * @extends Roo.util.Observable
28308 * A lightweight tab container.
28312 // basic tabs 1, built from existing content
28313 var tabs = new Roo.TabPanel("tabs1");
28314 tabs.addTab("script", "View Script");
28315 tabs.addTab("markup", "View Markup");
28316 tabs.activate("script");
28318 // more advanced tabs, built from javascript
28319 var jtabs = new Roo.TabPanel("jtabs");
28320 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28322 // set up the UpdateManager
28323 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28324 var updater = tab2.getUpdateManager();
28325 updater.setDefaultUrl("ajax1.htm");
28326 tab2.on('activate', updater.refresh, updater, true);
28328 // Use setUrl for Ajax loading
28329 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28330 tab3.setUrl("ajax2.htm", null, true);
28333 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28336 jtabs.activate("jtabs-1");
28339 * Create a new TabPanel.
28340 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28341 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28343 Roo.TabPanel = function(container, config){
28345 * The container element for this TabPanel.
28346 * @type Roo.Element
28348 this.el = Roo.get(container, true);
28350 if(typeof config == "boolean"){
28351 this.tabPosition = config ? "bottom" : "top";
28353 Roo.apply(this, config);
28356 if(this.tabPosition == "bottom"){
28357 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28358 this.el.addClass("x-tabs-bottom");
28360 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28361 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28362 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28364 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28366 if(this.tabPosition != "bottom"){
28367 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28368 * @type Roo.Element
28370 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28371 this.el.addClass("x-tabs-top");
28375 this.bodyEl.setStyle("position", "relative");
28377 this.active = null;
28378 this.activateDelegate = this.activate.createDelegate(this);
28383 * Fires when the active tab changes
28384 * @param {Roo.TabPanel} this
28385 * @param {Roo.TabPanelItem} activePanel The new active tab
28389 * @event beforetabchange
28390 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28391 * @param {Roo.TabPanel} this
28392 * @param {Object} e Set cancel to true on this object to cancel the tab change
28393 * @param {Roo.TabPanelItem} tab The tab being changed to
28395 "beforetabchange" : true
28398 Roo.EventManager.onWindowResize(this.onResize, this);
28399 this.cpad = this.el.getPadding("lr");
28400 this.hiddenCount = 0;
28403 // toolbar on the tabbar support...
28404 if (this.toolbar) {
28405 var tcfg = this.toolbar;
28406 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28407 this.toolbar = new Roo.Toolbar(tcfg);
28408 if (Roo.isSafari) {
28409 var tbl = tcfg.container.child('table', true);
28410 tbl.setAttribute('width', '100%');
28417 Roo.TabPanel.superclass.constructor.call(this);
28420 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28422 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28424 tabPosition : "top",
28426 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28428 currentTabWidth : 0,
28430 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28434 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28438 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28440 preferredTabWidth : 175,
28442 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28444 resizeTabs : false,
28446 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28448 monitorResize : true,
28450 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28455 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28456 * @param {String} id The id of the div to use <b>or create</b>
28457 * @param {String} text The text for the tab
28458 * @param {String} content (optional) Content to put in the TabPanelItem body
28459 * @param {Boolean} closable (optional) True to create a close icon on the tab
28460 * @return {Roo.TabPanelItem} The created TabPanelItem
28462 addTab : function(id, text, content, closable){
28463 var item = new Roo.TabPanelItem(this, id, text, closable);
28464 this.addTabItem(item);
28466 item.setContent(content);
28472 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28473 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28474 * @return {Roo.TabPanelItem}
28476 getTab : function(id){
28477 return this.items[id];
28481 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28482 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28484 hideTab : function(id){
28485 var t = this.items[id];
28488 this.hiddenCount++;
28489 this.autoSizeTabs();
28494 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28495 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28497 unhideTab : function(id){
28498 var t = this.items[id];
28500 t.setHidden(false);
28501 this.hiddenCount--;
28502 this.autoSizeTabs();
28507 * Adds an existing {@link Roo.TabPanelItem}.
28508 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28510 addTabItem : function(item){
28511 this.items[item.id] = item;
28512 this.items.push(item);
28513 if(this.resizeTabs){
28514 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28515 this.autoSizeTabs();
28522 * Removes a {@link Roo.TabPanelItem}.
28523 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28525 removeTab : function(id){
28526 var items = this.items;
28527 var tab = items[id];
28528 if(!tab) { return; }
28529 var index = items.indexOf(tab);
28530 if(this.active == tab && items.length > 1){
28531 var newTab = this.getNextAvailable(index);
28536 this.stripEl.dom.removeChild(tab.pnode.dom);
28537 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28538 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28540 items.splice(index, 1);
28541 delete this.items[tab.id];
28542 tab.fireEvent("close", tab);
28543 tab.purgeListeners();
28544 this.autoSizeTabs();
28547 getNextAvailable : function(start){
28548 var items = this.items;
28550 // look for a next tab that will slide over to
28551 // replace the one being removed
28552 while(index < items.length){
28553 var item = items[++index];
28554 if(item && !item.isHidden()){
28558 // if one isn't found select the previous tab (on the left)
28561 var item = items[--index];
28562 if(item && !item.isHidden()){
28570 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28571 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28573 disableTab : function(id){
28574 var tab = this.items[id];
28575 if(tab && this.active != tab){
28581 * Enables a {@link Roo.TabPanelItem} that is disabled.
28582 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28584 enableTab : function(id){
28585 var tab = this.items[id];
28590 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28591 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28592 * @return {Roo.TabPanelItem} The TabPanelItem.
28594 activate : function(id){
28595 var tab = this.items[id];
28599 if(tab == this.active || tab.disabled){
28603 this.fireEvent("beforetabchange", this, e, tab);
28604 if(e.cancel !== true && !tab.disabled){
28606 this.active.hide();
28608 this.active = this.items[id];
28609 this.active.show();
28610 this.fireEvent("tabchange", this, this.active);
28616 * Gets the active {@link Roo.TabPanelItem}.
28617 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28619 getActiveTab : function(){
28620 return this.active;
28624 * Updates the tab body element to fit the height of the container element
28625 * for overflow scrolling
28626 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28628 syncHeight : function(targetHeight){
28629 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28630 var bm = this.bodyEl.getMargins();
28631 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28632 this.bodyEl.setHeight(newHeight);
28636 onResize : function(){
28637 if(this.monitorResize){
28638 this.autoSizeTabs();
28643 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28645 beginUpdate : function(){
28646 this.updating = true;
28650 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28652 endUpdate : function(){
28653 this.updating = false;
28654 this.autoSizeTabs();
28658 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28660 autoSizeTabs : function(){
28661 var count = this.items.length;
28662 var vcount = count - this.hiddenCount;
28663 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28666 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28667 var availWidth = Math.floor(w / vcount);
28668 var b = this.stripBody;
28669 if(b.getWidth() > w){
28670 var tabs = this.items;
28671 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28672 if(availWidth < this.minTabWidth){
28673 /*if(!this.sleft){ // incomplete scrolling code
28674 this.createScrollButtons();
28677 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28680 if(this.currentTabWidth < this.preferredTabWidth){
28681 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28687 * Returns the number of tabs in this TabPanel.
28690 getCount : function(){
28691 return this.items.length;
28695 * Resizes all the tabs to the passed width
28696 * @param {Number} The new width
28698 setTabWidth : function(width){
28699 this.currentTabWidth = width;
28700 for(var i = 0, len = this.items.length; i < len; i++) {
28701 if(!this.items[i].isHidden()) {
28702 this.items[i].setWidth(width);
28708 * Destroys this TabPanel
28709 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28711 destroy : function(removeEl){
28712 Roo.EventManager.removeResizeListener(this.onResize, this);
28713 for(var i = 0, len = this.items.length; i < len; i++){
28714 this.items[i].purgeListeners();
28716 if(removeEl === true){
28717 this.el.update("");
28724 * @class Roo.TabPanelItem
28725 * @extends Roo.util.Observable
28726 * Represents an individual item (tab plus body) in a TabPanel.
28727 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28728 * @param {String} id The id of this TabPanelItem
28729 * @param {String} text The text for the tab of this TabPanelItem
28730 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28732 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28734 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28735 * @type Roo.TabPanel
28737 this.tabPanel = tabPanel;
28739 * The id for this TabPanelItem
28744 this.disabled = false;
28748 this.loaded = false;
28749 this.closable = closable;
28752 * The body element for this TabPanelItem.
28753 * @type Roo.Element
28755 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28756 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28757 this.bodyEl.setStyle("display", "block");
28758 this.bodyEl.setStyle("zoom", "1");
28761 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28763 this.el = Roo.get(els.el, true);
28764 this.inner = Roo.get(els.inner, true);
28765 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28766 this.pnode = Roo.get(els.el.parentNode, true);
28767 this.el.on("mousedown", this.onTabMouseDown, this);
28768 this.el.on("click", this.onTabClick, this);
28771 var c = Roo.get(els.close, true);
28772 c.dom.title = this.closeText;
28773 c.addClassOnOver("close-over");
28774 c.on("click", this.closeClick, this);
28780 * Fires when this tab becomes the active tab.
28781 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28782 * @param {Roo.TabPanelItem} this
28786 * @event beforeclose
28787 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28788 * @param {Roo.TabPanelItem} this
28789 * @param {Object} e Set cancel to true on this object to cancel the close.
28791 "beforeclose": true,
28794 * Fires when this tab is closed.
28795 * @param {Roo.TabPanelItem} this
28799 * @event deactivate
28800 * Fires when this tab is no longer the active tab.
28801 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28802 * @param {Roo.TabPanelItem} this
28804 "deactivate" : true
28806 this.hidden = false;
28808 Roo.TabPanelItem.superclass.constructor.call(this);
28811 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28812 purgeListeners : function(){
28813 Roo.util.Observable.prototype.purgeListeners.call(this);
28814 this.el.removeAllListeners();
28817 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28820 this.pnode.addClass("on");
28823 this.tabPanel.stripWrap.repaint();
28825 this.fireEvent("activate", this.tabPanel, this);
28829 * Returns true if this tab is the active tab.
28830 * @return {Boolean}
28832 isActive : function(){
28833 return this.tabPanel.getActiveTab() == this;
28837 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28840 this.pnode.removeClass("on");
28842 this.fireEvent("deactivate", this.tabPanel, this);
28845 hideAction : function(){
28846 this.bodyEl.hide();
28847 this.bodyEl.setStyle("position", "absolute");
28848 this.bodyEl.setLeft("-20000px");
28849 this.bodyEl.setTop("-20000px");
28852 showAction : function(){
28853 this.bodyEl.setStyle("position", "relative");
28854 this.bodyEl.setTop("");
28855 this.bodyEl.setLeft("");
28856 this.bodyEl.show();
28860 * Set the tooltip for the tab.
28861 * @param {String} tooltip The tab's tooltip
28863 setTooltip : function(text){
28864 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28865 this.textEl.dom.qtip = text;
28866 this.textEl.dom.removeAttribute('title');
28868 this.textEl.dom.title = text;
28872 onTabClick : function(e){
28873 e.preventDefault();
28874 this.tabPanel.activate(this.id);
28877 onTabMouseDown : function(e){
28878 e.preventDefault();
28879 this.tabPanel.activate(this.id);
28882 getWidth : function(){
28883 return this.inner.getWidth();
28886 setWidth : function(width){
28887 var iwidth = width - this.pnode.getPadding("lr");
28888 this.inner.setWidth(iwidth);
28889 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28890 this.pnode.setWidth(width);
28894 * Show or hide the tab
28895 * @param {Boolean} hidden True to hide or false to show.
28897 setHidden : function(hidden){
28898 this.hidden = hidden;
28899 this.pnode.setStyle("display", hidden ? "none" : "");
28903 * Returns true if this tab is "hidden"
28904 * @return {Boolean}
28906 isHidden : function(){
28907 return this.hidden;
28911 * Returns the text for this tab
28914 getText : function(){
28918 autoSize : function(){
28919 //this.el.beginMeasure();
28920 this.textEl.setWidth(1);
28922 * #2804 [new] Tabs in Roojs
28923 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28925 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28926 //this.el.endMeasure();
28930 * Sets the text for the tab (Note: this also sets the tooltip text)
28931 * @param {String} text The tab's text and tooltip
28933 setText : function(text){
28935 this.textEl.update(text);
28936 this.setTooltip(text);
28937 if(!this.tabPanel.resizeTabs){
28942 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28944 activate : function(){
28945 this.tabPanel.activate(this.id);
28949 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28951 disable : function(){
28952 if(this.tabPanel.active != this){
28953 this.disabled = true;
28954 this.pnode.addClass("disabled");
28959 * Enables this TabPanelItem if it was previously disabled.
28961 enable : function(){
28962 this.disabled = false;
28963 this.pnode.removeClass("disabled");
28967 * Sets the content for this TabPanelItem.
28968 * @param {String} content The content
28969 * @param {Boolean} loadScripts true to look for and load scripts
28971 setContent : function(content, loadScripts){
28972 this.bodyEl.update(content, loadScripts);
28976 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28977 * @return {Roo.UpdateManager} The UpdateManager
28979 getUpdateManager : function(){
28980 return this.bodyEl.getUpdateManager();
28984 * Set a URL to be used to load the content for this TabPanelItem.
28985 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28986 * @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)
28987 * @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)
28988 * @return {Roo.UpdateManager} The UpdateManager
28990 setUrl : function(url, params, loadOnce){
28991 if(this.refreshDelegate){
28992 this.un('activate', this.refreshDelegate);
28994 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28995 this.on("activate", this.refreshDelegate);
28996 return this.bodyEl.getUpdateManager();
29000 _handleRefresh : function(url, params, loadOnce){
29001 if(!loadOnce || !this.loaded){
29002 var updater = this.bodyEl.getUpdateManager();
29003 updater.update(url, params, this._setLoaded.createDelegate(this));
29008 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29009 * Will fail silently if the setUrl method has not been called.
29010 * This does not activate the panel, just updates its content.
29012 refresh : function(){
29013 if(this.refreshDelegate){
29014 this.loaded = false;
29015 this.refreshDelegate();
29020 _setLoaded : function(){
29021 this.loaded = true;
29025 closeClick : function(e){
29028 this.fireEvent("beforeclose", this, o);
29029 if(o.cancel !== true){
29030 this.tabPanel.removeTab(this.id);
29034 * The text displayed in the tooltip for the close icon.
29037 closeText : "Close this tab"
29041 Roo.TabPanel.prototype.createStrip = function(container){
29042 var strip = document.createElement("div");
29043 strip.className = "x-tabs-wrap";
29044 container.appendChild(strip);
29048 Roo.TabPanel.prototype.createStripList = function(strip){
29049 // div wrapper for retard IE
29050 // returns the "tr" element.
29051 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29052 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29053 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29054 return strip.firstChild.firstChild.firstChild.firstChild;
29057 Roo.TabPanel.prototype.createBody = function(container){
29058 var body = document.createElement("div");
29059 Roo.id(body, "tab-body");
29060 Roo.fly(body).addClass("x-tabs-body");
29061 container.appendChild(body);
29065 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29066 var body = Roo.getDom(id);
29068 body = document.createElement("div");
29071 Roo.fly(body).addClass("x-tabs-item-body");
29072 bodyEl.insertBefore(body, bodyEl.firstChild);
29076 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29077 var td = document.createElement("td");
29078 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29079 //stripEl.appendChild(td);
29081 td.className = "x-tabs-closable";
29082 if(!this.closeTpl){
29083 this.closeTpl = new Roo.Template(
29084 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29085 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29086 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29089 var el = this.closeTpl.overwrite(td, {"text": text});
29090 var close = el.getElementsByTagName("div")[0];
29091 var inner = el.getElementsByTagName("em")[0];
29092 return {"el": el, "close": close, "inner": inner};
29095 this.tabTpl = new Roo.Template(
29096 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29097 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29100 var el = this.tabTpl.overwrite(td, {"text": text});
29101 var inner = el.getElementsByTagName("em")[0];
29102 return {"el": el, "inner": inner};
29106 * Ext JS Library 1.1.1
29107 * Copyright(c) 2006-2007, Ext JS, LLC.
29109 * Originally Released Under LGPL - original licence link has changed is not relivant.
29112 * <script type="text/javascript">
29116 * @class Roo.Button
29117 * @extends Roo.util.Observable
29118 * Simple Button class
29119 * @cfg {String} text The button text
29120 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29121 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29122 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29123 * @cfg {Object} scope The scope of the handler
29124 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29125 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29126 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29127 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29128 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29129 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29130 applies if enableToggle = true)
29131 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29132 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29133 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29135 * Create a new button
29136 * @param {Object} config The config object
29138 Roo.Button = function(renderTo, config)
29142 renderTo = config.renderTo || false;
29145 Roo.apply(this, config);
29149 * Fires when this button is clicked
29150 * @param {Button} this
29151 * @param {EventObject} e The click event
29156 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29157 * @param {Button} this
29158 * @param {Boolean} pressed
29163 * Fires when the mouse hovers over the button
29164 * @param {Button} this
29165 * @param {Event} e The event object
29167 'mouseover' : true,
29170 * Fires when the mouse exits the button
29171 * @param {Button} this
29172 * @param {Event} e The event object
29177 * Fires when the button is rendered
29178 * @param {Button} this
29183 this.menu = Roo.menu.MenuMgr.get(this.menu);
29185 // register listeners first!! - so render can be captured..
29186 Roo.util.Observable.call(this);
29188 this.render(renderTo);
29194 Roo.extend(Roo.Button, Roo.util.Observable, {
29200 * Read-only. True if this button is hidden
29205 * Read-only. True if this button is disabled
29210 * Read-only. True if this button is pressed (only if enableToggle = true)
29216 * @cfg {Number} tabIndex
29217 * The DOM tabIndex for this button (defaults to undefined)
29219 tabIndex : undefined,
29222 * @cfg {Boolean} enableToggle
29223 * True to enable pressed/not pressed toggling (defaults to false)
29225 enableToggle: false,
29227 * @cfg {Mixed} menu
29228 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29232 * @cfg {String} menuAlign
29233 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29235 menuAlign : "tl-bl?",
29238 * @cfg {String} iconCls
29239 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29241 iconCls : undefined,
29243 * @cfg {String} type
29244 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29249 menuClassTarget: 'tr',
29252 * @cfg {String} clickEvent
29253 * The type of event to map to the button's event handler (defaults to 'click')
29255 clickEvent : 'click',
29258 * @cfg {Boolean} handleMouseEvents
29259 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29261 handleMouseEvents : true,
29264 * @cfg {String} tooltipType
29265 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29267 tooltipType : 'qtip',
29270 * @cfg {String} cls
29271 * A CSS class to apply to the button's main element.
29275 * @cfg {Roo.Template} template (Optional)
29276 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29277 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29278 * require code modifications if required elements (e.g. a button) aren't present.
29282 render : function(renderTo){
29284 if(this.hideParent){
29285 this.parentEl = Roo.get(renderTo);
29287 if(!this.dhconfig){
29288 if(!this.template){
29289 if(!Roo.Button.buttonTemplate){
29290 // hideous table template
29291 Roo.Button.buttonTemplate = new Roo.Template(
29292 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29293 '<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>',
29294 "</tr></tbody></table>");
29296 this.template = Roo.Button.buttonTemplate;
29298 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29299 var btnEl = btn.child("button:first");
29300 btnEl.on('focus', this.onFocus, this);
29301 btnEl.on('blur', this.onBlur, this);
29303 btn.addClass(this.cls);
29306 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29309 btnEl.addClass(this.iconCls);
29311 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29314 if(this.tabIndex !== undefined){
29315 btnEl.dom.tabIndex = this.tabIndex;
29318 if(typeof this.tooltip == 'object'){
29319 Roo.QuickTips.tips(Roo.apply({
29323 btnEl.dom[this.tooltipType] = this.tooltip;
29327 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29331 this.el.dom.id = this.el.id = this.id;
29334 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29335 this.menu.on("show", this.onMenuShow, this);
29336 this.menu.on("hide", this.onMenuHide, this);
29338 btn.addClass("x-btn");
29339 if(Roo.isIE && !Roo.isIE7){
29340 this.autoWidth.defer(1, this);
29344 if(this.handleMouseEvents){
29345 btn.on("mouseover", this.onMouseOver, this);
29346 btn.on("mouseout", this.onMouseOut, this);
29347 btn.on("mousedown", this.onMouseDown, this);
29349 btn.on(this.clickEvent, this.onClick, this);
29350 //btn.on("mouseup", this.onMouseUp, this);
29357 Roo.ButtonToggleMgr.register(this);
29359 this.el.addClass("x-btn-pressed");
29362 var repeater = new Roo.util.ClickRepeater(btn,
29363 typeof this.repeat == "object" ? this.repeat : {}
29365 repeater.on("click", this.onClick, this);
29368 this.fireEvent('render', this);
29372 * Returns the button's underlying element
29373 * @return {Roo.Element} The element
29375 getEl : function(){
29380 * Destroys this Button and removes any listeners.
29382 destroy : function(){
29383 Roo.ButtonToggleMgr.unregister(this);
29384 this.el.removeAllListeners();
29385 this.purgeListeners();
29390 autoWidth : function(){
29392 this.el.setWidth("auto");
29393 if(Roo.isIE7 && Roo.isStrict){
29394 var ib = this.el.child('button');
29395 if(ib && ib.getWidth() > 20){
29397 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29402 this.el.beginMeasure();
29404 if(this.el.getWidth() < this.minWidth){
29405 this.el.setWidth(this.minWidth);
29408 this.el.endMeasure();
29415 * Assigns this button's click handler
29416 * @param {Function} handler The function to call when the button is clicked
29417 * @param {Object} scope (optional) Scope for the function passed in
29419 setHandler : function(handler, scope){
29420 this.handler = handler;
29421 this.scope = scope;
29425 * Sets this button's text
29426 * @param {String} text The button text
29428 setText : function(text){
29431 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29437 * Gets the text for this button
29438 * @return {String} The button text
29440 getText : function(){
29448 this.hidden = false;
29450 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29458 this.hidden = true;
29460 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29465 * Convenience function for boolean show/hide
29466 * @param {Boolean} visible True to show, false to hide
29468 setVisible: function(visible){
29477 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29478 * @param {Boolean} state (optional) Force a particular state
29480 toggle : function(state){
29481 state = state === undefined ? !this.pressed : state;
29482 if(state != this.pressed){
29484 this.el.addClass("x-btn-pressed");
29485 this.pressed = true;
29486 this.fireEvent("toggle", this, true);
29488 this.el.removeClass("x-btn-pressed");
29489 this.pressed = false;
29490 this.fireEvent("toggle", this, false);
29492 if(this.toggleHandler){
29493 this.toggleHandler.call(this.scope || this, this, state);
29501 focus : function(){
29502 this.el.child('button:first').focus();
29506 * Disable this button
29508 disable : function(){
29510 this.el.addClass("x-btn-disabled");
29512 this.disabled = true;
29516 * Enable this button
29518 enable : function(){
29520 this.el.removeClass("x-btn-disabled");
29522 this.disabled = false;
29526 * Convenience function for boolean enable/disable
29527 * @param {Boolean} enabled True to enable, false to disable
29529 setDisabled : function(v){
29530 this[v !== true ? "enable" : "disable"]();
29534 onClick : function(e)
29537 e.preventDefault();
29542 if(!this.disabled){
29543 if(this.enableToggle){
29546 if(this.menu && !this.menu.isVisible()){
29547 this.menu.show(this.el, this.menuAlign);
29549 this.fireEvent("click", this, e);
29551 this.el.removeClass("x-btn-over");
29552 this.handler.call(this.scope || this, this, e);
29557 onMouseOver : function(e){
29558 if(!this.disabled){
29559 this.el.addClass("x-btn-over");
29560 this.fireEvent('mouseover', this, e);
29564 onMouseOut : function(e){
29565 if(!e.within(this.el, true)){
29566 this.el.removeClass("x-btn-over");
29567 this.fireEvent('mouseout', this, e);
29571 onFocus : function(e){
29572 if(!this.disabled){
29573 this.el.addClass("x-btn-focus");
29577 onBlur : function(e){
29578 this.el.removeClass("x-btn-focus");
29581 onMouseDown : function(e){
29582 if(!this.disabled && e.button == 0){
29583 this.el.addClass("x-btn-click");
29584 Roo.get(document).on('mouseup', this.onMouseUp, this);
29588 onMouseUp : function(e){
29590 this.el.removeClass("x-btn-click");
29591 Roo.get(document).un('mouseup', this.onMouseUp, this);
29595 onMenuShow : function(e){
29596 this.el.addClass("x-btn-menu-active");
29599 onMenuHide : function(e){
29600 this.el.removeClass("x-btn-menu-active");
29604 // Private utility class used by Button
29605 Roo.ButtonToggleMgr = function(){
29608 function toggleGroup(btn, state){
29610 var g = groups[btn.toggleGroup];
29611 for(var i = 0, l = g.length; i < l; i++){
29613 g[i].toggle(false);
29620 register : function(btn){
29621 if(!btn.toggleGroup){
29624 var g = groups[btn.toggleGroup];
29626 g = groups[btn.toggleGroup] = [];
29629 btn.on("toggle", toggleGroup);
29632 unregister : function(btn){
29633 if(!btn.toggleGroup){
29636 var g = groups[btn.toggleGroup];
29639 btn.un("toggle", toggleGroup);
29645 * Ext JS Library 1.1.1
29646 * Copyright(c) 2006-2007, Ext JS, LLC.
29648 * Originally Released Under LGPL - original licence link has changed is not relivant.
29651 * <script type="text/javascript">
29655 * @class Roo.SplitButton
29656 * @extends Roo.Button
29657 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29658 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29659 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29660 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29661 * @cfg {String} arrowTooltip The title attribute of the arrow
29663 * Create a new menu button
29664 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29665 * @param {Object} config The config object
29667 Roo.SplitButton = function(renderTo, config){
29668 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29670 * @event arrowclick
29671 * Fires when this button's arrow is clicked
29672 * @param {SplitButton} this
29673 * @param {EventObject} e The click event
29675 this.addEvents({"arrowclick":true});
29678 Roo.extend(Roo.SplitButton, Roo.Button, {
29679 render : function(renderTo){
29680 // this is one sweet looking template!
29681 var tpl = new Roo.Template(
29682 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29683 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29684 '<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>',
29685 "</tbody></table></td><td>",
29686 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29687 '<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>',
29688 "</tbody></table></td></tr></table>"
29690 var btn = tpl.append(renderTo, [this.text, this.type], true);
29691 var btnEl = btn.child("button");
29693 btn.addClass(this.cls);
29696 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29699 btnEl.addClass(this.iconCls);
29701 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29705 if(this.handleMouseEvents){
29706 btn.on("mouseover", this.onMouseOver, this);
29707 btn.on("mouseout", this.onMouseOut, this);
29708 btn.on("mousedown", this.onMouseDown, this);
29709 btn.on("mouseup", this.onMouseUp, this);
29711 btn.on(this.clickEvent, this.onClick, this);
29713 if(typeof this.tooltip == 'object'){
29714 Roo.QuickTips.tips(Roo.apply({
29718 btnEl.dom[this.tooltipType] = this.tooltip;
29721 if(this.arrowTooltip){
29722 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29731 this.el.addClass("x-btn-pressed");
29733 if(Roo.isIE && !Roo.isIE7){
29734 this.autoWidth.defer(1, this);
29739 this.menu.on("show", this.onMenuShow, this);
29740 this.menu.on("hide", this.onMenuHide, this);
29742 this.fireEvent('render', this);
29746 autoWidth : function(){
29748 var tbl = this.el.child("table:first");
29749 var tbl2 = this.el.child("table:last");
29750 this.el.setWidth("auto");
29751 tbl.setWidth("auto");
29752 if(Roo.isIE7 && Roo.isStrict){
29753 var ib = this.el.child('button:first');
29754 if(ib && ib.getWidth() > 20){
29756 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29761 this.el.beginMeasure();
29763 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29764 tbl.setWidth(this.minWidth-tbl2.getWidth());
29767 this.el.endMeasure();
29770 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29774 * Sets this button's click handler
29775 * @param {Function} handler The function to call when the button is clicked
29776 * @param {Object} scope (optional) Scope for the function passed above
29778 setHandler : function(handler, scope){
29779 this.handler = handler;
29780 this.scope = scope;
29784 * Sets this button's arrow click handler
29785 * @param {Function} handler The function to call when the arrow is clicked
29786 * @param {Object} scope (optional) Scope for the function passed above
29788 setArrowHandler : function(handler, scope){
29789 this.arrowHandler = handler;
29790 this.scope = scope;
29796 focus : function(){
29798 this.el.child("button:first").focus();
29803 onClick : function(e){
29804 e.preventDefault();
29805 if(!this.disabled){
29806 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29807 if(this.menu && !this.menu.isVisible()){
29808 this.menu.show(this.el, this.menuAlign);
29810 this.fireEvent("arrowclick", this, e);
29811 if(this.arrowHandler){
29812 this.arrowHandler.call(this.scope || this, this, e);
29815 this.fireEvent("click", this, e);
29817 this.handler.call(this.scope || this, this, e);
29823 onMouseDown : function(e){
29824 if(!this.disabled){
29825 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29829 onMouseUp : function(e){
29830 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29835 // backwards compat
29836 Roo.MenuButton = Roo.SplitButton;/*
29838 * Ext JS Library 1.1.1
29839 * Copyright(c) 2006-2007, Ext JS, LLC.
29841 * Originally Released Under LGPL - original licence link has changed is not relivant.
29844 * <script type="text/javascript">
29848 * @class Roo.Toolbar
29849 * Basic Toolbar class.
29851 * Creates a new Toolbar
29852 * @param {Object} container The config object
29854 Roo.Toolbar = function(container, buttons, config)
29856 /// old consturctor format still supported..
29857 if(container instanceof Array){ // omit the container for later rendering
29858 buttons = container;
29862 if (typeof(container) == 'object' && container.xtype) {
29863 config = container;
29864 container = config.container;
29865 buttons = config.buttons || []; // not really - use items!!
29868 if (config && config.items) {
29869 xitems = config.items;
29870 delete config.items;
29872 Roo.apply(this, config);
29873 this.buttons = buttons;
29876 this.render(container);
29878 this.xitems = xitems;
29879 Roo.each(xitems, function(b) {
29885 Roo.Toolbar.prototype = {
29887 * @cfg {Array} items
29888 * array of button configs or elements to add (will be converted to a MixedCollection)
29892 * @cfg {String/HTMLElement/Element} container
29893 * The id or element that will contain the toolbar
29896 render : function(ct){
29897 this.el = Roo.get(ct);
29899 this.el.addClass(this.cls);
29901 // using a table allows for vertical alignment
29902 // 100% width is needed by Safari...
29903 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29904 this.tr = this.el.child("tr", true);
29906 this.items = new Roo.util.MixedCollection(false, function(o){
29907 return o.id || ("item" + (++autoId));
29910 this.add.apply(this, this.buttons);
29911 delete this.buttons;
29916 * Adds element(s) to the toolbar -- this function takes a variable number of
29917 * arguments of mixed type and adds them to the toolbar.
29918 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29920 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29921 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29922 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29923 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29924 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29925 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29926 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29927 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29928 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29930 * @param {Mixed} arg2
29931 * @param {Mixed} etc.
29934 var a = arguments, l = a.length;
29935 for(var i = 0; i < l; i++){
29940 _add : function(el) {
29943 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29946 if (el.applyTo){ // some kind of form field
29947 return this.addField(el);
29949 if (el.render){ // some kind of Toolbar.Item
29950 return this.addItem(el);
29952 if (typeof el == "string"){ // string
29953 if(el == "separator" || el == "-"){
29954 return this.addSeparator();
29957 return this.addSpacer();
29960 return this.addFill();
29962 return this.addText(el);
29965 if(el.tagName){ // element
29966 return this.addElement(el);
29968 if(typeof el == "object"){ // must be button config?
29969 return this.addButton(el);
29971 // and now what?!?!
29977 * Add an Xtype element
29978 * @param {Object} xtype Xtype Object
29979 * @return {Object} created Object
29981 addxtype : function(e){
29982 return this.add(e);
29986 * Returns the Element for this toolbar.
29987 * @return {Roo.Element}
29989 getEl : function(){
29995 * @return {Roo.Toolbar.Item} The separator item
29997 addSeparator : function(){
29998 return this.addItem(new Roo.Toolbar.Separator());
30002 * Adds a spacer element
30003 * @return {Roo.Toolbar.Spacer} The spacer item
30005 addSpacer : function(){
30006 return this.addItem(new Roo.Toolbar.Spacer());
30010 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30011 * @return {Roo.Toolbar.Fill} The fill item
30013 addFill : function(){
30014 return this.addItem(new Roo.Toolbar.Fill());
30018 * Adds any standard HTML element to the toolbar
30019 * @param {String/HTMLElement/Element} el The element or id of the element to add
30020 * @return {Roo.Toolbar.Item} The element's item
30022 addElement : function(el){
30023 return this.addItem(new Roo.Toolbar.Item(el));
30026 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30027 * @type Roo.util.MixedCollection
30032 * Adds any Toolbar.Item or subclass
30033 * @param {Roo.Toolbar.Item} item
30034 * @return {Roo.Toolbar.Item} The item
30036 addItem : function(item){
30037 var td = this.nextBlock();
30039 this.items.add(item);
30044 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30045 * @param {Object/Array} config A button config or array of configs
30046 * @return {Roo.Toolbar.Button/Array}
30048 addButton : function(config){
30049 if(config instanceof Array){
30051 for(var i = 0, len = config.length; i < len; i++) {
30052 buttons.push(this.addButton(config[i]));
30057 if(!(config instanceof Roo.Toolbar.Button)){
30059 new Roo.Toolbar.SplitButton(config) :
30060 new Roo.Toolbar.Button(config);
30062 var td = this.nextBlock();
30069 * Adds text to the toolbar
30070 * @param {String} text The text to add
30071 * @return {Roo.Toolbar.Item} The element's item
30073 addText : function(text){
30074 return this.addItem(new Roo.Toolbar.TextItem(text));
30078 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30079 * @param {Number} index The index where the item is to be inserted
30080 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30081 * @return {Roo.Toolbar.Button/Item}
30083 insertButton : function(index, item){
30084 if(item instanceof Array){
30086 for(var i = 0, len = item.length; i < len; i++) {
30087 buttons.push(this.insertButton(index + i, item[i]));
30091 if (!(item instanceof Roo.Toolbar.Button)){
30092 item = new Roo.Toolbar.Button(item);
30094 var td = document.createElement("td");
30095 this.tr.insertBefore(td, this.tr.childNodes[index]);
30097 this.items.insert(index, item);
30102 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30103 * @param {Object} config
30104 * @return {Roo.Toolbar.Item} The element's item
30106 addDom : function(config, returnEl){
30107 var td = this.nextBlock();
30108 Roo.DomHelper.overwrite(td, config);
30109 var ti = new Roo.Toolbar.Item(td.firstChild);
30111 this.items.add(ti);
30116 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30117 * @type Roo.util.MixedCollection
30122 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30123 * Note: the field should not have been rendered yet. For a field that has already been
30124 * rendered, use {@link #addElement}.
30125 * @param {Roo.form.Field} field
30126 * @return {Roo.ToolbarItem}
30130 addField : function(field) {
30131 if (!this.fields) {
30133 this.fields = new Roo.util.MixedCollection(false, function(o){
30134 return o.id || ("item" + (++autoId));
30139 var td = this.nextBlock();
30141 var ti = new Roo.Toolbar.Item(td.firstChild);
30143 this.items.add(ti);
30144 this.fields.add(field);
30155 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30156 this.el.child('div').hide();
30164 this.el.child('div').show();
30168 nextBlock : function(){
30169 var td = document.createElement("td");
30170 this.tr.appendChild(td);
30175 destroy : function(){
30176 if(this.items){ // rendered?
30177 Roo.destroy.apply(Roo, this.items.items);
30179 if(this.fields){ // rendered?
30180 Roo.destroy.apply(Roo, this.fields.items);
30182 Roo.Element.uncache(this.el, this.tr);
30187 * @class Roo.Toolbar.Item
30188 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30190 * Creates a new Item
30191 * @param {HTMLElement} el
30193 Roo.Toolbar.Item = function(el){
30195 if (typeof (el.xtype) != 'undefined') {
30200 this.el = Roo.getDom(el);
30201 this.id = Roo.id(this.el);
30202 this.hidden = false;
30207 * Fires when the button is rendered
30208 * @param {Button} this
30212 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30214 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30215 //Roo.Toolbar.Item.prototype = {
30218 * Get this item's HTML Element
30219 * @return {HTMLElement}
30221 getEl : function(){
30226 render : function(td){
30229 td.appendChild(this.el);
30231 this.fireEvent('render', this);
30235 * Removes and destroys this item.
30237 destroy : function(){
30238 this.td.parentNode.removeChild(this.td);
30245 this.hidden = false;
30246 this.td.style.display = "";
30253 this.hidden = true;
30254 this.td.style.display = "none";
30258 * Convenience function for boolean show/hide.
30259 * @param {Boolean} visible true to show/false to hide
30261 setVisible: function(visible){
30270 * Try to focus this item.
30272 focus : function(){
30273 Roo.fly(this.el).focus();
30277 * Disables this item.
30279 disable : function(){
30280 Roo.fly(this.td).addClass("x-item-disabled");
30281 this.disabled = true;
30282 this.el.disabled = true;
30286 * Enables this item.
30288 enable : function(){
30289 Roo.fly(this.td).removeClass("x-item-disabled");
30290 this.disabled = false;
30291 this.el.disabled = false;
30297 * @class Roo.Toolbar.Separator
30298 * @extends Roo.Toolbar.Item
30299 * A simple toolbar separator class
30301 * Creates a new Separator
30303 Roo.Toolbar.Separator = function(cfg){
30305 var s = document.createElement("span");
30306 s.className = "ytb-sep";
30311 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30313 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30314 enable:Roo.emptyFn,
30315 disable:Roo.emptyFn,
30320 * @class Roo.Toolbar.Spacer
30321 * @extends Roo.Toolbar.Item
30322 * A simple element that adds extra horizontal space to a toolbar.
30324 * Creates a new Spacer
30326 Roo.Toolbar.Spacer = function(cfg){
30327 var s = document.createElement("div");
30328 s.className = "ytb-spacer";
30332 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30334 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30335 enable:Roo.emptyFn,
30336 disable:Roo.emptyFn,
30341 * @class Roo.Toolbar.Fill
30342 * @extends Roo.Toolbar.Spacer
30343 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30345 * Creates a new Spacer
30347 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30349 render : function(td){
30350 td.style.width = '100%';
30351 Roo.Toolbar.Fill.superclass.render.call(this, td);
30356 * @class Roo.Toolbar.TextItem
30357 * @extends Roo.Toolbar.Item
30358 * A simple class that renders text directly into a toolbar.
30360 * Creates a new TextItem
30361 * @param {String} text
30363 Roo.Toolbar.TextItem = function(cfg){
30364 var text = cfg || "";
30365 if (typeof(cfg) == 'object') {
30366 text = cfg.text || "";
30370 var s = document.createElement("span");
30371 s.className = "ytb-text";
30372 s.innerHTML = text;
30377 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30379 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30382 enable:Roo.emptyFn,
30383 disable:Roo.emptyFn,
30388 * @class Roo.Toolbar.Button
30389 * @extends Roo.Button
30390 * A button that renders into a toolbar.
30392 * Creates a new Button
30393 * @param {Object} config A standard {@link Roo.Button} config object
30395 Roo.Toolbar.Button = function(config){
30396 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30398 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30399 render : function(td){
30401 Roo.Toolbar.Button.superclass.render.call(this, td);
30405 * Removes and destroys this button
30407 destroy : function(){
30408 Roo.Toolbar.Button.superclass.destroy.call(this);
30409 this.td.parentNode.removeChild(this.td);
30413 * Shows this button
30416 this.hidden = false;
30417 this.td.style.display = "";
30421 * Hides this button
30424 this.hidden = true;
30425 this.td.style.display = "none";
30429 * Disables this item
30431 disable : function(){
30432 Roo.fly(this.td).addClass("x-item-disabled");
30433 this.disabled = true;
30437 * Enables this item
30439 enable : function(){
30440 Roo.fly(this.td).removeClass("x-item-disabled");
30441 this.disabled = false;
30444 // backwards compat
30445 Roo.ToolbarButton = Roo.Toolbar.Button;
30448 * @class Roo.Toolbar.SplitButton
30449 * @extends Roo.SplitButton
30450 * A menu button that renders into a toolbar.
30452 * Creates a new SplitButton
30453 * @param {Object} config A standard {@link Roo.SplitButton} config object
30455 Roo.Toolbar.SplitButton = function(config){
30456 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30458 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30459 render : function(td){
30461 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30465 * Removes and destroys this button
30467 destroy : function(){
30468 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30469 this.td.parentNode.removeChild(this.td);
30473 * Shows this button
30476 this.hidden = false;
30477 this.td.style.display = "";
30481 * Hides this button
30484 this.hidden = true;
30485 this.td.style.display = "none";
30489 // backwards compat
30490 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30492 * Ext JS Library 1.1.1
30493 * Copyright(c) 2006-2007, Ext JS, LLC.
30495 * Originally Released Under LGPL - original licence link has changed is not relivant.
30498 * <script type="text/javascript">
30502 * @class Roo.PagingToolbar
30503 * @extends Roo.Toolbar
30504 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30506 * Create a new PagingToolbar
30507 * @param {Object} config The config object
30509 Roo.PagingToolbar = function(el, ds, config)
30511 // old args format still supported... - xtype is prefered..
30512 if (typeof(el) == 'object' && el.xtype) {
30513 // created from xtype...
30515 ds = el.dataSource;
30516 el = config.container;
30519 if (config.items) {
30520 items = config.items;
30524 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30527 this.renderButtons(this.el);
30530 // supprot items array.
30532 Roo.each(items, function(e) {
30533 this.add(Roo.factory(e));
30538 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30540 * @cfg {Roo.data.Store} dataSource
30541 * The underlying data store providing the paged data
30544 * @cfg {String/HTMLElement/Element} container
30545 * container The id or element that will contain the toolbar
30548 * @cfg {Boolean} displayInfo
30549 * True to display the displayMsg (defaults to false)
30552 * @cfg {Number} pageSize
30553 * The number of records to display per page (defaults to 20)
30557 * @cfg {String} displayMsg
30558 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30560 displayMsg : 'Displaying {0} - {1} of {2}',
30562 * @cfg {String} emptyMsg
30563 * The message to display when no records are found (defaults to "No data to display")
30565 emptyMsg : 'No data to display',
30567 * Customizable piece of the default paging text (defaults to "Page")
30570 beforePageText : "Page",
30572 * Customizable piece of the default paging text (defaults to "of %0")
30575 afterPageText : "of {0}",
30577 * Customizable piece of the default paging text (defaults to "First Page")
30580 firstText : "First Page",
30582 * Customizable piece of the default paging text (defaults to "Previous Page")
30585 prevText : "Previous Page",
30587 * Customizable piece of the default paging text (defaults to "Next Page")
30590 nextText : "Next Page",
30592 * Customizable piece of the default paging text (defaults to "Last Page")
30595 lastText : "Last Page",
30597 * Customizable piece of the default paging text (defaults to "Refresh")
30600 refreshText : "Refresh",
30603 renderButtons : function(el){
30604 Roo.PagingToolbar.superclass.render.call(this, el);
30605 this.first = this.addButton({
30606 tooltip: this.firstText,
30607 cls: "x-btn-icon x-grid-page-first",
30609 handler: this.onClick.createDelegate(this, ["first"])
30611 this.prev = this.addButton({
30612 tooltip: this.prevText,
30613 cls: "x-btn-icon x-grid-page-prev",
30615 handler: this.onClick.createDelegate(this, ["prev"])
30617 //this.addSeparator();
30618 this.add(this.beforePageText);
30619 this.field = Roo.get(this.addDom({
30624 cls: "x-grid-page-number"
30626 this.field.on("keydown", this.onPagingKeydown, this);
30627 this.field.on("focus", function(){this.dom.select();});
30628 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30629 this.field.setHeight(18);
30630 //this.addSeparator();
30631 this.next = this.addButton({
30632 tooltip: this.nextText,
30633 cls: "x-btn-icon x-grid-page-next",
30635 handler: this.onClick.createDelegate(this, ["next"])
30637 this.last = this.addButton({
30638 tooltip: this.lastText,
30639 cls: "x-btn-icon x-grid-page-last",
30641 handler: this.onClick.createDelegate(this, ["last"])
30643 //this.addSeparator();
30644 this.loading = this.addButton({
30645 tooltip: this.refreshText,
30646 cls: "x-btn-icon x-grid-loading",
30647 handler: this.onClick.createDelegate(this, ["refresh"])
30650 if(this.displayInfo){
30651 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30656 updateInfo : function(){
30657 if(this.displayEl){
30658 var count = this.ds.getCount();
30659 var msg = count == 0 ?
30663 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30665 this.displayEl.update(msg);
30670 onLoad : function(ds, r, o){
30671 this.cursor = o.params ? o.params.start : 0;
30672 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30674 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30675 this.field.dom.value = ap;
30676 this.first.setDisabled(ap == 1);
30677 this.prev.setDisabled(ap == 1);
30678 this.next.setDisabled(ap == ps);
30679 this.last.setDisabled(ap == ps);
30680 this.loading.enable();
30685 getPageData : function(){
30686 var total = this.ds.getTotalCount();
30689 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30690 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30695 onLoadError : function(){
30696 this.loading.enable();
30700 onPagingKeydown : function(e){
30701 var k = e.getKey();
30702 var d = this.getPageData();
30704 var v = this.field.dom.value, pageNum;
30705 if(!v || isNaN(pageNum = parseInt(v, 10))){
30706 this.field.dom.value = d.activePage;
30709 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30710 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30713 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))
30715 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30716 this.field.dom.value = pageNum;
30717 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30720 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30722 var v = this.field.dom.value, pageNum;
30723 var increment = (e.shiftKey) ? 10 : 1;
30724 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30727 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30728 this.field.dom.value = d.activePage;
30731 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30733 this.field.dom.value = parseInt(v, 10) + increment;
30734 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30735 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30742 beforeLoad : function(){
30744 this.loading.disable();
30749 onClick : function(which){
30753 ds.load({params:{start: 0, limit: this.pageSize}});
30756 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30759 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30762 var total = ds.getTotalCount();
30763 var extra = total % this.pageSize;
30764 var lastStart = extra ? (total - extra) : total-this.pageSize;
30765 ds.load({params:{start: lastStart, limit: this.pageSize}});
30768 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30774 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30775 * @param {Roo.data.Store} store The data store to unbind
30777 unbind : function(ds){
30778 ds.un("beforeload", this.beforeLoad, this);
30779 ds.un("load", this.onLoad, this);
30780 ds.un("loadexception", this.onLoadError, this);
30781 ds.un("remove", this.updateInfo, this);
30782 ds.un("add", this.updateInfo, this);
30783 this.ds = undefined;
30787 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30788 * @param {Roo.data.Store} store The data store to bind
30790 bind : function(ds){
30791 ds.on("beforeload", this.beforeLoad, this);
30792 ds.on("load", this.onLoad, this);
30793 ds.on("loadexception", this.onLoadError, this);
30794 ds.on("remove", this.updateInfo, this);
30795 ds.on("add", this.updateInfo, this);
30800 * Ext JS Library 1.1.1
30801 * Copyright(c) 2006-2007, Ext JS, LLC.
30803 * Originally Released Under LGPL - original licence link has changed is not relivant.
30806 * <script type="text/javascript">
30810 * @class Roo.Resizable
30811 * @extends Roo.util.Observable
30812 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30813 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30814 * 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
30815 * the element will be wrapped for you automatically.</p>
30816 * <p>Here is the list of valid resize handles:</p>
30819 ------ -------------------
30828 'hd' horizontal drag
30831 * <p>Here's an example showing the creation of a typical Resizable:</p>
30833 var resizer = new Roo.Resizable("element-id", {
30841 resizer.on("resize", myHandler);
30843 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30844 * resizer.east.setDisplayed(false);</p>
30845 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30846 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30847 * resize operation's new size (defaults to [0, 0])
30848 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30849 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30850 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30851 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30852 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30853 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30854 * @cfg {Number} width The width of the element in pixels (defaults to null)
30855 * @cfg {Number} height The height of the element in pixels (defaults to null)
30856 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30857 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30858 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30859 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30860 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30861 * in favor of the handles config option (defaults to false)
30862 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30863 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30864 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30865 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30866 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30867 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30868 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30869 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30870 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30871 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30872 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30874 * Create a new resizable component
30875 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30876 * @param {Object} config configuration options
30878 Roo.Resizable = function(el, config)
30880 this.el = Roo.get(el);
30882 if(config && config.wrap){
30883 config.resizeChild = this.el;
30884 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30885 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30886 this.el.setStyle("overflow", "hidden");
30887 this.el.setPositioning(config.resizeChild.getPositioning());
30888 config.resizeChild.clearPositioning();
30889 if(!config.width || !config.height){
30890 var csize = config.resizeChild.getSize();
30891 this.el.setSize(csize.width, csize.height);
30893 if(config.pinned && !config.adjustments){
30894 config.adjustments = "auto";
30898 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30899 this.proxy.unselectable();
30900 this.proxy.enableDisplayMode('block');
30902 Roo.apply(this, config);
30905 this.disableTrackOver = true;
30906 this.el.addClass("x-resizable-pinned");
30908 // if the element isn't positioned, make it relative
30909 var position = this.el.getStyle("position");
30910 if(position != "absolute" && position != "fixed"){
30911 this.el.setStyle("position", "relative");
30913 if(!this.handles){ // no handles passed, must be legacy style
30914 this.handles = 's,e,se';
30915 if(this.multiDirectional){
30916 this.handles += ',n,w';
30919 if(this.handles == "all"){
30920 this.handles = "n s e w ne nw se sw";
30922 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30923 var ps = Roo.Resizable.positions;
30924 for(var i = 0, len = hs.length; i < len; i++){
30925 if(hs[i] && ps[hs[i]]){
30926 var pos = ps[hs[i]];
30927 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30931 this.corner = this.southeast;
30933 // updateBox = the box can move..
30934 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30935 this.updateBox = true;
30938 this.activeHandle = null;
30940 if(this.resizeChild){
30941 if(typeof this.resizeChild == "boolean"){
30942 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30944 this.resizeChild = Roo.get(this.resizeChild, true);
30948 if(this.adjustments == "auto"){
30949 var rc = this.resizeChild;
30950 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30951 if(rc && (hw || hn)){
30952 rc.position("relative");
30953 rc.setLeft(hw ? hw.el.getWidth() : 0);
30954 rc.setTop(hn ? hn.el.getHeight() : 0);
30956 this.adjustments = [
30957 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30958 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30962 if(this.draggable){
30963 this.dd = this.dynamic ?
30964 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30965 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30971 * @event beforeresize
30972 * Fired before resize is allowed. Set enabled to false to cancel resize.
30973 * @param {Roo.Resizable} this
30974 * @param {Roo.EventObject} e The mousedown event
30976 "beforeresize" : true,
30979 * Fired a resizing.
30980 * @param {Roo.Resizable} this
30981 * @param {Number} x The new x position
30982 * @param {Number} y The new y position
30983 * @param {Number} w The new w width
30984 * @param {Number} h The new h hight
30985 * @param {Roo.EventObject} e The mouseup event
30990 * Fired after a resize.
30991 * @param {Roo.Resizable} this
30992 * @param {Number} width The new width
30993 * @param {Number} height The new height
30994 * @param {Roo.EventObject} e The mouseup event
30999 if(this.width !== null && this.height !== null){
31000 this.resizeTo(this.width, this.height);
31002 this.updateChildSize();
31005 this.el.dom.style.zoom = 1;
31007 Roo.Resizable.superclass.constructor.call(this);
31010 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31011 resizeChild : false,
31012 adjustments : [0, 0],
31022 multiDirectional : false,
31023 disableTrackOver : false,
31024 easing : 'easeOutStrong',
31025 widthIncrement : 0,
31026 heightIncrement : 0,
31030 preserveRatio : false,
31031 transparent: false,
31037 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31039 constrainTo: undefined,
31041 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31043 resizeRegion: undefined,
31047 * Perform a manual resize
31048 * @param {Number} width
31049 * @param {Number} height
31051 resizeTo : function(width, height){
31052 this.el.setSize(width, height);
31053 this.updateChildSize();
31054 this.fireEvent("resize", this, width, height, null);
31058 startSizing : function(e, handle){
31059 this.fireEvent("beforeresize", this, e);
31060 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31063 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31064 this.overlay.unselectable();
31065 this.overlay.enableDisplayMode("block");
31066 this.overlay.on("mousemove", this.onMouseMove, this);
31067 this.overlay.on("mouseup", this.onMouseUp, this);
31069 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31071 this.resizing = true;
31072 this.startBox = this.el.getBox();
31073 this.startPoint = e.getXY();
31074 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31075 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31077 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31078 this.overlay.show();
31080 if(this.constrainTo) {
31081 var ct = Roo.get(this.constrainTo);
31082 this.resizeRegion = ct.getRegion().adjust(
31083 ct.getFrameWidth('t'),
31084 ct.getFrameWidth('l'),
31085 -ct.getFrameWidth('b'),
31086 -ct.getFrameWidth('r')
31090 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31092 this.proxy.setBox(this.startBox);
31094 this.proxy.setStyle('visibility', 'visible');
31100 onMouseDown : function(handle, e){
31103 this.activeHandle = handle;
31104 this.startSizing(e, handle);
31109 onMouseUp : function(e){
31110 var size = this.resizeElement();
31111 this.resizing = false;
31113 this.overlay.hide();
31115 this.fireEvent("resize", this, size.width, size.height, e);
31119 updateChildSize : function(){
31121 if(this.resizeChild){
31123 var child = this.resizeChild;
31124 var adj = this.adjustments;
31125 if(el.dom.offsetWidth){
31126 var b = el.getSize(true);
31127 child.setSize(b.width+adj[0], b.height+adj[1]);
31129 // Second call here for IE
31130 // The first call enables instant resizing and
31131 // the second call corrects scroll bars if they
31134 setTimeout(function(){
31135 if(el.dom.offsetWidth){
31136 var b = el.getSize(true);
31137 child.setSize(b.width+adj[0], b.height+adj[1]);
31145 snap : function(value, inc, min){
31146 if(!inc || !value) {
31149 var newValue = value;
31150 var m = value % inc;
31153 newValue = value + (inc-m);
31155 newValue = value - m;
31158 return Math.max(min, newValue);
31162 resizeElement : function(){
31163 var box = this.proxy.getBox();
31164 if(this.updateBox){
31165 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31167 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31169 this.updateChildSize();
31177 constrain : function(v, diff, m, mx){
31180 }else if(v - diff > mx){
31187 onMouseMove : function(e){
31190 try{// try catch so if something goes wrong the user doesn't get hung
31192 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31196 //var curXY = this.startPoint;
31197 var curSize = this.curSize || this.startBox;
31198 var x = this.startBox.x, y = this.startBox.y;
31199 var ox = x, oy = y;
31200 var w = curSize.width, h = curSize.height;
31201 var ow = w, oh = h;
31202 var mw = this.minWidth, mh = this.minHeight;
31203 var mxw = this.maxWidth, mxh = this.maxHeight;
31204 var wi = this.widthIncrement;
31205 var hi = this.heightIncrement;
31207 var eventXY = e.getXY();
31208 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31209 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31211 var pos = this.activeHandle.position;
31216 w = Math.min(Math.max(mw, w), mxw);
31221 h = Math.min(Math.max(mh, h), mxh);
31226 w = Math.min(Math.max(mw, w), mxw);
31227 h = Math.min(Math.max(mh, h), mxh);
31230 diffY = this.constrain(h, diffY, mh, mxh);
31237 var adiffX = Math.abs(diffX);
31238 var sub = (adiffX % wi); // how much
31239 if (sub > (wi/2)) { // far enough to snap
31240 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31242 // remove difference..
31243 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31247 x = Math.max(this.minX, x);
31250 diffX = this.constrain(w, diffX, mw, mxw);
31256 w = Math.min(Math.max(mw, w), mxw);
31257 diffY = this.constrain(h, diffY, mh, mxh);
31262 diffX = this.constrain(w, diffX, mw, mxw);
31263 diffY = this.constrain(h, diffY, mh, mxh);
31270 diffX = this.constrain(w, diffX, mw, mxw);
31272 h = Math.min(Math.max(mh, h), mxh);
31278 var sw = this.snap(w, wi, mw);
31279 var sh = this.snap(h, hi, mh);
31280 if(sw != w || sh != h){
31303 if(this.preserveRatio){
31308 h = Math.min(Math.max(mh, h), mxh);
31313 w = Math.min(Math.max(mw, w), mxw);
31318 w = Math.min(Math.max(mw, w), mxw);
31324 w = Math.min(Math.max(mw, w), mxw);
31330 h = Math.min(Math.max(mh, h), mxh);
31338 h = Math.min(Math.max(mh, h), mxh);
31348 h = Math.min(Math.max(mh, h), mxh);
31356 if (pos == 'hdrag') {
31359 this.proxy.setBounds(x, y, w, h);
31361 this.resizeElement();
31365 this.fireEvent("resizing", this, x, y, w, h, e);
31369 handleOver : function(){
31371 this.el.addClass("x-resizable-over");
31376 handleOut : function(){
31377 if(!this.resizing){
31378 this.el.removeClass("x-resizable-over");
31383 * Returns the element this component is bound to.
31384 * @return {Roo.Element}
31386 getEl : function(){
31391 * Returns the resizeChild element (or null).
31392 * @return {Roo.Element}
31394 getResizeChild : function(){
31395 return this.resizeChild;
31397 groupHandler : function()
31402 * Destroys this resizable. If the element was wrapped and
31403 * removeEl is not true then the element remains.
31404 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31406 destroy : function(removeEl){
31407 this.proxy.remove();
31409 this.overlay.removeAllListeners();
31410 this.overlay.remove();
31412 var ps = Roo.Resizable.positions;
31414 if(typeof ps[k] != "function" && this[ps[k]]){
31415 var h = this[ps[k]];
31416 h.el.removeAllListeners();
31421 this.el.update("");
31428 // hash to map config positions to true positions
31429 Roo.Resizable.positions = {
31430 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31435 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31437 // only initialize the template if resizable is used
31438 var tpl = Roo.DomHelper.createTemplate(
31439 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31442 Roo.Resizable.Handle.prototype.tpl = tpl;
31444 this.position = pos;
31446 // show north drag fro topdra
31447 var handlepos = pos == 'hdrag' ? 'north' : pos;
31449 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31450 if (pos == 'hdrag') {
31451 this.el.setStyle('cursor', 'pointer');
31453 this.el.unselectable();
31455 this.el.setOpacity(0);
31457 this.el.on("mousedown", this.onMouseDown, this);
31458 if(!disableTrackOver){
31459 this.el.on("mouseover", this.onMouseOver, this);
31460 this.el.on("mouseout", this.onMouseOut, this);
31465 Roo.Resizable.Handle.prototype = {
31466 afterResize : function(rz){
31471 onMouseDown : function(e){
31472 this.rz.onMouseDown(this, e);
31475 onMouseOver : function(e){
31476 this.rz.handleOver(this, e);
31479 onMouseOut : function(e){
31480 this.rz.handleOut(this, e);
31484 * Ext JS Library 1.1.1
31485 * Copyright(c) 2006-2007, Ext JS, LLC.
31487 * Originally Released Under LGPL - original licence link has changed is not relivant.
31490 * <script type="text/javascript">
31494 * @class Roo.Editor
31495 * @extends Roo.Component
31496 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31498 * Create a new Editor
31499 * @param {Roo.form.Field} field The Field object (or descendant)
31500 * @param {Object} config The config object
31502 Roo.Editor = function(field, config){
31503 Roo.Editor.superclass.constructor.call(this, config);
31504 this.field = field;
31507 * @event beforestartedit
31508 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31509 * false from the handler of this event.
31510 * @param {Editor} this
31511 * @param {Roo.Element} boundEl The underlying element bound to this editor
31512 * @param {Mixed} value The field value being set
31514 "beforestartedit" : true,
31517 * Fires when this editor is displayed
31518 * @param {Roo.Element} boundEl The underlying element bound to this editor
31519 * @param {Mixed} value The starting field value
31521 "startedit" : true,
31523 * @event beforecomplete
31524 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31525 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31526 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31527 * event will not fire since no edit actually occurred.
31528 * @param {Editor} this
31529 * @param {Mixed} value The current field value
31530 * @param {Mixed} startValue The original field value
31532 "beforecomplete" : true,
31535 * Fires after editing is complete and any changed value has been written to the underlying field.
31536 * @param {Editor} this
31537 * @param {Mixed} value The current field value
31538 * @param {Mixed} startValue The original field value
31542 * @event specialkey
31543 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31544 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31545 * @param {Roo.form.Field} this
31546 * @param {Roo.EventObject} e The event object
31548 "specialkey" : true
31552 Roo.extend(Roo.Editor, Roo.Component, {
31554 * @cfg {Boolean/String} autosize
31555 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31556 * or "height" to adopt the height only (defaults to false)
31559 * @cfg {Boolean} revertInvalid
31560 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31561 * validation fails (defaults to true)
31564 * @cfg {Boolean} ignoreNoChange
31565 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31566 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31567 * will never be ignored.
31570 * @cfg {Boolean} hideEl
31571 * False to keep the bound element visible while the editor is displayed (defaults to true)
31574 * @cfg {Mixed} value
31575 * The data value of the underlying field (defaults to "")
31579 * @cfg {String} alignment
31580 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31584 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31585 * for bottom-right shadow (defaults to "frame")
31589 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31593 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31595 completeOnEnter : false,
31597 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31599 cancelOnEsc : false,
31601 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31606 onRender : function(ct, position){
31607 this.el = new Roo.Layer({
31608 shadow: this.shadow,
31614 constrain: this.constrain
31616 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31617 if(this.field.msgTarget != 'title'){
31618 this.field.msgTarget = 'qtip';
31620 this.field.render(this.el);
31622 this.field.el.dom.setAttribute('autocomplete', 'off');
31624 this.field.on("specialkey", this.onSpecialKey, this);
31625 if(this.swallowKeys){
31626 this.field.el.swallowEvent(['keydown','keypress']);
31629 this.field.on("blur", this.onBlur, this);
31630 if(this.field.grow){
31631 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31635 onSpecialKey : function(field, e)
31637 //Roo.log('editor onSpecialKey');
31638 if(this.completeOnEnter && e.getKey() == e.ENTER){
31640 this.completeEdit();
31643 // do not fire special key otherwise it might hide close the editor...
31644 if(e.getKey() == e.ENTER){
31647 if(this.cancelOnEsc && e.getKey() == e.ESC){
31651 this.fireEvent('specialkey', field, e);
31656 * Starts the editing process and shows the editor.
31657 * @param {String/HTMLElement/Element} el The element to edit
31658 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31659 * to the innerHTML of el.
31661 startEdit : function(el, value){
31663 this.completeEdit();
31665 this.boundEl = Roo.get(el);
31666 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31667 if(!this.rendered){
31668 this.render(this.parentEl || document.body);
31670 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31673 this.startValue = v;
31674 this.field.setValue(v);
31676 var sz = this.boundEl.getSize();
31677 switch(this.autoSize){
31679 this.setSize(sz.width, "");
31682 this.setSize("", sz.height);
31685 this.setSize(sz.width, sz.height);
31688 this.el.alignTo(this.boundEl, this.alignment);
31689 this.editing = true;
31691 Roo.QuickTips.disable();
31697 * Sets the height and width of this editor.
31698 * @param {Number} width The new width
31699 * @param {Number} height The new height
31701 setSize : function(w, h){
31702 this.field.setSize(w, h);
31709 * Realigns the editor to the bound field based on the current alignment config value.
31711 realign : function(){
31712 this.el.alignTo(this.boundEl, this.alignment);
31716 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31717 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31719 completeEdit : function(remainVisible){
31723 var v = this.getValue();
31724 if(this.revertInvalid !== false && !this.field.isValid()){
31725 v = this.startValue;
31726 this.cancelEdit(true);
31728 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31729 this.editing = false;
31733 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31734 this.editing = false;
31735 if(this.updateEl && this.boundEl){
31736 this.boundEl.update(v);
31738 if(remainVisible !== true){
31741 this.fireEvent("complete", this, v, this.startValue);
31746 onShow : function(){
31748 if(this.hideEl !== false){
31749 this.boundEl.hide();
31752 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31753 this.fixIEFocus = true;
31754 this.deferredFocus.defer(50, this);
31756 this.field.focus();
31758 this.fireEvent("startedit", this.boundEl, this.startValue);
31761 deferredFocus : function(){
31763 this.field.focus();
31768 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31769 * reverted to the original starting value.
31770 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31771 * cancel (defaults to false)
31773 cancelEdit : function(remainVisible){
31775 this.setValue(this.startValue);
31776 if(remainVisible !== true){
31783 onBlur : function(){
31784 if(this.allowBlur !== true && this.editing){
31785 this.completeEdit();
31790 onHide : function(){
31792 this.completeEdit();
31796 if(this.field.collapse){
31797 this.field.collapse();
31800 if(this.hideEl !== false){
31801 this.boundEl.show();
31804 Roo.QuickTips.enable();
31809 * Sets the data value of the editor
31810 * @param {Mixed} value Any valid value supported by the underlying field
31812 setValue : function(v){
31813 this.field.setValue(v);
31817 * Gets the data value of the editor
31818 * @return {Mixed} The data value
31820 getValue : function(){
31821 return this.field.getValue();
31825 * Ext JS Library 1.1.1
31826 * Copyright(c) 2006-2007, Ext JS, LLC.
31828 * Originally Released Under LGPL - original licence link has changed is not relivant.
31831 * <script type="text/javascript">
31835 * @class Roo.BasicDialog
31836 * @extends Roo.util.Observable
31837 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31839 var dlg = new Roo.BasicDialog("my-dlg", {
31848 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31849 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31850 dlg.addButton('Cancel', dlg.hide, dlg);
31853 <b>A Dialog should always be a direct child of the body element.</b>
31854 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31855 * @cfg {String} title Default text to display in the title bar (defaults to null)
31856 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31857 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31858 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31859 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31860 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31861 * (defaults to null with no animation)
31862 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31863 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31864 * property for valid values (defaults to 'all')
31865 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31866 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31867 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31868 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31869 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31870 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31871 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31872 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31873 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31874 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31875 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31876 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31877 * draggable = true (defaults to false)
31878 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31879 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31880 * shadow (defaults to false)
31881 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31882 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31883 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31884 * @cfg {Array} buttons Array of buttons
31885 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31887 * Create a new BasicDialog.
31888 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31889 * @param {Object} config Configuration options
31891 Roo.BasicDialog = function(el, config){
31892 this.el = Roo.get(el);
31893 var dh = Roo.DomHelper;
31894 if(!this.el && config && config.autoCreate){
31895 if(typeof config.autoCreate == "object"){
31896 if(!config.autoCreate.id){
31897 config.autoCreate.id = el;
31899 this.el = dh.append(document.body,
31900 config.autoCreate, true);
31902 this.el = dh.append(document.body,
31903 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31907 el.setDisplayed(true);
31908 el.hide = this.hideAction;
31910 el.addClass("x-dlg");
31912 Roo.apply(this, config);
31914 this.proxy = el.createProxy("x-dlg-proxy");
31915 this.proxy.hide = this.hideAction;
31916 this.proxy.setOpacity(.5);
31920 el.setWidth(config.width);
31923 el.setHeight(config.height);
31925 this.size = el.getSize();
31926 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31927 this.xy = [config.x,config.y];
31929 this.xy = el.getCenterXY(true);
31931 /** The header element @type Roo.Element */
31932 this.header = el.child("> .x-dlg-hd");
31933 /** The body element @type Roo.Element */
31934 this.body = el.child("> .x-dlg-bd");
31935 /** The footer element @type Roo.Element */
31936 this.footer = el.child("> .x-dlg-ft");
31939 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31942 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31945 this.header.unselectable();
31947 this.header.update(this.title);
31949 // this element allows the dialog to be focused for keyboard event
31950 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31951 this.focusEl.swallowEvent("click", true);
31953 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31955 // wrap the body and footer for special rendering
31956 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31958 this.bwrap.dom.appendChild(this.footer.dom);
31961 this.bg = this.el.createChild({
31962 tag: "div", cls:"x-dlg-bg",
31963 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31965 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31968 if(this.autoScroll !== false && !this.autoTabs){
31969 this.body.setStyle("overflow", "auto");
31972 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31974 if(this.closable !== false){
31975 this.el.addClass("x-dlg-closable");
31976 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31977 this.close.on("click", this.closeClick, this);
31978 this.close.addClassOnOver("x-dlg-close-over");
31980 if(this.collapsible !== false){
31981 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31982 this.collapseBtn.on("click", this.collapseClick, this);
31983 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31984 this.header.on("dblclick", this.collapseClick, this);
31986 if(this.resizable !== false){
31987 this.el.addClass("x-dlg-resizable");
31988 this.resizer = new Roo.Resizable(el, {
31989 minWidth: this.minWidth || 80,
31990 minHeight:this.minHeight || 80,
31991 handles: this.resizeHandles || "all",
31994 this.resizer.on("beforeresize", this.beforeResize, this);
31995 this.resizer.on("resize", this.onResize, this);
31997 if(this.draggable !== false){
31998 el.addClass("x-dlg-draggable");
31999 if (!this.proxyDrag) {
32000 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32003 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32005 dd.setHandleElId(this.header.id);
32006 dd.endDrag = this.endMove.createDelegate(this);
32007 dd.startDrag = this.startMove.createDelegate(this);
32008 dd.onDrag = this.onDrag.createDelegate(this);
32013 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32014 this.mask.enableDisplayMode("block");
32016 this.el.addClass("x-dlg-modal");
32019 this.shadow = new Roo.Shadow({
32020 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32021 offset : this.shadowOffset
32024 this.shadowOffset = 0;
32026 if(Roo.useShims && this.shim !== false){
32027 this.shim = this.el.createShim();
32028 this.shim.hide = this.hideAction;
32036 if (this.buttons) {
32037 var bts= this.buttons;
32039 Roo.each(bts, function(b) {
32048 * Fires when a key is pressed
32049 * @param {Roo.BasicDialog} this
32050 * @param {Roo.EventObject} e
32055 * Fires when this dialog is moved by the user.
32056 * @param {Roo.BasicDialog} this
32057 * @param {Number} x The new page X
32058 * @param {Number} y The new page Y
32063 * Fires when this dialog is resized by the user.
32064 * @param {Roo.BasicDialog} this
32065 * @param {Number} width The new width
32066 * @param {Number} height The new height
32070 * @event beforehide
32071 * Fires before this dialog is hidden.
32072 * @param {Roo.BasicDialog} this
32074 "beforehide" : true,
32077 * Fires when this dialog is hidden.
32078 * @param {Roo.BasicDialog} this
32082 * @event beforeshow
32083 * Fires before this dialog is shown.
32084 * @param {Roo.BasicDialog} this
32086 "beforeshow" : true,
32089 * Fires when this dialog is shown.
32090 * @param {Roo.BasicDialog} this
32094 el.on("keydown", this.onKeyDown, this);
32095 el.on("mousedown", this.toFront, this);
32096 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32098 Roo.DialogManager.register(this);
32099 Roo.BasicDialog.superclass.constructor.call(this);
32102 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32103 shadowOffset: Roo.isIE ? 6 : 5,
32106 minButtonWidth: 75,
32107 defaultButton: null,
32108 buttonAlign: "right",
32113 * Sets the dialog title text
32114 * @param {String} text The title text to display
32115 * @return {Roo.BasicDialog} this
32117 setTitle : function(text){
32118 this.header.update(text);
32123 closeClick : function(){
32128 collapseClick : function(){
32129 this[this.collapsed ? "expand" : "collapse"]();
32133 * Collapses the dialog to its minimized state (only the title bar is visible).
32134 * Equivalent to the user clicking the collapse dialog button.
32136 collapse : function(){
32137 if(!this.collapsed){
32138 this.collapsed = true;
32139 this.el.addClass("x-dlg-collapsed");
32140 this.restoreHeight = this.el.getHeight();
32141 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32146 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32147 * clicking the expand dialog button.
32149 expand : function(){
32150 if(this.collapsed){
32151 this.collapsed = false;
32152 this.el.removeClass("x-dlg-collapsed");
32153 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32158 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32159 * @return {Roo.TabPanel} The tabs component
32161 initTabs : function(){
32162 var tabs = this.getTabs();
32163 while(tabs.getTab(0)){
32166 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32168 tabs.addTab(Roo.id(dom), dom.title);
32176 beforeResize : function(){
32177 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32181 onResize : function(){
32182 this.refreshSize();
32183 this.syncBodyHeight();
32184 this.adjustAssets();
32186 this.fireEvent("resize", this, this.size.width, this.size.height);
32190 onKeyDown : function(e){
32191 if(this.isVisible()){
32192 this.fireEvent("keydown", this, e);
32197 * Resizes the dialog.
32198 * @param {Number} width
32199 * @param {Number} height
32200 * @return {Roo.BasicDialog} this
32202 resizeTo : function(width, height){
32203 this.el.setSize(width, height);
32204 this.size = {width: width, height: height};
32205 this.syncBodyHeight();
32206 if(this.fixedcenter){
32209 if(this.isVisible()){
32210 this.constrainXY();
32211 this.adjustAssets();
32213 this.fireEvent("resize", this, width, height);
32219 * Resizes the dialog to fit the specified content size.
32220 * @param {Number} width
32221 * @param {Number} height
32222 * @return {Roo.BasicDialog} this
32224 setContentSize : function(w, h){
32225 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32226 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32227 //if(!this.el.isBorderBox()){
32228 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32229 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32232 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32233 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32235 this.resizeTo(w, h);
32240 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32241 * executed in response to a particular key being pressed while the dialog is active.
32242 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32243 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32244 * @param {Function} fn The function to call
32245 * @param {Object} scope (optional) The scope of the function
32246 * @return {Roo.BasicDialog} this
32248 addKeyListener : function(key, fn, scope){
32249 var keyCode, shift, ctrl, alt;
32250 if(typeof key == "object" && !(key instanceof Array)){
32251 keyCode = key["key"];
32252 shift = key["shift"];
32253 ctrl = key["ctrl"];
32258 var handler = function(dlg, e){
32259 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32260 var k = e.getKey();
32261 if(keyCode instanceof Array){
32262 for(var i = 0, len = keyCode.length; i < len; i++){
32263 if(keyCode[i] == k){
32264 fn.call(scope || window, dlg, k, e);
32270 fn.call(scope || window, dlg, k, e);
32275 this.on("keydown", handler);
32280 * Returns the TabPanel component (creates it if it doesn't exist).
32281 * Note: If you wish to simply check for the existence of tabs without creating them,
32282 * check for a null 'tabs' property.
32283 * @return {Roo.TabPanel} The tabs component
32285 getTabs : function(){
32287 this.el.addClass("x-dlg-auto-tabs");
32288 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32289 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32295 * Adds a button to the footer section of the dialog.
32296 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32297 * object or a valid Roo.DomHelper element config
32298 * @param {Function} handler The function called when the button is clicked
32299 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32300 * @return {Roo.Button} The new button
32302 addButton : function(config, handler, scope){
32303 var dh = Roo.DomHelper;
32305 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32307 if(!this.btnContainer){
32308 var tb = this.footer.createChild({
32310 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32311 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32313 this.btnContainer = tb.firstChild.firstChild.firstChild;
32318 minWidth: this.minButtonWidth,
32321 if(typeof config == "string"){
32322 bconfig.text = config;
32325 bconfig.dhconfig = config;
32327 Roo.apply(bconfig, config);
32331 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32332 bconfig.position = Math.max(0, bconfig.position);
32333 fc = this.btnContainer.childNodes[bconfig.position];
32336 var btn = new Roo.Button(
32338 this.btnContainer.insertBefore(document.createElement("td"),fc)
32339 : this.btnContainer.appendChild(document.createElement("td")),
32340 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32343 this.syncBodyHeight();
32346 * Array of all the buttons that have been added to this dialog via addButton
32351 this.buttons.push(btn);
32356 * Sets the default button to be focused when the dialog is displayed.
32357 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32358 * @return {Roo.BasicDialog} this
32360 setDefaultButton : function(btn){
32361 this.defaultButton = btn;
32366 getHeaderFooterHeight : function(safe){
32369 height += this.header.getHeight();
32372 var fm = this.footer.getMargins();
32373 height += (this.footer.getHeight()+fm.top+fm.bottom);
32375 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32376 height += this.centerBg.getPadding("tb");
32381 syncBodyHeight : function()
32383 var bd = this.body, // the text
32384 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32386 var height = this.size.height - this.getHeaderFooterHeight(false);
32387 bd.setHeight(height-bd.getMargins("tb"));
32388 var hh = this.header.getHeight();
32389 var h = this.size.height-hh;
32392 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32393 bw.setHeight(h-cb.getPadding("tb"));
32395 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32396 bd.setWidth(bw.getWidth(true));
32398 this.tabs.syncHeight();
32400 this.tabs.el.repaint();
32406 * Restores the previous state of the dialog if Roo.state is configured.
32407 * @return {Roo.BasicDialog} this
32409 restoreState : function(){
32410 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32411 if(box && box.width){
32412 this.xy = [box.x, box.y];
32413 this.resizeTo(box.width, box.height);
32419 beforeShow : function(){
32421 if(this.fixedcenter){
32422 this.xy = this.el.getCenterXY(true);
32425 Roo.get(document.body).addClass("x-body-masked");
32426 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32429 this.constrainXY();
32433 animShow : function(){
32434 var b = Roo.get(this.animateTarget).getBox();
32435 this.proxy.setSize(b.width, b.height);
32436 this.proxy.setLocation(b.x, b.y);
32438 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32439 true, .35, this.showEl.createDelegate(this));
32443 * Shows the dialog.
32444 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32445 * @return {Roo.BasicDialog} this
32447 show : function(animateTarget){
32448 if (this.fireEvent("beforeshow", this) === false){
32451 if(this.syncHeightBeforeShow){
32452 this.syncBodyHeight();
32453 }else if(this.firstShow){
32454 this.firstShow = false;
32455 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32457 this.animateTarget = animateTarget || this.animateTarget;
32458 if(!this.el.isVisible()){
32460 if(this.animateTarget && Roo.get(this.animateTarget)){
32470 showEl : function(){
32472 this.el.setXY(this.xy);
32474 this.adjustAssets(true);
32477 // IE peekaboo bug - fix found by Dave Fenwick
32481 this.fireEvent("show", this);
32485 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32486 * dialog itself will receive focus.
32488 focus : function(){
32489 if(this.defaultButton){
32490 this.defaultButton.focus();
32492 this.focusEl.focus();
32497 constrainXY : function(){
32498 if(this.constraintoviewport !== false){
32499 if(!this.viewSize){
32500 if(this.container){
32501 var s = this.container.getSize();
32502 this.viewSize = [s.width, s.height];
32504 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32507 var s = Roo.get(this.container||document).getScroll();
32509 var x = this.xy[0], y = this.xy[1];
32510 var w = this.size.width, h = this.size.height;
32511 var vw = this.viewSize[0], vh = this.viewSize[1];
32512 // only move it if it needs it
32514 // first validate right/bottom
32515 if(x + w > vw+s.left){
32519 if(y + h > vh+s.top){
32523 // then make sure top/left isn't negative
32535 if(this.isVisible()){
32536 this.el.setLocation(x, y);
32537 this.adjustAssets();
32544 onDrag : function(){
32545 if(!this.proxyDrag){
32546 this.xy = this.el.getXY();
32547 this.adjustAssets();
32552 adjustAssets : function(doShow){
32553 var x = this.xy[0], y = this.xy[1];
32554 var w = this.size.width, h = this.size.height;
32555 if(doShow === true){
32557 this.shadow.show(this.el);
32563 if(this.shadow && this.shadow.isVisible()){
32564 this.shadow.show(this.el);
32566 if(this.shim && this.shim.isVisible()){
32567 this.shim.setBounds(x, y, w, h);
32572 adjustViewport : function(w, h){
32574 w = Roo.lib.Dom.getViewWidth();
32575 h = Roo.lib.Dom.getViewHeight();
32578 this.viewSize = [w, h];
32579 if(this.modal && this.mask.isVisible()){
32580 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32581 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32583 if(this.isVisible()){
32584 this.constrainXY();
32589 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32590 * shadow, proxy, mask, etc.) Also removes all event listeners.
32591 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32593 destroy : function(removeEl){
32594 if(this.isVisible()){
32595 this.animateTarget = null;
32598 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32600 this.tabs.destroy(removeEl);
32613 for(var i = 0, len = this.buttons.length; i < len; i++){
32614 this.buttons[i].destroy();
32617 this.el.removeAllListeners();
32618 if(removeEl === true){
32619 this.el.update("");
32622 Roo.DialogManager.unregister(this);
32626 startMove : function(){
32627 if(this.proxyDrag){
32630 if(this.constraintoviewport !== false){
32631 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32636 endMove : function(){
32637 if(!this.proxyDrag){
32638 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32640 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32643 this.refreshSize();
32644 this.adjustAssets();
32646 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32650 * Brings this dialog to the front of any other visible dialogs
32651 * @return {Roo.BasicDialog} this
32653 toFront : function(){
32654 Roo.DialogManager.bringToFront(this);
32659 * Sends this dialog to the back (under) of any other visible dialogs
32660 * @return {Roo.BasicDialog} this
32662 toBack : function(){
32663 Roo.DialogManager.sendToBack(this);
32668 * Centers this dialog in the viewport
32669 * @return {Roo.BasicDialog} this
32671 center : function(){
32672 var xy = this.el.getCenterXY(true);
32673 this.moveTo(xy[0], xy[1]);
32678 * Moves the dialog's top-left corner to the specified point
32679 * @param {Number} x
32680 * @param {Number} y
32681 * @return {Roo.BasicDialog} this
32683 moveTo : function(x, y){
32685 if(this.isVisible()){
32686 this.el.setXY(this.xy);
32687 this.adjustAssets();
32693 * Aligns the dialog to the specified element
32694 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32695 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32696 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32697 * @return {Roo.BasicDialog} this
32699 alignTo : function(element, position, offsets){
32700 this.xy = this.el.getAlignToXY(element, position, offsets);
32701 if(this.isVisible()){
32702 this.el.setXY(this.xy);
32703 this.adjustAssets();
32709 * Anchors an element to another element and realigns it when the window is resized.
32710 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32711 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32712 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32713 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32714 * is a number, it is used as the buffer delay (defaults to 50ms).
32715 * @return {Roo.BasicDialog} this
32717 anchorTo : function(el, alignment, offsets, monitorScroll){
32718 var action = function(){
32719 this.alignTo(el, alignment, offsets);
32721 Roo.EventManager.onWindowResize(action, this);
32722 var tm = typeof monitorScroll;
32723 if(tm != 'undefined'){
32724 Roo.EventManager.on(window, 'scroll', action, this,
32725 {buffer: tm == 'number' ? monitorScroll : 50});
32732 * Returns true if the dialog is visible
32733 * @return {Boolean}
32735 isVisible : function(){
32736 return this.el.isVisible();
32740 animHide : function(callback){
32741 var b = Roo.get(this.animateTarget).getBox();
32743 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32745 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32746 this.hideEl.createDelegate(this, [callback]));
32750 * Hides the dialog.
32751 * @param {Function} callback (optional) Function to call when the dialog is hidden
32752 * @return {Roo.BasicDialog} this
32754 hide : function(callback){
32755 if (this.fireEvent("beforehide", this) === false){
32759 this.shadow.hide();
32764 // sometimes animateTarget seems to get set.. causing problems...
32765 // this just double checks..
32766 if(this.animateTarget && Roo.get(this.animateTarget)) {
32767 this.animHide(callback);
32770 this.hideEl(callback);
32776 hideEl : function(callback){
32780 Roo.get(document.body).removeClass("x-body-masked");
32782 this.fireEvent("hide", this);
32783 if(typeof callback == "function"){
32789 hideAction : function(){
32790 this.setLeft("-10000px");
32791 this.setTop("-10000px");
32792 this.setStyle("visibility", "hidden");
32796 refreshSize : function(){
32797 this.size = this.el.getSize();
32798 this.xy = this.el.getXY();
32799 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32803 // z-index is managed by the DialogManager and may be overwritten at any time
32804 setZIndex : function(index){
32806 this.mask.setStyle("z-index", index);
32809 this.shim.setStyle("z-index", ++index);
32812 this.shadow.setZIndex(++index);
32814 this.el.setStyle("z-index", ++index);
32816 this.proxy.setStyle("z-index", ++index);
32819 this.resizer.proxy.setStyle("z-index", ++index);
32822 this.lastZIndex = index;
32826 * Returns the element for this dialog
32827 * @return {Roo.Element} The underlying dialog Element
32829 getEl : function(){
32835 * @class Roo.DialogManager
32836 * Provides global access to BasicDialogs that have been created and
32837 * support for z-indexing (layering) multiple open dialogs.
32839 Roo.DialogManager = function(){
32841 var accessList = [];
32845 var sortDialogs = function(d1, d2){
32846 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32850 var orderDialogs = function(){
32851 accessList.sort(sortDialogs);
32852 var seed = Roo.DialogManager.zseed;
32853 for(var i = 0, len = accessList.length; i < len; i++){
32854 var dlg = accessList[i];
32856 dlg.setZIndex(seed + (i*10));
32863 * The starting z-index for BasicDialogs (defaults to 9000)
32864 * @type Number The z-index value
32869 register : function(dlg){
32870 list[dlg.id] = dlg;
32871 accessList.push(dlg);
32875 unregister : function(dlg){
32876 delete list[dlg.id];
32879 if(!accessList.indexOf){
32880 for( i = 0, len = accessList.length; i < len; i++){
32881 if(accessList[i] == dlg){
32882 accessList.splice(i, 1);
32887 i = accessList.indexOf(dlg);
32889 accessList.splice(i, 1);
32895 * Gets a registered dialog by id
32896 * @param {String/Object} id The id of the dialog or a dialog
32897 * @return {Roo.BasicDialog} this
32899 get : function(id){
32900 return typeof id == "object" ? id : list[id];
32904 * Brings the specified dialog to the front
32905 * @param {String/Object} dlg The id of the dialog or a dialog
32906 * @return {Roo.BasicDialog} this
32908 bringToFront : function(dlg){
32909 dlg = this.get(dlg);
32912 dlg._lastAccess = new Date().getTime();
32919 * Sends the specified dialog to the back
32920 * @param {String/Object} dlg The id of the dialog or a dialog
32921 * @return {Roo.BasicDialog} this
32923 sendToBack : function(dlg){
32924 dlg = this.get(dlg);
32925 dlg._lastAccess = -(new Date().getTime());
32931 * Hides all dialogs
32933 hideAll : function(){
32934 for(var id in list){
32935 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32944 * @class Roo.LayoutDialog
32945 * @extends Roo.BasicDialog
32946 * Dialog which provides adjustments for working with a layout in a Dialog.
32947 * Add your necessary layout config options to the dialog's config.<br>
32948 * Example usage (including a nested layout):
32951 dialog = new Roo.LayoutDialog("download-dlg", {
32960 // layout config merges with the dialog config
32962 tabPosition: "top",
32963 alwaysShowTabs: true
32966 dialog.addKeyListener(27, dialog.hide, dialog);
32967 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32968 dialog.addButton("Build It!", this.getDownload, this);
32970 // we can even add nested layouts
32971 var innerLayout = new Roo.BorderLayout("dl-inner", {
32981 innerLayout.beginUpdate();
32982 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32983 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32984 innerLayout.endUpdate(true);
32986 var layout = dialog.getLayout();
32987 layout.beginUpdate();
32988 layout.add("center", new Roo.ContentPanel("standard-panel",
32989 {title: "Download the Source", fitToFrame:true}));
32990 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32991 {title: "Build your own roo.js"}));
32992 layout.getRegion("center").showPanel(sp);
32993 layout.endUpdate();
32997 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32998 * @param {Object} config configuration options
33000 Roo.LayoutDialog = function(el, cfg){
33003 if (typeof(cfg) == 'undefined') {
33004 config = Roo.apply({}, el);
33005 // not sure why we use documentElement here.. - it should always be body.
33006 // IE7 borks horribly if we use documentElement.
33007 // webkit also does not like documentElement - it creates a body element...
33008 el = Roo.get( document.body || document.documentElement ).createChild();
33009 //config.autoCreate = true;
33013 config.autoTabs = false;
33014 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33015 this.body.setStyle({overflow:"hidden", position:"relative"});
33016 this.layout = new Roo.BorderLayout(this.body.dom, config);
33017 this.layout.monitorWindowResize = false;
33018 this.el.addClass("x-dlg-auto-layout");
33019 // fix case when center region overwrites center function
33020 this.center = Roo.BasicDialog.prototype.center;
33021 this.on("show", this.layout.layout, this.layout, true);
33022 if (config.items) {
33023 var xitems = config.items;
33024 delete config.items;
33025 Roo.each(xitems, this.addxtype, this);
33030 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33032 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33035 endUpdate : function(){
33036 this.layout.endUpdate();
33040 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33043 beginUpdate : function(){
33044 this.layout.beginUpdate();
33048 * Get the BorderLayout for this dialog
33049 * @return {Roo.BorderLayout}
33051 getLayout : function(){
33052 return this.layout;
33055 showEl : function(){
33056 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33058 this.layout.layout();
33063 // Use the syncHeightBeforeShow config option to control this automatically
33064 syncBodyHeight : function(){
33065 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33066 if(this.layout){this.layout.layout();}
33070 * Add an xtype element (actually adds to the layout.)
33071 * @return {Object} xdata xtype object data.
33074 addxtype : function(c) {
33075 return this.layout.addxtype(c);
33079 * Ext JS Library 1.1.1
33080 * Copyright(c) 2006-2007, Ext JS, LLC.
33082 * Originally Released Under LGPL - original licence link has changed is not relivant.
33085 * <script type="text/javascript">
33089 * @class Roo.MessageBox
33090 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33094 Roo.Msg.alert('Status', 'Changes saved successfully.');
33096 // Prompt for user data:
33097 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33099 // process text value...
33103 // Show a dialog using config options:
33105 title:'Save Changes?',
33106 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33107 buttons: Roo.Msg.YESNOCANCEL,
33114 Roo.MessageBox = function(){
33115 var dlg, opt, mask, waitTimer;
33116 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33117 var buttons, activeTextEl, bwidth;
33120 var handleButton = function(button){
33122 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33126 var handleHide = function(){
33127 if(opt && opt.cls){
33128 dlg.el.removeClass(opt.cls);
33131 Roo.TaskMgr.stop(waitTimer);
33137 var updateButtons = function(b){
33140 buttons["ok"].hide();
33141 buttons["cancel"].hide();
33142 buttons["yes"].hide();
33143 buttons["no"].hide();
33144 dlg.footer.dom.style.display = 'none';
33147 dlg.footer.dom.style.display = '';
33148 for(var k in buttons){
33149 if(typeof buttons[k] != "function"){
33152 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33153 width += buttons[k].el.getWidth()+15;
33163 var handleEsc = function(d, k, e){
33164 if(opt && opt.closable !== false){
33174 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33175 * @return {Roo.BasicDialog} The BasicDialog element
33177 getDialog : function(){
33179 dlg = new Roo.BasicDialog("x-msg-box", {
33184 constraintoviewport:false,
33186 collapsible : false,
33189 width:400, height:100,
33190 buttonAlign:"center",
33191 closeClick : function(){
33192 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33193 handleButton("no");
33195 handleButton("cancel");
33199 dlg.on("hide", handleHide);
33201 dlg.addKeyListener(27, handleEsc);
33203 var bt = this.buttonText;
33204 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33205 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33206 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33207 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33208 bodyEl = dlg.body.createChild({
33210 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>'
33212 msgEl = bodyEl.dom.firstChild;
33213 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33214 textboxEl.enableDisplayMode();
33215 textboxEl.addKeyListener([10,13], function(){
33216 if(dlg.isVisible() && opt && opt.buttons){
33217 if(opt.buttons.ok){
33218 handleButton("ok");
33219 }else if(opt.buttons.yes){
33220 handleButton("yes");
33224 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33225 textareaEl.enableDisplayMode();
33226 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33227 progressEl.enableDisplayMode();
33228 var pf = progressEl.dom.firstChild;
33230 pp = Roo.get(pf.firstChild);
33231 pp.setHeight(pf.offsetHeight);
33239 * Updates the message box body text
33240 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33241 * the XHTML-compliant non-breaking space character '&#160;')
33242 * @return {Roo.MessageBox} This message box
33244 updateText : function(text){
33245 if(!dlg.isVisible() && !opt.width){
33246 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33248 msgEl.innerHTML = text || ' ';
33250 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33251 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33253 Math.min(opt.width || cw , this.maxWidth),
33254 Math.max(opt.minWidth || this.minWidth, bwidth)
33257 activeTextEl.setWidth(w);
33259 if(dlg.isVisible()){
33260 dlg.fixedcenter = false;
33262 // to big, make it scroll. = But as usual stupid IE does not support
33265 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33266 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33267 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33269 bodyEl.dom.style.height = '';
33270 bodyEl.dom.style.overflowY = '';
33273 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33275 bodyEl.dom.style.overflowX = '';
33278 dlg.setContentSize(w, bodyEl.getHeight());
33279 if(dlg.isVisible()){
33280 dlg.fixedcenter = true;
33286 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33287 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33288 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33289 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33290 * @return {Roo.MessageBox} This message box
33292 updateProgress : function(value, text){
33294 this.updateText(text);
33296 if (pp) { // weird bug on my firefox - for some reason this is not defined
33297 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33303 * Returns true if the message box is currently displayed
33304 * @return {Boolean} True if the message box is visible, else false
33306 isVisible : function(){
33307 return dlg && dlg.isVisible();
33311 * Hides the message box if it is displayed
33314 if(this.isVisible()){
33320 * Displays a new message box, or reinitializes an existing message box, based on the config options
33321 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33322 * The following config object properties are supported:
33324 Property Type Description
33325 ---------- --------------- ------------------------------------------------------------------------------------
33326 animEl String/Element An id or Element from which the message box should animate as it opens and
33327 closes (defaults to undefined)
33328 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33329 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33330 closable Boolean False to hide the top-right close button (defaults to true). Note that
33331 progress and wait dialogs will ignore this property and always hide the
33332 close button as they can only be closed programmatically.
33333 cls String A custom CSS class to apply to the message box element
33334 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33335 displayed (defaults to 75)
33336 fn Function A callback function to execute after closing the dialog. The arguments to the
33337 function will be btn (the name of the button that was clicked, if applicable,
33338 e.g. "ok"), and text (the value of the active text field, if applicable).
33339 Progress and wait dialogs will ignore this option since they do not respond to
33340 user actions and can only be closed programmatically, so any required function
33341 should be called by the same code after it closes the dialog.
33342 icon String A CSS class that provides a background image to be used as an icon for
33343 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33344 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33345 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33346 modal Boolean False to allow user interaction with the page while the message box is
33347 displayed (defaults to true)
33348 msg String A string that will replace the existing message box body text (defaults
33349 to the XHTML-compliant non-breaking space character ' ')
33350 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33351 progress Boolean True to display a progress bar (defaults to false)
33352 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33353 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33354 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33355 title String The title text
33356 value String The string value to set into the active textbox element if displayed
33357 wait Boolean True to display a progress bar (defaults to false)
33358 width Number The width of the dialog in pixels
33365 msg: 'Please enter your address:',
33367 buttons: Roo.MessageBox.OKCANCEL,
33370 animEl: 'addAddressBtn'
33373 * @param {Object} config Configuration options
33374 * @return {Roo.MessageBox} This message box
33376 show : function(options)
33379 // this causes nightmares if you show one dialog after another
33380 // especially on callbacks..
33382 if(this.isVisible()){
33385 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33386 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33387 Roo.log("New Dialog Message:" + options.msg )
33388 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33389 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33392 var d = this.getDialog();
33394 d.setTitle(opt.title || " ");
33395 d.close.setDisplayed(opt.closable !== false);
33396 activeTextEl = textboxEl;
33397 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33402 textareaEl.setHeight(typeof opt.multiline == "number" ?
33403 opt.multiline : this.defaultTextHeight);
33404 activeTextEl = textareaEl;
33413 progressEl.setDisplayed(opt.progress === true);
33414 this.updateProgress(0);
33415 activeTextEl.dom.value = opt.value || "";
33417 dlg.setDefaultButton(activeTextEl);
33419 var bs = opt.buttons;
33422 db = buttons["ok"];
33423 }else if(bs && bs.yes){
33424 db = buttons["yes"];
33426 dlg.setDefaultButton(db);
33428 bwidth = updateButtons(opt.buttons);
33429 this.updateText(opt.msg);
33431 d.el.addClass(opt.cls);
33433 d.proxyDrag = opt.proxyDrag === true;
33434 d.modal = opt.modal !== false;
33435 d.mask = opt.modal !== false ? mask : false;
33436 if(!d.isVisible()){
33437 // force it to the end of the z-index stack so it gets a cursor in FF
33438 document.body.appendChild(dlg.el.dom);
33439 d.animateTarget = null;
33440 d.show(options.animEl);
33446 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33447 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33448 * and closing the message box when the process is complete.
33449 * @param {String} title The title bar text
33450 * @param {String} msg The message box body text
33451 * @return {Roo.MessageBox} This message box
33453 progress : function(title, msg){
33460 minWidth: this.minProgressWidth,
33467 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33468 * If a callback function is passed it will be called after the user clicks the button, and the
33469 * id of the button that was clicked will be passed as the only parameter to the callback
33470 * (could also be the top-right close button).
33471 * @param {String} title The title bar text
33472 * @param {String} msg The message box body text
33473 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33474 * @param {Object} scope (optional) The scope of the callback function
33475 * @return {Roo.MessageBox} This message box
33477 alert : function(title, msg, fn, scope){
33490 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33491 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33492 * You are responsible for closing the message box when the process is complete.
33493 * @param {String} msg The message box body text
33494 * @param {String} title (optional) The title bar text
33495 * @return {Roo.MessageBox} This message box
33497 wait : function(msg, title){
33508 waitTimer = Roo.TaskMgr.start({
33510 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33518 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33519 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33520 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33521 * @param {String} title The title bar text
33522 * @param {String} msg The message box body text
33523 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33524 * @param {Object} scope (optional) The scope of the callback function
33525 * @return {Roo.MessageBox} This message box
33527 confirm : function(title, msg, fn, scope){
33531 buttons: this.YESNO,
33540 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33541 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33542 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33543 * (could also be the top-right close button) and the text that was entered will be passed as the two
33544 * parameters to the callback.
33545 * @param {String} title The title bar text
33546 * @param {String} msg The message box body text
33547 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33548 * @param {Object} scope (optional) The scope of the callback function
33549 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33550 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33551 * @return {Roo.MessageBox} This message box
33553 prompt : function(title, msg, fn, scope, multiline){
33557 buttons: this.OKCANCEL,
33562 multiline: multiline,
33569 * Button config that displays a single OK button
33574 * Button config that displays Yes and No buttons
33577 YESNO : {yes:true, no:true},
33579 * Button config that displays OK and Cancel buttons
33582 OKCANCEL : {ok:true, cancel:true},
33584 * Button config that displays Yes, No and Cancel buttons
33587 YESNOCANCEL : {yes:true, no:true, cancel:true},
33590 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33593 defaultTextHeight : 75,
33595 * The maximum width in pixels of the message box (defaults to 600)
33600 * The minimum width in pixels of the message box (defaults to 100)
33605 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33606 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33609 minProgressWidth : 250,
33611 * An object containing the default button text strings that can be overriden for localized language support.
33612 * Supported properties are: ok, cancel, yes and no.
33613 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33626 * Shorthand for {@link Roo.MessageBox}
33628 Roo.Msg = Roo.MessageBox;/*
33630 * Ext JS Library 1.1.1
33631 * Copyright(c) 2006-2007, Ext JS, LLC.
33633 * Originally Released Under LGPL - original licence link has changed is not relivant.
33636 * <script type="text/javascript">
33639 * @class Roo.QuickTips
33640 * Provides attractive and customizable tooltips for any element.
33643 Roo.QuickTips = function(){
33644 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33645 var ce, bd, xy, dd;
33646 var visible = false, disabled = true, inited = false;
33647 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33649 var onOver = function(e){
33653 var t = e.getTarget();
33654 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33657 if(ce && t == ce.el){
33658 clearTimeout(hideProc);
33661 if(t && tagEls[t.id]){
33662 tagEls[t.id].el = t;
33663 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33666 var ttp, et = Roo.fly(t);
33667 var ns = cfg.namespace;
33668 if(tm.interceptTitles && t.title){
33671 t.removeAttribute("title");
33672 e.preventDefault();
33674 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33677 showProc = show.defer(tm.showDelay, tm, [{
33679 text: ttp.replace(/\\n/g,'<br/>'),
33680 width: et.getAttributeNS(ns, cfg.width),
33681 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33682 title: et.getAttributeNS(ns, cfg.title),
33683 cls: et.getAttributeNS(ns, cfg.cls)
33688 var onOut = function(e){
33689 clearTimeout(showProc);
33690 var t = e.getTarget();
33691 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33692 hideProc = setTimeout(hide, tm.hideDelay);
33696 var onMove = function(e){
33702 if(tm.trackMouse && ce){
33707 var onDown = function(e){
33708 clearTimeout(showProc);
33709 clearTimeout(hideProc);
33711 if(tm.hideOnClick){
33714 tm.enable.defer(100, tm);
33719 var getPad = function(){
33720 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33723 var show = function(o){
33727 clearTimeout(dismissProc);
33729 if(removeCls){ // in case manually hidden
33730 el.removeClass(removeCls);
33734 el.addClass(ce.cls);
33735 removeCls = ce.cls;
33738 tipTitle.update(ce.title);
33741 tipTitle.update('');
33744 el.dom.style.width = tm.maxWidth+'px';
33745 //tipBody.dom.style.width = '';
33746 tipBodyText.update(o.text);
33747 var p = getPad(), w = ce.width;
33749 var td = tipBodyText.dom;
33750 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33751 if(aw > tm.maxWidth){
33753 }else if(aw < tm.minWidth){
33759 //tipBody.setWidth(w);
33760 el.setWidth(parseInt(w, 10) + p);
33761 if(ce.autoHide === false){
33762 close.setDisplayed(true);
33767 close.setDisplayed(false);
33773 el.avoidY = xy[1]-18;
33778 el.setStyle("visibility", "visible");
33779 el.fadeIn({callback: afterShow});
33785 var afterShow = function(){
33789 if(tm.autoDismiss && ce.autoHide !== false){
33790 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33795 var hide = function(noanim){
33796 clearTimeout(dismissProc);
33797 clearTimeout(hideProc);
33799 if(el.isVisible()){
33801 if(noanim !== true && tm.animate){
33802 el.fadeOut({callback: afterHide});
33809 var afterHide = function(){
33812 el.removeClass(removeCls);
33819 * @cfg {Number} minWidth
33820 * The minimum width of the quick tip (defaults to 40)
33824 * @cfg {Number} maxWidth
33825 * The maximum width of the quick tip (defaults to 300)
33829 * @cfg {Boolean} interceptTitles
33830 * True to automatically use the element's DOM title value if available (defaults to false)
33832 interceptTitles : false,
33834 * @cfg {Boolean} trackMouse
33835 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33837 trackMouse : false,
33839 * @cfg {Boolean} hideOnClick
33840 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33842 hideOnClick : true,
33844 * @cfg {Number} showDelay
33845 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33849 * @cfg {Number} hideDelay
33850 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33854 * @cfg {Boolean} autoHide
33855 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33856 * Used in conjunction with hideDelay.
33861 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33862 * (defaults to true). Used in conjunction with autoDismissDelay.
33864 autoDismiss : true,
33867 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33869 autoDismissDelay : 5000,
33871 * @cfg {Boolean} animate
33872 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33877 * @cfg {String} title
33878 * Title text to display (defaults to ''). This can be any valid HTML markup.
33882 * @cfg {String} text
33883 * Body text to display (defaults to ''). This can be any valid HTML markup.
33887 * @cfg {String} cls
33888 * A CSS class to apply to the base quick tip element (defaults to '').
33892 * @cfg {Number} width
33893 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33894 * minWidth or maxWidth.
33899 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33900 * or display QuickTips in a page.
33903 tm = Roo.QuickTips;
33904 cfg = tm.tagConfig;
33906 if(!Roo.isReady){ // allow calling of init() before onReady
33907 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33910 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33911 el.fxDefaults = {stopFx: true};
33912 // maximum custom styling
33913 //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>');
33914 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>');
33915 tipTitle = el.child('h3');
33916 tipTitle.enableDisplayMode("block");
33917 tipBody = el.child('div.x-tip-bd');
33918 tipBodyText = el.child('div.x-tip-bd-inner');
33919 //bdLeft = el.child('div.x-tip-bd-left');
33920 //bdRight = el.child('div.x-tip-bd-right');
33921 close = el.child('div.x-tip-close');
33922 close.enableDisplayMode("block");
33923 close.on("click", hide);
33924 var d = Roo.get(document);
33925 d.on("mousedown", onDown);
33926 d.on("mouseover", onOver);
33927 d.on("mouseout", onOut);
33928 d.on("mousemove", onMove);
33929 esc = d.addKeyListener(27, hide);
33932 dd = el.initDD("default", null, {
33933 onDrag : function(){
33937 dd.setHandleElId(tipTitle.id);
33946 * Configures a new quick tip instance and assigns it to a target element. The following config options
33949 Property Type Description
33950 ---------- --------------------- ------------------------------------------------------------------------
33951 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33953 * @param {Object} config The config object
33955 register : function(config){
33956 var cs = config instanceof Array ? config : arguments;
33957 for(var i = 0, len = cs.length; i < len; i++) {
33959 var target = c.target;
33961 if(target instanceof Array){
33962 for(var j = 0, jlen = target.length; j < jlen; j++){
33963 tagEls[target[j]] = c;
33966 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33973 * Removes this quick tip from its element and destroys it.
33974 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33976 unregister : function(el){
33977 delete tagEls[Roo.id(el)];
33981 * Enable this quick tip.
33983 enable : function(){
33984 if(inited && disabled){
33986 if(locks.length < 1){
33993 * Disable this quick tip.
33995 disable : function(){
33997 clearTimeout(showProc);
33998 clearTimeout(hideProc);
33999 clearTimeout(dismissProc);
34007 * Returns true if the quick tip is enabled, else false.
34009 isEnabled : function(){
34015 namespace : "roo", // was ext?? this may break..
34016 alt_namespace : "ext",
34017 attribute : "qtip",
34027 // backwards compat
34028 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34030 * Ext JS Library 1.1.1
34031 * Copyright(c) 2006-2007, Ext JS, LLC.
34033 * Originally Released Under LGPL - original licence link has changed is not relivant.
34036 * <script type="text/javascript">
34041 * @class Roo.tree.TreePanel
34042 * @extends Roo.data.Tree
34044 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34045 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34046 * @cfg {Boolean} enableDD true to enable drag and drop
34047 * @cfg {Boolean} enableDrag true to enable just drag
34048 * @cfg {Boolean} enableDrop true to enable just drop
34049 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34050 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34051 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34052 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34053 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34054 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34055 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34056 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34057 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34058 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34059 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34060 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34061 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34062 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34063 * @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>
34064 * @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>
34067 * @param {String/HTMLElement/Element} el The container element
34068 * @param {Object} config
34070 Roo.tree.TreePanel = function(el, config){
34072 var loader = false;
34074 root = config.root;
34075 delete config.root;
34077 if (config.loader) {
34078 loader = config.loader;
34079 delete config.loader;
34082 Roo.apply(this, config);
34083 Roo.tree.TreePanel.superclass.constructor.call(this);
34084 this.el = Roo.get(el);
34085 this.el.addClass('x-tree');
34086 //console.log(root);
34088 this.setRootNode( Roo.factory(root, Roo.tree));
34091 this.loader = Roo.factory(loader, Roo.tree);
34094 * Read-only. The id of the container element becomes this TreePanel's id.
34096 this.id = this.el.id;
34099 * @event beforeload
34100 * Fires before a node is loaded, return false to cancel
34101 * @param {Node} node The node being loaded
34103 "beforeload" : true,
34106 * Fires when a node is loaded
34107 * @param {Node} node The node that was loaded
34111 * @event textchange
34112 * Fires when the text for a node is changed
34113 * @param {Node} node The node
34114 * @param {String} text The new text
34115 * @param {String} oldText The old text
34117 "textchange" : true,
34119 * @event beforeexpand
34120 * Fires before a node is expanded, return false to cancel.
34121 * @param {Node} node The node
34122 * @param {Boolean} deep
34123 * @param {Boolean} anim
34125 "beforeexpand" : true,
34127 * @event beforecollapse
34128 * Fires before a node is collapsed, return false to cancel.
34129 * @param {Node} node The node
34130 * @param {Boolean} deep
34131 * @param {Boolean} anim
34133 "beforecollapse" : true,
34136 * Fires when a node is expanded
34137 * @param {Node} node The node
34141 * @event disabledchange
34142 * Fires when the disabled status of a node changes
34143 * @param {Node} node The node
34144 * @param {Boolean} disabled
34146 "disabledchange" : true,
34149 * Fires when a node is collapsed
34150 * @param {Node} node The node
34154 * @event beforeclick
34155 * Fires before click processing on a node. Return false to cancel the default action.
34156 * @param {Node} node The node
34157 * @param {Roo.EventObject} e The event object
34159 "beforeclick":true,
34161 * @event checkchange
34162 * Fires when a node with a checkbox's checked property changes
34163 * @param {Node} this This node
34164 * @param {Boolean} checked
34166 "checkchange":true,
34169 * Fires when a node is clicked
34170 * @param {Node} node The node
34171 * @param {Roo.EventObject} e The event object
34176 * Fires when a node is double clicked
34177 * @param {Node} node The node
34178 * @param {Roo.EventObject} e The event object
34182 * @event contextmenu
34183 * Fires when a node is right clicked
34184 * @param {Node} node The node
34185 * @param {Roo.EventObject} e The event object
34187 "contextmenu":true,
34189 * @event beforechildrenrendered
34190 * Fires right before the child nodes for a node are rendered
34191 * @param {Node} node The node
34193 "beforechildrenrendered":true,
34196 * Fires when a node starts being dragged
34197 * @param {Roo.tree.TreePanel} this
34198 * @param {Roo.tree.TreeNode} node
34199 * @param {event} e The raw browser event
34201 "startdrag" : true,
34204 * Fires when a drag operation is complete
34205 * @param {Roo.tree.TreePanel} this
34206 * @param {Roo.tree.TreeNode} node
34207 * @param {event} e The raw browser event
34212 * Fires when a dragged node is dropped on a valid DD target
34213 * @param {Roo.tree.TreePanel} this
34214 * @param {Roo.tree.TreeNode} node
34215 * @param {DD} dd The dd it was dropped on
34216 * @param {event} e The raw browser event
34220 * @event beforenodedrop
34221 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34222 * passed to handlers has the following properties:<br />
34223 * <ul style="padding:5px;padding-left:16px;">
34224 * <li>tree - The TreePanel</li>
34225 * <li>target - The node being targeted for the drop</li>
34226 * <li>data - The drag data from the drag source</li>
34227 * <li>point - The point of the drop - append, above or below</li>
34228 * <li>source - The drag source</li>
34229 * <li>rawEvent - Raw mouse event</li>
34230 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34231 * to be inserted by setting them on this object.</li>
34232 * <li>cancel - Set this to true to cancel the drop.</li>
34234 * @param {Object} dropEvent
34236 "beforenodedrop" : true,
34239 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34240 * passed to handlers has the following properties:<br />
34241 * <ul style="padding:5px;padding-left:16px;">
34242 * <li>tree - The TreePanel</li>
34243 * <li>target - The node being targeted for the drop</li>
34244 * <li>data - The drag data from the drag source</li>
34245 * <li>point - The point of the drop - append, above or below</li>
34246 * <li>source - The drag source</li>
34247 * <li>rawEvent - Raw mouse event</li>
34248 * <li>dropNode - Dropped node(s).</li>
34250 * @param {Object} dropEvent
34254 * @event nodedragover
34255 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34256 * passed to handlers has the following properties:<br />
34257 * <ul style="padding:5px;padding-left:16px;">
34258 * <li>tree - The TreePanel</li>
34259 * <li>target - The node being targeted for the drop</li>
34260 * <li>data - The drag data from the drag source</li>
34261 * <li>point - The point of the drop - append, above or below</li>
34262 * <li>source - The drag source</li>
34263 * <li>rawEvent - Raw mouse event</li>
34264 * <li>dropNode - Drop node(s) provided by the source.</li>
34265 * <li>cancel - Set this to true to signal drop not allowed.</li>
34267 * @param {Object} dragOverEvent
34269 "nodedragover" : true
34272 if(this.singleExpand){
34273 this.on("beforeexpand", this.restrictExpand, this);
34276 this.editor.tree = this;
34277 this.editor = Roo.factory(this.editor, Roo.tree);
34280 if (this.selModel) {
34281 this.selModel = Roo.factory(this.selModel, Roo.tree);
34285 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34286 rootVisible : true,
34287 animate: Roo.enableFx,
34290 hlDrop : Roo.enableFx,
34294 rendererTip: false,
34296 restrictExpand : function(node){
34297 var p = node.parentNode;
34299 if(p.expandedChild && p.expandedChild.parentNode == p){
34300 p.expandedChild.collapse();
34302 p.expandedChild = node;
34306 // private override
34307 setRootNode : function(node){
34308 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34309 if(!this.rootVisible){
34310 node.ui = new Roo.tree.RootTreeNodeUI(node);
34316 * Returns the container element for this TreePanel
34318 getEl : function(){
34323 * Returns the default TreeLoader for this TreePanel
34325 getLoader : function(){
34326 return this.loader;
34332 expandAll : function(){
34333 this.root.expand(true);
34337 * Collapse all nodes
34339 collapseAll : function(){
34340 this.root.collapse(true);
34344 * Returns the selection model used by this TreePanel
34346 getSelectionModel : function(){
34347 if(!this.selModel){
34348 this.selModel = new Roo.tree.DefaultSelectionModel();
34350 return this.selModel;
34354 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34355 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34356 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34359 getChecked : function(a, startNode){
34360 startNode = startNode || this.root;
34362 var f = function(){
34363 if(this.attributes.checked){
34364 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34367 startNode.cascade(f);
34372 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34373 * @param {String} path
34374 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34375 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34376 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34378 expandPath : function(path, attr, callback){
34379 attr = attr || "id";
34380 var keys = path.split(this.pathSeparator);
34381 var curNode = this.root;
34382 if(curNode.attributes[attr] != keys[1]){ // invalid root
34384 callback(false, null);
34389 var f = function(){
34390 if(++index == keys.length){
34392 callback(true, curNode);
34396 var c = curNode.findChild(attr, keys[index]);
34399 callback(false, curNode);
34404 c.expand(false, false, f);
34406 curNode.expand(false, false, f);
34410 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34411 * @param {String} path
34412 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34413 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34414 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34416 selectPath : function(path, attr, callback){
34417 attr = attr || "id";
34418 var keys = path.split(this.pathSeparator);
34419 var v = keys.pop();
34420 if(keys.length > 0){
34421 var f = function(success, node){
34422 if(success && node){
34423 var n = node.findChild(attr, v);
34429 }else if(callback){
34430 callback(false, n);
34434 callback(false, n);
34438 this.expandPath(keys.join(this.pathSeparator), attr, f);
34440 this.root.select();
34442 callback(true, this.root);
34447 getTreeEl : function(){
34452 * Trigger rendering of this TreePanel
34454 render : function(){
34455 if (this.innerCt) {
34456 return this; // stop it rendering more than once!!
34459 this.innerCt = this.el.createChild({tag:"ul",
34460 cls:"x-tree-root-ct " +
34461 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34463 if(this.containerScroll){
34464 Roo.dd.ScrollManager.register(this.el);
34466 if((this.enableDD || this.enableDrop) && !this.dropZone){
34468 * The dropZone used by this tree if drop is enabled
34469 * @type Roo.tree.TreeDropZone
34471 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34472 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34475 if((this.enableDD || this.enableDrag) && !this.dragZone){
34477 * The dragZone used by this tree if drag is enabled
34478 * @type Roo.tree.TreeDragZone
34480 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34481 ddGroup: this.ddGroup || "TreeDD",
34482 scroll: this.ddScroll
34485 this.getSelectionModel().init(this);
34487 Roo.log("ROOT not set in tree");
34490 this.root.render();
34491 if(!this.rootVisible){
34492 this.root.renderChildren();
34498 * Ext JS Library 1.1.1
34499 * Copyright(c) 2006-2007, Ext JS, LLC.
34501 * Originally Released Under LGPL - original licence link has changed is not relivant.
34504 * <script type="text/javascript">
34509 * @class Roo.tree.DefaultSelectionModel
34510 * @extends Roo.util.Observable
34511 * The default single selection for a TreePanel.
34512 * @param {Object} cfg Configuration
34514 Roo.tree.DefaultSelectionModel = function(cfg){
34515 this.selNode = null;
34521 * @event selectionchange
34522 * Fires when the selected node changes
34523 * @param {DefaultSelectionModel} this
34524 * @param {TreeNode} node the new selection
34526 "selectionchange" : true,
34529 * @event beforeselect
34530 * Fires before the selected node changes, return false to cancel the change
34531 * @param {DefaultSelectionModel} this
34532 * @param {TreeNode} node the new selection
34533 * @param {TreeNode} node the old selection
34535 "beforeselect" : true
34538 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34541 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34542 init : function(tree){
34544 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34545 tree.on("click", this.onNodeClick, this);
34548 onNodeClick : function(node, e){
34549 if (e.ctrlKey && this.selNode == node) {
34550 this.unselect(node);
34558 * @param {TreeNode} node The node to select
34559 * @return {TreeNode} The selected node
34561 select : function(node){
34562 var last = this.selNode;
34563 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34565 last.ui.onSelectedChange(false);
34567 this.selNode = node;
34568 node.ui.onSelectedChange(true);
34569 this.fireEvent("selectionchange", this, node, last);
34576 * @param {TreeNode} node The node to unselect
34578 unselect : function(node){
34579 if(this.selNode == node){
34580 this.clearSelections();
34585 * Clear all selections
34587 clearSelections : function(){
34588 var n = this.selNode;
34590 n.ui.onSelectedChange(false);
34591 this.selNode = null;
34592 this.fireEvent("selectionchange", this, null);
34598 * Get the selected node
34599 * @return {TreeNode} The selected node
34601 getSelectedNode : function(){
34602 return this.selNode;
34606 * Returns true if the node is selected
34607 * @param {TreeNode} node The node to check
34608 * @return {Boolean}
34610 isSelected : function(node){
34611 return this.selNode == node;
34615 * Selects the node above the selected node in the tree, intelligently walking the nodes
34616 * @return TreeNode The new selection
34618 selectPrevious : function(){
34619 var s = this.selNode || this.lastSelNode;
34623 var ps = s.previousSibling;
34625 if(!ps.isExpanded() || ps.childNodes.length < 1){
34626 return this.select(ps);
34628 var lc = ps.lastChild;
34629 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34632 return this.select(lc);
34634 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34635 return this.select(s.parentNode);
34641 * Selects the node above the selected node in the tree, intelligently walking the nodes
34642 * @return TreeNode The new selection
34644 selectNext : function(){
34645 var s = this.selNode || this.lastSelNode;
34649 if(s.firstChild && s.isExpanded()){
34650 return this.select(s.firstChild);
34651 }else if(s.nextSibling){
34652 return this.select(s.nextSibling);
34653 }else if(s.parentNode){
34655 s.parentNode.bubble(function(){
34656 if(this.nextSibling){
34657 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34666 onKeyDown : function(e){
34667 var s = this.selNode || this.lastSelNode;
34668 // undesirable, but required
34673 var k = e.getKey();
34681 this.selectPrevious();
34684 e.preventDefault();
34685 if(s.hasChildNodes()){
34686 if(!s.isExpanded()){
34688 }else if(s.firstChild){
34689 this.select(s.firstChild, e);
34694 e.preventDefault();
34695 if(s.hasChildNodes() && s.isExpanded()){
34697 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34698 this.select(s.parentNode, e);
34706 * @class Roo.tree.MultiSelectionModel
34707 * @extends Roo.util.Observable
34708 * Multi selection for a TreePanel.
34709 * @param {Object} cfg Configuration
34711 Roo.tree.MultiSelectionModel = function(){
34712 this.selNodes = [];
34716 * @event selectionchange
34717 * Fires when the selected nodes change
34718 * @param {MultiSelectionModel} this
34719 * @param {Array} nodes Array of the selected nodes
34721 "selectionchange" : true
34723 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34727 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34728 init : function(tree){
34730 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34731 tree.on("click", this.onNodeClick, this);
34734 onNodeClick : function(node, e){
34735 this.select(node, e, e.ctrlKey);
34740 * @param {TreeNode} node The node to select
34741 * @param {EventObject} e (optional) An event associated with the selection
34742 * @param {Boolean} keepExisting True to retain existing selections
34743 * @return {TreeNode} The selected node
34745 select : function(node, e, keepExisting){
34746 if(keepExisting !== true){
34747 this.clearSelections(true);
34749 if(this.isSelected(node)){
34750 this.lastSelNode = node;
34753 this.selNodes.push(node);
34754 this.selMap[node.id] = node;
34755 this.lastSelNode = node;
34756 node.ui.onSelectedChange(true);
34757 this.fireEvent("selectionchange", this, this.selNodes);
34763 * @param {TreeNode} node The node to unselect
34765 unselect : function(node){
34766 if(this.selMap[node.id]){
34767 node.ui.onSelectedChange(false);
34768 var sn = this.selNodes;
34771 index = sn.indexOf(node);
34773 for(var i = 0, len = sn.length; i < len; i++){
34781 this.selNodes.splice(index, 1);
34783 delete this.selMap[node.id];
34784 this.fireEvent("selectionchange", this, this.selNodes);
34789 * Clear all selections
34791 clearSelections : function(suppressEvent){
34792 var sn = this.selNodes;
34794 for(var i = 0, len = sn.length; i < len; i++){
34795 sn[i].ui.onSelectedChange(false);
34797 this.selNodes = [];
34799 if(suppressEvent !== true){
34800 this.fireEvent("selectionchange", this, this.selNodes);
34806 * Returns true if the node is selected
34807 * @param {TreeNode} node The node to check
34808 * @return {Boolean}
34810 isSelected : function(node){
34811 return this.selMap[node.id] ? true : false;
34815 * Returns an array of the selected nodes
34818 getSelectedNodes : function(){
34819 return this.selNodes;
34822 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34824 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34826 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34829 * Ext JS Library 1.1.1
34830 * Copyright(c) 2006-2007, Ext JS, LLC.
34832 * Originally Released Under LGPL - original licence link has changed is not relivant.
34835 * <script type="text/javascript">
34839 * @class Roo.tree.TreeNode
34840 * @extends Roo.data.Node
34841 * @cfg {String} text The text for this node
34842 * @cfg {Boolean} expanded true to start the node expanded
34843 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34844 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34845 * @cfg {Boolean} disabled true to start the node disabled
34846 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34847 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34848 * @cfg {String} cls A css class to be added to the node
34849 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34850 * @cfg {String} href URL of the link used for the node (defaults to #)
34851 * @cfg {String} hrefTarget target frame for the link
34852 * @cfg {String} qtip An Ext QuickTip for the node
34853 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34854 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34855 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34856 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34857 * (defaults to undefined with no checkbox rendered)
34859 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34861 Roo.tree.TreeNode = function(attributes){
34862 attributes = attributes || {};
34863 if(typeof attributes == "string"){
34864 attributes = {text: attributes};
34866 this.childrenRendered = false;
34867 this.rendered = false;
34868 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34869 this.expanded = attributes.expanded === true;
34870 this.isTarget = attributes.isTarget !== false;
34871 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34872 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34875 * Read-only. The text for this node. To change it use setText().
34878 this.text = attributes.text;
34880 * True if this node is disabled.
34883 this.disabled = attributes.disabled === true;
34887 * @event textchange
34888 * Fires when the text for this node is changed
34889 * @param {Node} this This node
34890 * @param {String} text The new text
34891 * @param {String} oldText The old text
34893 "textchange" : true,
34895 * @event beforeexpand
34896 * Fires before this node is expanded, return false to cancel.
34897 * @param {Node} this This node
34898 * @param {Boolean} deep
34899 * @param {Boolean} anim
34901 "beforeexpand" : true,
34903 * @event beforecollapse
34904 * Fires before this node is collapsed, return false to cancel.
34905 * @param {Node} this This node
34906 * @param {Boolean} deep
34907 * @param {Boolean} anim
34909 "beforecollapse" : true,
34912 * Fires when this node is expanded
34913 * @param {Node} this This node
34917 * @event disabledchange
34918 * Fires when the disabled status of this node changes
34919 * @param {Node} this This node
34920 * @param {Boolean} disabled
34922 "disabledchange" : true,
34925 * Fires when this node is collapsed
34926 * @param {Node} this This node
34930 * @event beforeclick
34931 * Fires before click processing. Return false to cancel the default action.
34932 * @param {Node} this This node
34933 * @param {Roo.EventObject} e The event object
34935 "beforeclick":true,
34937 * @event checkchange
34938 * Fires when a node with a checkbox's checked property changes
34939 * @param {Node} this This node
34940 * @param {Boolean} checked
34942 "checkchange":true,
34945 * Fires when this node is clicked
34946 * @param {Node} this This node
34947 * @param {Roo.EventObject} e The event object
34952 * Fires when this node is double clicked
34953 * @param {Node} this This node
34954 * @param {Roo.EventObject} e The event object
34958 * @event contextmenu
34959 * Fires when this node is right clicked
34960 * @param {Node} this This node
34961 * @param {Roo.EventObject} e The event object
34963 "contextmenu":true,
34965 * @event beforechildrenrendered
34966 * Fires right before the child nodes for this node are rendered
34967 * @param {Node} this This node
34969 "beforechildrenrendered":true
34972 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34975 * Read-only. The UI for this node
34978 this.ui = new uiClass(this);
34980 // finally support items[]
34981 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34986 Roo.each(this.attributes.items, function(c) {
34987 this.appendChild(Roo.factory(c,Roo.Tree));
34989 delete this.attributes.items;
34994 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34995 preventHScroll: true,
34997 * Returns true if this node is expanded
34998 * @return {Boolean}
35000 isExpanded : function(){
35001 return this.expanded;
35005 * Returns the UI object for this node
35006 * @return {TreeNodeUI}
35008 getUI : function(){
35012 // private override
35013 setFirstChild : function(node){
35014 var of = this.firstChild;
35015 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35016 if(this.childrenRendered && of && node != of){
35017 of.renderIndent(true, true);
35020 this.renderIndent(true, true);
35024 // private override
35025 setLastChild : function(node){
35026 var ol = this.lastChild;
35027 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35028 if(this.childrenRendered && ol && node != ol){
35029 ol.renderIndent(true, true);
35032 this.renderIndent(true, true);
35036 // these methods are overridden to provide lazy rendering support
35037 // private override
35038 appendChild : function()
35040 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35041 if(node && this.childrenRendered){
35044 this.ui.updateExpandIcon();
35048 // private override
35049 removeChild : function(node){
35050 this.ownerTree.getSelectionModel().unselect(node);
35051 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35052 // if it's been rendered remove dom node
35053 if(this.childrenRendered){
35056 if(this.childNodes.length < 1){
35057 this.collapse(false, false);
35059 this.ui.updateExpandIcon();
35061 if(!this.firstChild) {
35062 this.childrenRendered = false;
35067 // private override
35068 insertBefore : function(node, refNode){
35069 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35070 if(newNode && refNode && this.childrenRendered){
35073 this.ui.updateExpandIcon();
35078 * Sets the text for this node
35079 * @param {String} text
35081 setText : function(text){
35082 var oldText = this.text;
35084 this.attributes.text = text;
35085 if(this.rendered){ // event without subscribing
35086 this.ui.onTextChange(this, text, oldText);
35088 this.fireEvent("textchange", this, text, oldText);
35092 * Triggers selection of this node
35094 select : function(){
35095 this.getOwnerTree().getSelectionModel().select(this);
35099 * Triggers deselection of this node
35101 unselect : function(){
35102 this.getOwnerTree().getSelectionModel().unselect(this);
35106 * Returns true if this node is selected
35107 * @return {Boolean}
35109 isSelected : function(){
35110 return this.getOwnerTree().getSelectionModel().isSelected(this);
35114 * Expand this node.
35115 * @param {Boolean} deep (optional) True to expand all children as well
35116 * @param {Boolean} anim (optional) false to cancel the default animation
35117 * @param {Function} callback (optional) A callback to be called when
35118 * expanding this node completes (does not wait for deep expand to complete).
35119 * Called with 1 parameter, this node.
35121 expand : function(deep, anim, callback){
35122 if(!this.expanded){
35123 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35126 if(!this.childrenRendered){
35127 this.renderChildren();
35129 this.expanded = true;
35130 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35131 this.ui.animExpand(function(){
35132 this.fireEvent("expand", this);
35133 if(typeof callback == "function"){
35137 this.expandChildNodes(true);
35139 }.createDelegate(this));
35143 this.fireEvent("expand", this);
35144 if(typeof callback == "function"){
35149 if(typeof callback == "function"){
35154 this.expandChildNodes(true);
35158 isHiddenRoot : function(){
35159 return this.isRoot && !this.getOwnerTree().rootVisible;
35163 * Collapse this node.
35164 * @param {Boolean} deep (optional) True to collapse all children as well
35165 * @param {Boolean} anim (optional) false to cancel the default animation
35167 collapse : function(deep, anim){
35168 if(this.expanded && !this.isHiddenRoot()){
35169 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35172 this.expanded = false;
35173 if((this.getOwnerTree().animate && anim !== false) || anim){
35174 this.ui.animCollapse(function(){
35175 this.fireEvent("collapse", this);
35177 this.collapseChildNodes(true);
35179 }.createDelegate(this));
35182 this.ui.collapse();
35183 this.fireEvent("collapse", this);
35187 var cs = this.childNodes;
35188 for(var i = 0, len = cs.length; i < len; i++) {
35189 cs[i].collapse(true, false);
35195 delayedExpand : function(delay){
35196 if(!this.expandProcId){
35197 this.expandProcId = this.expand.defer(delay, this);
35202 cancelExpand : function(){
35203 if(this.expandProcId){
35204 clearTimeout(this.expandProcId);
35206 this.expandProcId = false;
35210 * Toggles expanded/collapsed state of the node
35212 toggle : function(){
35221 * Ensures all parent nodes are expanded
35223 ensureVisible : function(callback){
35224 var tree = this.getOwnerTree();
35225 tree.expandPath(this.parentNode.getPath(), false, function(){
35226 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35227 Roo.callback(callback);
35228 }.createDelegate(this));
35232 * Expand all child nodes
35233 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35235 expandChildNodes : function(deep){
35236 var cs = this.childNodes;
35237 for(var i = 0, len = cs.length; i < len; i++) {
35238 cs[i].expand(deep);
35243 * Collapse all child nodes
35244 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35246 collapseChildNodes : function(deep){
35247 var cs = this.childNodes;
35248 for(var i = 0, len = cs.length; i < len; i++) {
35249 cs[i].collapse(deep);
35254 * Disables this node
35256 disable : function(){
35257 this.disabled = true;
35259 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35260 this.ui.onDisableChange(this, true);
35262 this.fireEvent("disabledchange", this, true);
35266 * Enables this node
35268 enable : function(){
35269 this.disabled = false;
35270 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35271 this.ui.onDisableChange(this, false);
35273 this.fireEvent("disabledchange", this, false);
35277 renderChildren : function(suppressEvent){
35278 if(suppressEvent !== false){
35279 this.fireEvent("beforechildrenrendered", this);
35281 var cs = this.childNodes;
35282 for(var i = 0, len = cs.length; i < len; i++){
35283 cs[i].render(true);
35285 this.childrenRendered = true;
35289 sort : function(fn, scope){
35290 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35291 if(this.childrenRendered){
35292 var cs = this.childNodes;
35293 for(var i = 0, len = cs.length; i < len; i++){
35294 cs[i].render(true);
35300 render : function(bulkRender){
35301 this.ui.render(bulkRender);
35302 if(!this.rendered){
35303 this.rendered = true;
35305 this.expanded = false;
35306 this.expand(false, false);
35312 renderIndent : function(deep, refresh){
35314 this.ui.childIndent = null;
35316 this.ui.renderIndent();
35317 if(deep === true && this.childrenRendered){
35318 var cs = this.childNodes;
35319 for(var i = 0, len = cs.length; i < len; i++){
35320 cs[i].renderIndent(true, refresh);
35326 * Ext JS Library 1.1.1
35327 * Copyright(c) 2006-2007, Ext JS, LLC.
35329 * Originally Released Under LGPL - original licence link has changed is not relivant.
35332 * <script type="text/javascript">
35336 * @class Roo.tree.AsyncTreeNode
35337 * @extends Roo.tree.TreeNode
35338 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35340 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35342 Roo.tree.AsyncTreeNode = function(config){
35343 this.loaded = false;
35344 this.loading = false;
35345 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35347 * @event beforeload
35348 * Fires before this node is loaded, return false to cancel
35349 * @param {Node} this This node
35351 this.addEvents({'beforeload':true, 'load': true});
35354 * Fires when this node is loaded
35355 * @param {Node} this This node
35358 * The loader used by this node (defaults to using the tree's defined loader)
35363 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35364 expand : function(deep, anim, callback){
35365 if(this.loading){ // if an async load is already running, waiting til it's done
35367 var f = function(){
35368 if(!this.loading){ // done loading
35369 clearInterval(timer);
35370 this.expand(deep, anim, callback);
35372 }.createDelegate(this);
35373 timer = setInterval(f, 200);
35377 if(this.fireEvent("beforeload", this) === false){
35380 this.loading = true;
35381 this.ui.beforeLoad(this);
35382 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35384 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35388 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35392 * Returns true if this node is currently loading
35393 * @return {Boolean}
35395 isLoading : function(){
35396 return this.loading;
35399 loadComplete : function(deep, anim, callback){
35400 this.loading = false;
35401 this.loaded = true;
35402 this.ui.afterLoad(this);
35403 this.fireEvent("load", this);
35404 this.expand(deep, anim, callback);
35408 * Returns true if this node has been loaded
35409 * @return {Boolean}
35411 isLoaded : function(){
35412 return this.loaded;
35415 hasChildNodes : function(){
35416 if(!this.isLeaf() && !this.loaded){
35419 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35424 * Trigger a reload for this node
35425 * @param {Function} callback
35427 reload : function(callback){
35428 this.collapse(false, false);
35429 while(this.firstChild){
35430 this.removeChild(this.firstChild);
35432 this.childrenRendered = false;
35433 this.loaded = false;
35434 if(this.isHiddenRoot()){
35435 this.expanded = false;
35437 this.expand(false, false, callback);
35441 * Ext JS Library 1.1.1
35442 * Copyright(c) 2006-2007, Ext JS, LLC.
35444 * Originally Released Under LGPL - original licence link has changed is not relivant.
35447 * <script type="text/javascript">
35451 * @class Roo.tree.TreeNodeUI
35453 * @param {Object} node The node to render
35454 * The TreeNode UI implementation is separate from the
35455 * tree implementation. Unless you are customizing the tree UI,
35456 * you should never have to use this directly.
35458 Roo.tree.TreeNodeUI = function(node){
35460 this.rendered = false;
35461 this.animating = false;
35462 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35465 Roo.tree.TreeNodeUI.prototype = {
35466 removeChild : function(node){
35468 this.ctNode.removeChild(node.ui.getEl());
35472 beforeLoad : function(){
35473 this.addClass("x-tree-node-loading");
35476 afterLoad : function(){
35477 this.removeClass("x-tree-node-loading");
35480 onTextChange : function(node, text, oldText){
35482 this.textNode.innerHTML = text;
35486 onDisableChange : function(node, state){
35487 this.disabled = state;
35489 this.addClass("x-tree-node-disabled");
35491 this.removeClass("x-tree-node-disabled");
35495 onSelectedChange : function(state){
35498 this.addClass("x-tree-selected");
35501 this.removeClass("x-tree-selected");
35505 onMove : function(tree, node, oldParent, newParent, index, refNode){
35506 this.childIndent = null;
35508 var targetNode = newParent.ui.getContainer();
35509 if(!targetNode){//target not rendered
35510 this.holder = document.createElement("div");
35511 this.holder.appendChild(this.wrap);
35514 var insertBefore = refNode ? refNode.ui.getEl() : null;
35516 targetNode.insertBefore(this.wrap, insertBefore);
35518 targetNode.appendChild(this.wrap);
35520 this.node.renderIndent(true);
35524 addClass : function(cls){
35526 Roo.fly(this.elNode).addClass(cls);
35530 removeClass : function(cls){
35532 Roo.fly(this.elNode).removeClass(cls);
35536 remove : function(){
35538 this.holder = document.createElement("div");
35539 this.holder.appendChild(this.wrap);
35543 fireEvent : function(){
35544 return this.node.fireEvent.apply(this.node, arguments);
35547 initEvents : function(){
35548 this.node.on("move", this.onMove, this);
35549 var E = Roo.EventManager;
35550 var a = this.anchor;
35552 var el = Roo.fly(a, '_treeui');
35554 if(Roo.isOpera){ // opera render bug ignores the CSS
35555 el.setStyle("text-decoration", "none");
35558 el.on("click", this.onClick, this);
35559 el.on("dblclick", this.onDblClick, this);
35562 Roo.EventManager.on(this.checkbox,
35563 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35566 el.on("contextmenu", this.onContextMenu, this);
35568 var icon = Roo.fly(this.iconNode);
35569 icon.on("click", this.onClick, this);
35570 icon.on("dblclick", this.onDblClick, this);
35571 icon.on("contextmenu", this.onContextMenu, this);
35572 E.on(this.ecNode, "click", this.ecClick, this, true);
35574 if(this.node.disabled){
35575 this.addClass("x-tree-node-disabled");
35577 if(this.node.hidden){
35578 this.addClass("x-tree-node-disabled");
35580 var ot = this.node.getOwnerTree();
35581 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35582 if(dd && (!this.node.isRoot || ot.rootVisible)){
35583 Roo.dd.Registry.register(this.elNode, {
35585 handles: this.getDDHandles(),
35591 getDDHandles : function(){
35592 return [this.iconNode, this.textNode];
35597 this.wrap.style.display = "none";
35603 this.wrap.style.display = "";
35607 onContextMenu : function(e){
35608 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35609 e.preventDefault();
35611 this.fireEvent("contextmenu", this.node, e);
35615 onClick : function(e){
35620 if(this.fireEvent("beforeclick", this.node, e) !== false){
35621 if(!this.disabled && this.node.attributes.href){
35622 this.fireEvent("click", this.node, e);
35625 e.preventDefault();
35630 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35631 this.node.toggle();
35634 this.fireEvent("click", this.node, e);
35640 onDblClick : function(e){
35641 e.preventDefault();
35646 this.toggleCheck();
35648 if(!this.animating && this.node.hasChildNodes()){
35649 this.node.toggle();
35651 this.fireEvent("dblclick", this.node, e);
35654 onCheckChange : function(){
35655 var checked = this.checkbox.checked;
35656 this.node.attributes.checked = checked;
35657 this.fireEvent('checkchange', this.node, checked);
35660 ecClick : function(e){
35661 if(!this.animating && this.node.hasChildNodes()){
35662 this.node.toggle();
35666 startDrop : function(){
35667 this.dropping = true;
35670 // delayed drop so the click event doesn't get fired on a drop
35671 endDrop : function(){
35672 setTimeout(function(){
35673 this.dropping = false;
35674 }.createDelegate(this), 50);
35677 expand : function(){
35678 this.updateExpandIcon();
35679 this.ctNode.style.display = "";
35682 focus : function(){
35683 if(!this.node.preventHScroll){
35684 try{this.anchor.focus();
35686 }else if(!Roo.isIE){
35688 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35689 var l = noscroll.scrollLeft;
35690 this.anchor.focus();
35691 noscroll.scrollLeft = l;
35696 toggleCheck : function(value){
35697 var cb = this.checkbox;
35699 cb.checked = (value === undefined ? !cb.checked : value);
35705 this.anchor.blur();
35709 animExpand : function(callback){
35710 var ct = Roo.get(this.ctNode);
35712 if(!this.node.hasChildNodes()){
35713 this.updateExpandIcon();
35714 this.ctNode.style.display = "";
35715 Roo.callback(callback);
35718 this.animating = true;
35719 this.updateExpandIcon();
35722 callback : function(){
35723 this.animating = false;
35724 Roo.callback(callback);
35727 duration: this.node.ownerTree.duration || .25
35731 highlight : function(){
35732 var tree = this.node.getOwnerTree();
35733 Roo.fly(this.wrap).highlight(
35734 tree.hlColor || "C3DAF9",
35735 {endColor: tree.hlBaseColor}
35739 collapse : function(){
35740 this.updateExpandIcon();
35741 this.ctNode.style.display = "none";
35744 animCollapse : function(callback){
35745 var ct = Roo.get(this.ctNode);
35746 ct.enableDisplayMode('block');
35749 this.animating = true;
35750 this.updateExpandIcon();
35753 callback : function(){
35754 this.animating = false;
35755 Roo.callback(callback);
35758 duration: this.node.ownerTree.duration || .25
35762 getContainer : function(){
35763 return this.ctNode;
35766 getEl : function(){
35770 appendDDGhost : function(ghostNode){
35771 ghostNode.appendChild(this.elNode.cloneNode(true));
35774 getDDRepairXY : function(){
35775 return Roo.lib.Dom.getXY(this.iconNode);
35778 onRender : function(){
35782 render : function(bulkRender){
35783 var n = this.node, a = n.attributes;
35784 var targetNode = n.parentNode ?
35785 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35787 if(!this.rendered){
35788 this.rendered = true;
35790 this.renderElements(n, a, targetNode, bulkRender);
35793 if(this.textNode.setAttributeNS){
35794 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35796 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35799 this.textNode.setAttribute("ext:qtip", a.qtip);
35801 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35804 }else if(a.qtipCfg){
35805 a.qtipCfg.target = Roo.id(this.textNode);
35806 Roo.QuickTips.register(a.qtipCfg);
35809 if(!this.node.expanded){
35810 this.updateExpandIcon();
35813 if(bulkRender === true) {
35814 targetNode.appendChild(this.wrap);
35819 renderElements : function(n, a, targetNode, bulkRender)
35821 // add some indent caching, this helps performance when rendering a large tree
35822 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35823 var t = n.getOwnerTree();
35824 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35825 if (typeof(n.attributes.html) != 'undefined') {
35826 txt = n.attributes.html;
35828 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35829 var cb = typeof a.checked == 'boolean';
35830 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35831 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35832 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35833 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35834 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35835 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35836 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35837 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35838 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35839 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35842 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35843 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35844 n.nextSibling.ui.getEl(), buf.join(""));
35846 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35849 this.elNode = this.wrap.childNodes[0];
35850 this.ctNode = this.wrap.childNodes[1];
35851 var cs = this.elNode.childNodes;
35852 this.indentNode = cs[0];
35853 this.ecNode = cs[1];
35854 this.iconNode = cs[2];
35857 this.checkbox = cs[3];
35860 this.anchor = cs[index];
35861 this.textNode = cs[index].firstChild;
35864 getAnchor : function(){
35865 return this.anchor;
35868 getTextEl : function(){
35869 return this.textNode;
35872 getIconEl : function(){
35873 return this.iconNode;
35876 isChecked : function(){
35877 return this.checkbox ? this.checkbox.checked : false;
35880 updateExpandIcon : function(){
35882 var n = this.node, c1, c2;
35883 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35884 var hasChild = n.hasChildNodes();
35888 c1 = "x-tree-node-collapsed";
35889 c2 = "x-tree-node-expanded";
35892 c1 = "x-tree-node-expanded";
35893 c2 = "x-tree-node-collapsed";
35896 this.removeClass("x-tree-node-leaf");
35897 this.wasLeaf = false;
35899 if(this.c1 != c1 || this.c2 != c2){
35900 Roo.fly(this.elNode).replaceClass(c1, c2);
35901 this.c1 = c1; this.c2 = c2;
35904 // this changes non-leafs into leafs if they have no children.
35905 // it's not very rational behaviour..
35907 if(!this.wasLeaf && this.node.leaf){
35908 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35911 this.wasLeaf = true;
35914 var ecc = "x-tree-ec-icon "+cls;
35915 if(this.ecc != ecc){
35916 this.ecNode.className = ecc;
35922 getChildIndent : function(){
35923 if(!this.childIndent){
35927 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35929 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35931 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35936 this.childIndent = buf.join("");
35938 return this.childIndent;
35941 renderIndent : function(){
35944 var p = this.node.parentNode;
35946 indent = p.ui.getChildIndent();
35948 if(this.indentMarkup != indent){ // don't rerender if not required
35949 this.indentNode.innerHTML = indent;
35950 this.indentMarkup = indent;
35952 this.updateExpandIcon();
35957 Roo.tree.RootTreeNodeUI = function(){
35958 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35960 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35961 render : function(){
35962 if(!this.rendered){
35963 var targetNode = this.node.ownerTree.innerCt.dom;
35964 this.node.expanded = true;
35965 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35966 this.wrap = this.ctNode = targetNode.firstChild;
35969 collapse : function(){
35971 expand : function(){
35975 * Ext JS Library 1.1.1
35976 * Copyright(c) 2006-2007, Ext JS, LLC.
35978 * Originally Released Under LGPL - original licence link has changed is not relivant.
35981 * <script type="text/javascript">
35984 * @class Roo.tree.TreeLoader
35985 * @extends Roo.util.Observable
35986 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35987 * nodes from a specified URL. The response must be a javascript Array definition
35988 * who's elements are node definition objects. eg:
35993 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35994 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36001 * The old style respose with just an array is still supported, but not recommended.
36004 * A server request is sent, and child nodes are loaded only when a node is expanded.
36005 * The loading node's id is passed to the server under the parameter name "node" to
36006 * enable the server to produce the correct child nodes.
36008 * To pass extra parameters, an event handler may be attached to the "beforeload"
36009 * event, and the parameters specified in the TreeLoader's baseParams property:
36011 myTreeLoader.on("beforeload", function(treeLoader, node) {
36012 this.baseParams.category = node.attributes.category;
36015 * This would pass an HTTP parameter called "category" to the server containing
36016 * the value of the Node's "category" attribute.
36018 * Creates a new Treeloader.
36019 * @param {Object} config A config object containing config properties.
36021 Roo.tree.TreeLoader = function(config){
36022 this.baseParams = {};
36023 this.requestMethod = "POST";
36024 Roo.apply(this, config);
36029 * @event beforeload
36030 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36031 * @param {Object} This TreeLoader object.
36032 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36033 * @param {Object} callback The callback function specified in the {@link #load} call.
36038 * Fires when the node has been successfuly loaded.
36039 * @param {Object} This TreeLoader object.
36040 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36041 * @param {Object} response The response object containing the data from the server.
36045 * @event loadexception
36046 * Fires if the network request failed.
36047 * @param {Object} This TreeLoader object.
36048 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36049 * @param {Object} response The response object containing the data from the server.
36051 loadexception : true,
36054 * Fires before a node is created, enabling you to return custom Node types
36055 * @param {Object} This TreeLoader object.
36056 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36061 Roo.tree.TreeLoader.superclass.constructor.call(this);
36064 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36066 * @cfg {String} dataUrl The URL from which to request a Json string which
36067 * specifies an array of node definition object representing the child nodes
36071 * @cfg {String} requestMethod either GET or POST
36072 * defaults to POST (due to BC)
36076 * @cfg {Object} baseParams (optional) An object containing properties which
36077 * specify HTTP parameters to be passed to each request for child nodes.
36080 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36081 * created by this loader. If the attributes sent by the server have an attribute in this object,
36082 * they take priority.
36085 * @cfg {Object} uiProviders (optional) An object containing properties which
36087 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36088 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36089 * <i>uiProvider</i> attribute of a returned child node is a string rather
36090 * than a reference to a TreeNodeUI implementation, this that string value
36091 * is used as a property name in the uiProviders object. You can define the provider named
36092 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36097 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36098 * child nodes before loading.
36100 clearOnLoad : true,
36103 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36104 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36105 * Grid query { data : [ .....] }
36110 * @cfg {String} queryParam (optional)
36111 * Name of the query as it will be passed on the querystring (defaults to 'node')
36112 * eg. the request will be ?node=[id]
36119 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36120 * This is called automatically when a node is expanded, but may be used to reload
36121 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36122 * @param {Roo.tree.TreeNode} node
36123 * @param {Function} callback
36125 load : function(node, callback){
36126 if(this.clearOnLoad){
36127 while(node.firstChild){
36128 node.removeChild(node.firstChild);
36131 if(node.attributes.children){ // preloaded json children
36132 var cs = node.attributes.children;
36133 for(var i = 0, len = cs.length; i < len; i++){
36134 node.appendChild(this.createNode(cs[i]));
36136 if(typeof callback == "function"){
36139 }else if(this.dataUrl){
36140 this.requestData(node, callback);
36144 getParams: function(node){
36145 var buf = [], bp = this.baseParams;
36146 for(var key in bp){
36147 if(typeof bp[key] != "function"){
36148 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36151 var n = this.queryParam === false ? 'node' : this.queryParam;
36152 buf.push(n + "=", encodeURIComponent(node.id));
36153 return buf.join("");
36156 requestData : function(node, callback){
36157 if(this.fireEvent("beforeload", this, node, callback) !== false){
36158 this.transId = Roo.Ajax.request({
36159 method:this.requestMethod,
36160 url: this.dataUrl||this.url,
36161 success: this.handleResponse,
36162 failure: this.handleFailure,
36164 argument: {callback: callback, node: node},
36165 params: this.getParams(node)
36168 // if the load is cancelled, make sure we notify
36169 // the node that we are done
36170 if(typeof callback == "function"){
36176 isLoading : function(){
36177 return this.transId ? true : false;
36180 abort : function(){
36181 if(this.isLoading()){
36182 Roo.Ajax.abort(this.transId);
36187 createNode : function(attr)
36189 // apply baseAttrs, nice idea Corey!
36190 if(this.baseAttrs){
36191 Roo.applyIf(attr, this.baseAttrs);
36193 if(this.applyLoader !== false){
36194 attr.loader = this;
36196 // uiProvider = depreciated..
36198 if(typeof(attr.uiProvider) == 'string'){
36199 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36200 /** eval:var:attr */ eval(attr.uiProvider);
36202 if(typeof(this.uiProviders['default']) != 'undefined') {
36203 attr.uiProvider = this.uiProviders['default'];
36206 this.fireEvent('create', this, attr);
36208 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36210 new Roo.tree.TreeNode(attr) :
36211 new Roo.tree.AsyncTreeNode(attr));
36214 processResponse : function(response, node, callback)
36216 var json = response.responseText;
36219 var o = Roo.decode(json);
36221 if (this.root === false && typeof(o.success) != undefined) {
36222 this.root = 'data'; // the default behaviour for list like data..
36225 if (this.root !== false && !o.success) {
36226 // it's a failure condition.
36227 var a = response.argument;
36228 this.fireEvent("loadexception", this, a.node, response);
36229 Roo.log("Load failed - should have a handler really");
36235 if (this.root !== false) {
36239 for(var i = 0, len = o.length; i < len; i++){
36240 var n = this.createNode(o[i]);
36242 node.appendChild(n);
36245 if(typeof callback == "function"){
36246 callback(this, node);
36249 this.handleFailure(response);
36253 handleResponse : function(response){
36254 this.transId = false;
36255 var a = response.argument;
36256 this.processResponse(response, a.node, a.callback);
36257 this.fireEvent("load", this, a.node, response);
36260 handleFailure : function(response)
36262 // should handle failure better..
36263 this.transId = false;
36264 var a = response.argument;
36265 this.fireEvent("loadexception", this, a.node, response);
36266 if(typeof a.callback == "function"){
36267 a.callback(this, a.node);
36272 * Ext JS Library 1.1.1
36273 * Copyright(c) 2006-2007, Ext JS, LLC.
36275 * Originally Released Under LGPL - original licence link has changed is not relivant.
36278 * <script type="text/javascript">
36282 * @class Roo.tree.TreeFilter
36283 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36284 * @param {TreePanel} tree
36285 * @param {Object} config (optional)
36287 Roo.tree.TreeFilter = function(tree, config){
36289 this.filtered = {};
36290 Roo.apply(this, config);
36293 Roo.tree.TreeFilter.prototype = {
36300 * Filter the data by a specific attribute.
36301 * @param {String/RegExp} value Either string that the attribute value
36302 * should start with or a RegExp to test against the attribute
36303 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36304 * @param {TreeNode} startNode (optional) The node to start the filter at.
36306 filter : function(value, attr, startNode){
36307 attr = attr || "text";
36309 if(typeof value == "string"){
36310 var vlen = value.length;
36311 // auto clear empty filter
36312 if(vlen == 0 && this.clearBlank){
36316 value = value.toLowerCase();
36318 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36320 }else if(value.exec){ // regex?
36322 return value.test(n.attributes[attr]);
36325 throw 'Illegal filter type, must be string or regex';
36327 this.filterBy(f, null, startNode);
36331 * Filter by a function. The passed function will be called with each
36332 * node in the tree (or from the startNode). If the function returns true, the node is kept
36333 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36334 * @param {Function} fn The filter function
36335 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36337 filterBy : function(fn, scope, startNode){
36338 startNode = startNode || this.tree.root;
36339 if(this.autoClear){
36342 var af = this.filtered, rv = this.reverse;
36343 var f = function(n){
36344 if(n == startNode){
36350 var m = fn.call(scope || n, n);
36358 startNode.cascade(f);
36361 if(typeof id != "function"){
36363 if(n && n.parentNode){
36364 n.parentNode.removeChild(n);
36372 * Clears the current filter. Note: with the "remove" option
36373 * set a filter cannot be cleared.
36375 clear : function(){
36377 var af = this.filtered;
36379 if(typeof id != "function"){
36386 this.filtered = {};
36391 * Ext JS Library 1.1.1
36392 * Copyright(c) 2006-2007, Ext JS, LLC.
36394 * Originally Released Under LGPL - original licence link has changed is not relivant.
36397 * <script type="text/javascript">
36402 * @class Roo.tree.TreeSorter
36403 * Provides sorting of nodes in a TreePanel
36405 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36406 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36407 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36408 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36409 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36410 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36412 * @param {TreePanel} tree
36413 * @param {Object} config
36415 Roo.tree.TreeSorter = function(tree, config){
36416 Roo.apply(this, config);
36417 tree.on("beforechildrenrendered", this.doSort, this);
36418 tree.on("append", this.updateSort, this);
36419 tree.on("insert", this.updateSort, this);
36421 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36422 var p = this.property || "text";
36423 var sortType = this.sortType;
36424 var fs = this.folderSort;
36425 var cs = this.caseSensitive === true;
36426 var leafAttr = this.leafAttr || 'leaf';
36428 this.sortFn = function(n1, n2){
36430 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36433 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36437 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36438 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36440 return dsc ? +1 : -1;
36442 return dsc ? -1 : +1;
36449 Roo.tree.TreeSorter.prototype = {
36450 doSort : function(node){
36451 node.sort(this.sortFn);
36454 compareNodes : function(n1, n2){
36455 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36458 updateSort : function(tree, node){
36459 if(node.childrenRendered){
36460 this.doSort.defer(1, this, [node]);
36465 * Ext JS Library 1.1.1
36466 * Copyright(c) 2006-2007, Ext JS, LLC.
36468 * Originally Released Under LGPL - original licence link has changed is not relivant.
36471 * <script type="text/javascript">
36474 if(Roo.dd.DropZone){
36476 Roo.tree.TreeDropZone = function(tree, config){
36477 this.allowParentInsert = false;
36478 this.allowContainerDrop = false;
36479 this.appendOnly = false;
36480 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36482 this.lastInsertClass = "x-tree-no-status";
36483 this.dragOverData = {};
36486 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36487 ddGroup : "TreeDD",
36490 expandDelay : 1000,
36492 expandNode : function(node){
36493 if(node.hasChildNodes() && !node.isExpanded()){
36494 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36498 queueExpand : function(node){
36499 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36502 cancelExpand : function(){
36503 if(this.expandProcId){
36504 clearTimeout(this.expandProcId);
36505 this.expandProcId = false;
36509 isValidDropPoint : function(n, pt, dd, e, data){
36510 if(!n || !data){ return false; }
36511 var targetNode = n.node;
36512 var dropNode = data.node;
36513 // default drop rules
36514 if(!(targetNode && targetNode.isTarget && pt)){
36517 if(pt == "append" && targetNode.allowChildren === false){
36520 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36523 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36526 // reuse the object
36527 var overEvent = this.dragOverData;
36528 overEvent.tree = this.tree;
36529 overEvent.target = targetNode;
36530 overEvent.data = data;
36531 overEvent.point = pt;
36532 overEvent.source = dd;
36533 overEvent.rawEvent = e;
36534 overEvent.dropNode = dropNode;
36535 overEvent.cancel = false;
36536 var result = this.tree.fireEvent("nodedragover", overEvent);
36537 return overEvent.cancel === false && result !== false;
36540 getDropPoint : function(e, n, dd)
36544 return tn.allowChildren !== false ? "append" : false; // always append for root
36546 var dragEl = n.ddel;
36547 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36548 var y = Roo.lib.Event.getPageY(e);
36549 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36551 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36552 var noAppend = tn.allowChildren === false;
36553 if(this.appendOnly || tn.parentNode.allowChildren === false){
36554 return noAppend ? false : "append";
36556 var noBelow = false;
36557 if(!this.allowParentInsert){
36558 noBelow = tn.hasChildNodes() && tn.isExpanded();
36560 var q = (b - t) / (noAppend ? 2 : 3);
36561 if(y >= t && y < (t + q)){
36563 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36570 onNodeEnter : function(n, dd, e, data)
36572 this.cancelExpand();
36575 onNodeOver : function(n, dd, e, data)
36578 var pt = this.getDropPoint(e, n, dd);
36581 // auto node expand check
36582 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36583 this.queueExpand(node);
36584 }else if(pt != "append"){
36585 this.cancelExpand();
36588 // set the insert point style on the target node
36589 var returnCls = this.dropNotAllowed;
36590 if(this.isValidDropPoint(n, pt, dd, e, data)){
36595 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36596 cls = "x-tree-drag-insert-above";
36597 }else if(pt == "below"){
36598 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36599 cls = "x-tree-drag-insert-below";
36601 returnCls = "x-tree-drop-ok-append";
36602 cls = "x-tree-drag-append";
36604 if(this.lastInsertClass != cls){
36605 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36606 this.lastInsertClass = cls;
36613 onNodeOut : function(n, dd, e, data){
36615 this.cancelExpand();
36616 this.removeDropIndicators(n);
36619 onNodeDrop : function(n, dd, e, data){
36620 var point = this.getDropPoint(e, n, dd);
36621 var targetNode = n.node;
36622 targetNode.ui.startDrop();
36623 if(!this.isValidDropPoint(n, point, dd, e, data)){
36624 targetNode.ui.endDrop();
36627 // first try to find the drop node
36628 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36631 target: targetNode,
36636 dropNode: dropNode,
36639 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36640 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36641 targetNode.ui.endDrop();
36644 // allow target changing
36645 targetNode = dropEvent.target;
36646 if(point == "append" && !targetNode.isExpanded()){
36647 targetNode.expand(false, null, function(){
36648 this.completeDrop(dropEvent);
36649 }.createDelegate(this));
36651 this.completeDrop(dropEvent);
36656 completeDrop : function(de){
36657 var ns = de.dropNode, p = de.point, t = de.target;
36658 if(!(ns instanceof Array)){
36662 for(var i = 0, len = ns.length; i < len; i++){
36665 t.parentNode.insertBefore(n, t);
36666 }else if(p == "below"){
36667 t.parentNode.insertBefore(n, t.nextSibling);
36673 if(this.tree.hlDrop){
36677 this.tree.fireEvent("nodedrop", de);
36680 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36681 if(this.tree.hlDrop){
36682 dropNode.ui.focus();
36683 dropNode.ui.highlight();
36685 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36688 getTree : function(){
36692 removeDropIndicators : function(n){
36695 Roo.fly(el).removeClass([
36696 "x-tree-drag-insert-above",
36697 "x-tree-drag-insert-below",
36698 "x-tree-drag-append"]);
36699 this.lastInsertClass = "_noclass";
36703 beforeDragDrop : function(target, e, id){
36704 this.cancelExpand();
36708 afterRepair : function(data){
36709 if(data && Roo.enableFx){
36710 data.node.ui.highlight();
36720 * Ext JS Library 1.1.1
36721 * Copyright(c) 2006-2007, Ext JS, LLC.
36723 * Originally Released Under LGPL - original licence link has changed is not relivant.
36726 * <script type="text/javascript">
36730 if(Roo.dd.DragZone){
36731 Roo.tree.TreeDragZone = function(tree, config){
36732 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36736 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36737 ddGroup : "TreeDD",
36739 onBeforeDrag : function(data, e){
36741 return n && n.draggable && !n.disabled;
36745 onInitDrag : function(e){
36746 var data = this.dragData;
36747 this.tree.getSelectionModel().select(data.node);
36748 this.proxy.update("");
36749 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36750 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36753 getRepairXY : function(e, data){
36754 return data.node.ui.getDDRepairXY();
36757 onEndDrag : function(data, e){
36758 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36763 onValidDrop : function(dd, e, id){
36764 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36768 beforeInvalidDrop : function(e, id){
36769 // this scrolls the original position back into view
36770 var sm = this.tree.getSelectionModel();
36771 sm.clearSelections();
36772 sm.select(this.dragData.node);
36777 * Ext JS Library 1.1.1
36778 * Copyright(c) 2006-2007, Ext JS, LLC.
36780 * Originally Released Under LGPL - original licence link has changed is not relivant.
36783 * <script type="text/javascript">
36786 * @class Roo.tree.TreeEditor
36787 * @extends Roo.Editor
36788 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36789 * as the editor field.
36791 * @param {Object} config (used to be the tree panel.)
36792 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36794 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36795 * @cfg {Roo.form.TextField|Object} field The field configuration
36799 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36802 if (oldconfig) { // old style..
36803 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36806 tree = config.tree;
36807 config.field = config.field || {};
36808 config.field.xtype = 'TextField';
36809 field = Roo.factory(config.field, Roo.form);
36811 config = config || {};
36816 * @event beforenodeedit
36817 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36818 * false from the handler of this event.
36819 * @param {Editor} this
36820 * @param {Roo.tree.Node} node
36822 "beforenodeedit" : true
36826 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36830 tree.on('beforeclick', this.beforeNodeClick, this);
36831 tree.getTreeEl().on('mousedown', this.hide, this);
36832 this.on('complete', this.updateNode, this);
36833 this.on('beforestartedit', this.fitToTree, this);
36834 this.on('startedit', this.bindScroll, this, {delay:10});
36835 this.on('specialkey', this.onSpecialKey, this);
36838 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36840 * @cfg {String} alignment
36841 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36847 * @cfg {Boolean} hideEl
36848 * True to hide the bound element while the editor is displayed (defaults to false)
36852 * @cfg {String} cls
36853 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36855 cls: "x-small-editor x-tree-editor",
36857 * @cfg {Boolean} shim
36858 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36864 * @cfg {Number} maxWidth
36865 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36866 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36867 * scroll and client offsets into account prior to each edit.
36874 fitToTree : function(ed, el){
36875 var td = this.tree.getTreeEl().dom, nd = el.dom;
36876 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36877 td.scrollLeft = nd.offsetLeft;
36881 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36882 this.setSize(w, '');
36884 return this.fireEvent('beforenodeedit', this, this.editNode);
36889 triggerEdit : function(node){
36890 this.completeEdit();
36891 this.editNode = node;
36892 this.startEdit(node.ui.textNode, node.text);
36896 bindScroll : function(){
36897 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36901 beforeNodeClick : function(node, e){
36902 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36903 this.lastClick = new Date();
36904 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36906 this.triggerEdit(node);
36913 updateNode : function(ed, value){
36914 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36915 this.editNode.setText(value);
36919 onHide : function(){
36920 Roo.tree.TreeEditor.superclass.onHide.call(this);
36922 this.editNode.ui.focus();
36927 onSpecialKey : function(field, e){
36928 var k = e.getKey();
36932 }else if(k == e.ENTER && !e.hasModifier()){
36934 this.completeEdit();
36937 });//<Script type="text/javascript">
36940 * Ext JS Library 1.1.1
36941 * Copyright(c) 2006-2007, Ext JS, LLC.
36943 * Originally Released Under LGPL - original licence link has changed is not relivant.
36946 * <script type="text/javascript">
36950 * Not documented??? - probably should be...
36953 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36954 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36956 renderElements : function(n, a, targetNode, bulkRender){
36957 //consel.log("renderElements?");
36958 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36960 var t = n.getOwnerTree();
36961 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36963 var cols = t.columns;
36964 var bw = t.borderWidth;
36966 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36967 var cb = typeof a.checked == "boolean";
36968 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36969 var colcls = 'x-t-' + tid + '-c0';
36971 '<li class="x-tree-node">',
36974 '<div class="x-tree-node-el ', a.cls,'">',
36976 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36979 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36980 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36981 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36982 (a.icon ? ' x-tree-node-inline-icon' : ''),
36983 (a.iconCls ? ' '+a.iconCls : ''),
36984 '" unselectable="on" />',
36985 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36986 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36988 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36989 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36990 '<span unselectable="on" qtip="' + tx + '">',
36994 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36995 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36997 for(var i = 1, len = cols.length; i < len; i++){
36999 colcls = 'x-t-' + tid + '-c' +i;
37000 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37001 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37002 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37008 '<div class="x-clear"></div></div>',
37009 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37012 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37013 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37014 n.nextSibling.ui.getEl(), buf.join(""));
37016 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37018 var el = this.wrap.firstChild;
37020 this.elNode = el.firstChild;
37021 this.ranchor = el.childNodes[1];
37022 this.ctNode = this.wrap.childNodes[1];
37023 var cs = el.firstChild.childNodes;
37024 this.indentNode = cs[0];
37025 this.ecNode = cs[1];
37026 this.iconNode = cs[2];
37029 this.checkbox = cs[3];
37032 this.anchor = cs[index];
37034 this.textNode = cs[index].firstChild;
37036 //el.on("click", this.onClick, this);
37037 //el.on("dblclick", this.onDblClick, this);
37040 // console.log(this);
37042 initEvents : function(){
37043 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37046 var a = this.ranchor;
37048 var el = Roo.get(a);
37050 if(Roo.isOpera){ // opera render bug ignores the CSS
37051 el.setStyle("text-decoration", "none");
37054 el.on("click", this.onClick, this);
37055 el.on("dblclick", this.onDblClick, this);
37056 el.on("contextmenu", this.onContextMenu, this);
37060 /*onSelectedChange : function(state){
37063 this.addClass("x-tree-selected");
37066 this.removeClass("x-tree-selected");
37069 addClass : function(cls){
37071 Roo.fly(this.elRow).addClass(cls);
37077 removeClass : function(cls){
37079 Roo.fly(this.elRow).removeClass(cls);
37085 });//<Script type="text/javascript">
37089 * Ext JS Library 1.1.1
37090 * Copyright(c) 2006-2007, Ext JS, LLC.
37092 * Originally Released Under LGPL - original licence link has changed is not relivant.
37095 * <script type="text/javascript">
37100 * @class Roo.tree.ColumnTree
37101 * @extends Roo.data.TreePanel
37102 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37103 * @cfg {int} borderWidth compined right/left border allowance
37105 * @param {String/HTMLElement/Element} el The container element
37106 * @param {Object} config
37108 Roo.tree.ColumnTree = function(el, config)
37110 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37114 * Fire this event on a container when it resizes
37115 * @param {int} w Width
37116 * @param {int} h Height
37120 this.on('resize', this.onResize, this);
37123 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37127 borderWidth: Roo.isBorderBox ? 0 : 2,
37130 render : function(){
37131 // add the header.....
37133 Roo.tree.ColumnTree.superclass.render.apply(this);
37135 this.el.addClass('x-column-tree');
37137 this.headers = this.el.createChild(
37138 {cls:'x-tree-headers'},this.innerCt.dom);
37140 var cols = this.columns, c;
37141 var totalWidth = 0;
37143 var len = cols.length;
37144 for(var i = 0; i < len; i++){
37146 totalWidth += c.width;
37147 this.headEls.push(this.headers.createChild({
37148 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37150 cls:'x-tree-hd-text',
37153 style:'width:'+(c.width-this.borderWidth)+'px;'
37156 this.headers.createChild({cls:'x-clear'});
37157 // prevent floats from wrapping when clipped
37158 this.headers.setWidth(totalWidth);
37159 //this.innerCt.setWidth(totalWidth);
37160 this.innerCt.setStyle({ overflow: 'auto' });
37161 this.onResize(this.width, this.height);
37165 onResize : function(w,h)
37170 this.innerCt.setWidth(this.width);
37171 this.innerCt.setHeight(this.height-20);
37174 var cols = this.columns, c;
37175 var totalWidth = 0;
37177 var len = cols.length;
37178 for(var i = 0; i < len; i++){
37180 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37181 // it's the expander..
37182 expEl = this.headEls[i];
37185 totalWidth += c.width;
37189 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37191 this.headers.setWidth(w-20);
37200 * Ext JS Library 1.1.1
37201 * Copyright(c) 2006-2007, Ext JS, LLC.
37203 * Originally Released Under LGPL - original licence link has changed is not relivant.
37206 * <script type="text/javascript">
37210 * @class Roo.menu.Menu
37211 * @extends Roo.util.Observable
37212 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37213 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37215 * Creates a new Menu
37216 * @param {Object} config Configuration options
37218 Roo.menu.Menu = function(config){
37219 Roo.apply(this, config);
37220 this.id = this.id || Roo.id();
37223 * @event beforeshow
37224 * Fires before this menu is displayed
37225 * @param {Roo.menu.Menu} this
37229 * @event beforehide
37230 * Fires before this menu is hidden
37231 * @param {Roo.menu.Menu} this
37236 * Fires after this menu is displayed
37237 * @param {Roo.menu.Menu} this
37242 * Fires after this menu is hidden
37243 * @param {Roo.menu.Menu} this
37248 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37249 * @param {Roo.menu.Menu} this
37250 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37251 * @param {Roo.EventObject} e
37256 * Fires when the mouse is hovering over this menu
37257 * @param {Roo.menu.Menu} this
37258 * @param {Roo.EventObject} e
37259 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37264 * Fires when the mouse exits this menu
37265 * @param {Roo.menu.Menu} this
37266 * @param {Roo.EventObject} e
37267 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37272 * Fires when a menu item contained in this menu is clicked
37273 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37274 * @param {Roo.EventObject} e
37278 if (this.registerMenu) {
37279 Roo.menu.MenuMgr.register(this);
37282 var mis = this.items;
37283 this.items = new Roo.util.MixedCollection();
37285 this.add.apply(this, mis);
37289 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37291 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37295 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37296 * for bottom-right shadow (defaults to "sides")
37300 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37301 * this menu (defaults to "tl-tr?")
37303 subMenuAlign : "tl-tr?",
37305 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37306 * relative to its element of origin (defaults to "tl-bl?")
37308 defaultAlign : "tl-bl?",
37310 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37312 allowOtherMenus : false,
37314 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37316 registerMenu : true,
37321 render : function(){
37325 var el = this.el = new Roo.Layer({
37327 shadow:this.shadow,
37329 parentEl: this.parentEl || document.body,
37333 this.keyNav = new Roo.menu.MenuNav(this);
37336 el.addClass("x-menu-plain");
37339 el.addClass(this.cls);
37341 // generic focus element
37342 this.focusEl = el.createChild({
37343 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37345 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37346 //disabling touch- as it's causing issues ..
37347 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37348 ul.on('click' , this.onClick, this);
37351 ul.on("mouseover", this.onMouseOver, this);
37352 ul.on("mouseout", this.onMouseOut, this);
37353 this.items.each(function(item){
37358 var li = document.createElement("li");
37359 li.className = "x-menu-list-item";
37360 ul.dom.appendChild(li);
37361 item.render(li, this);
37368 autoWidth : function(){
37369 var el = this.el, ul = this.ul;
37373 var w = this.width;
37376 }else if(Roo.isIE){
37377 el.setWidth(this.minWidth);
37378 var t = el.dom.offsetWidth; // force recalc
37379 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37384 delayAutoWidth : function(){
37387 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37389 this.awTask.delay(20);
37394 findTargetItem : function(e){
37395 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37396 if(t && t.menuItemId){
37397 return this.items.get(t.menuItemId);
37402 onClick : function(e){
37403 Roo.log("menu.onClick");
37404 var t = this.findTargetItem(e);
37409 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37410 if(t == this.activeItem && t.shouldDeactivate(e)){
37411 this.activeItem.deactivate();
37412 delete this.activeItem;
37416 this.setActiveItem(t, true);
37424 this.fireEvent("click", this, t, e);
37428 setActiveItem : function(item, autoExpand){
37429 if(item != this.activeItem){
37430 if(this.activeItem){
37431 this.activeItem.deactivate();
37433 this.activeItem = item;
37434 item.activate(autoExpand);
37435 }else if(autoExpand){
37441 tryActivate : function(start, step){
37442 var items = this.items;
37443 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37444 var item = items.get(i);
37445 if(!item.disabled && item.canActivate){
37446 this.setActiveItem(item, false);
37454 onMouseOver : function(e){
37456 if(t = this.findTargetItem(e)){
37457 if(t.canActivate && !t.disabled){
37458 this.setActiveItem(t, true);
37461 this.fireEvent("mouseover", this, e, t);
37465 onMouseOut : function(e){
37467 if(t = this.findTargetItem(e)){
37468 if(t == this.activeItem && t.shouldDeactivate(e)){
37469 this.activeItem.deactivate();
37470 delete this.activeItem;
37473 this.fireEvent("mouseout", this, e, t);
37477 * Read-only. Returns true if the menu is currently displayed, else false.
37480 isVisible : function(){
37481 return this.el && !this.hidden;
37485 * Displays this menu relative to another element
37486 * @param {String/HTMLElement/Roo.Element} element The element to align to
37487 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37488 * the element (defaults to this.defaultAlign)
37489 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37491 show : function(el, pos, parentMenu){
37492 this.parentMenu = parentMenu;
37496 this.fireEvent("beforeshow", this);
37497 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37501 * Displays this menu at a specific xy position
37502 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37503 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37505 showAt : function(xy, parentMenu, /* private: */_e){
37506 this.parentMenu = parentMenu;
37511 this.fireEvent("beforeshow", this);
37512 xy = this.el.adjustForConstraints(xy);
37516 this.hidden = false;
37518 this.fireEvent("show", this);
37521 focus : function(){
37523 this.doFocus.defer(50, this);
37527 doFocus : function(){
37529 this.focusEl.focus();
37534 * Hides this menu and optionally all parent menus
37535 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37537 hide : function(deep){
37538 if(this.el && this.isVisible()){
37539 this.fireEvent("beforehide", this);
37540 if(this.activeItem){
37541 this.activeItem.deactivate();
37542 this.activeItem = null;
37545 this.hidden = true;
37546 this.fireEvent("hide", this);
37548 if(deep === true && this.parentMenu){
37549 this.parentMenu.hide(true);
37554 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37555 * Any of the following are valid:
37557 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37558 * <li>An HTMLElement object which will be converted to a menu item</li>
37559 * <li>A menu item config object that will be created as a new menu item</li>
37560 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37561 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37566 var menu = new Roo.menu.Menu();
37568 // Create a menu item to add by reference
37569 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37571 // Add a bunch of items at once using different methods.
37572 // Only the last item added will be returned.
37573 var item = menu.add(
37574 menuItem, // add existing item by ref
37575 'Dynamic Item', // new TextItem
37576 '-', // new separator
37577 { text: 'Config Item' } // new item by config
37580 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37581 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37584 var a = arguments, l = a.length, item;
37585 for(var i = 0; i < l; i++){
37587 if ((typeof(el) == "object") && el.xtype && el.xns) {
37588 el = Roo.factory(el, Roo.menu);
37591 if(el.render){ // some kind of Item
37592 item = this.addItem(el);
37593 }else if(typeof el == "string"){ // string
37594 if(el == "separator" || el == "-"){
37595 item = this.addSeparator();
37597 item = this.addText(el);
37599 }else if(el.tagName || el.el){ // element
37600 item = this.addElement(el);
37601 }else if(typeof el == "object"){ // must be menu item config?
37602 item = this.addMenuItem(el);
37609 * Returns this menu's underlying {@link Roo.Element} object
37610 * @return {Roo.Element} The element
37612 getEl : function(){
37620 * Adds a separator bar to the menu
37621 * @return {Roo.menu.Item} The menu item that was added
37623 addSeparator : function(){
37624 return this.addItem(new Roo.menu.Separator());
37628 * Adds an {@link Roo.Element} object to the menu
37629 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37630 * @return {Roo.menu.Item} The menu item that was added
37632 addElement : function(el){
37633 return this.addItem(new Roo.menu.BaseItem(el));
37637 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37638 * @param {Roo.menu.Item} item The menu item to add
37639 * @return {Roo.menu.Item} The menu item that was added
37641 addItem : function(item){
37642 this.items.add(item);
37644 var li = document.createElement("li");
37645 li.className = "x-menu-list-item";
37646 this.ul.dom.appendChild(li);
37647 item.render(li, this);
37648 this.delayAutoWidth();
37654 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37655 * @param {Object} config A MenuItem config object
37656 * @return {Roo.menu.Item} The menu item that was added
37658 addMenuItem : function(config){
37659 if(!(config instanceof Roo.menu.Item)){
37660 if(typeof config.checked == "boolean"){ // must be check menu item config?
37661 config = new Roo.menu.CheckItem(config);
37663 config = new Roo.menu.Item(config);
37666 return this.addItem(config);
37670 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37671 * @param {String} text The text to display in the menu item
37672 * @return {Roo.menu.Item} The menu item that was added
37674 addText : function(text){
37675 return this.addItem(new Roo.menu.TextItem({ text : text }));
37679 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37680 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37681 * @param {Roo.menu.Item} item The menu item to add
37682 * @return {Roo.menu.Item} The menu item that was added
37684 insert : function(index, item){
37685 this.items.insert(index, item);
37687 var li = document.createElement("li");
37688 li.className = "x-menu-list-item";
37689 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37690 item.render(li, this);
37691 this.delayAutoWidth();
37697 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37698 * @param {Roo.menu.Item} item The menu item to remove
37700 remove : function(item){
37701 this.items.removeKey(item.id);
37706 * Removes and destroys all items in the menu
37708 removeAll : function(){
37710 while(f = this.items.first()){
37716 // MenuNav is a private utility class used internally by the Menu
37717 Roo.menu.MenuNav = function(menu){
37718 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37719 this.scope = this.menu = menu;
37722 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37723 doRelay : function(e, h){
37724 var k = e.getKey();
37725 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37726 this.menu.tryActivate(0, 1);
37729 return h.call(this.scope || this, e, this.menu);
37732 up : function(e, m){
37733 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37734 m.tryActivate(m.items.length-1, -1);
37738 down : function(e, m){
37739 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37740 m.tryActivate(0, 1);
37744 right : function(e, m){
37746 m.activeItem.expandMenu(true);
37750 left : function(e, m){
37752 if(m.parentMenu && m.parentMenu.activeItem){
37753 m.parentMenu.activeItem.activate();
37757 enter : function(e, m){
37759 e.stopPropagation();
37760 m.activeItem.onClick(e);
37761 m.fireEvent("click", this, m.activeItem);
37767 * Ext JS Library 1.1.1
37768 * Copyright(c) 2006-2007, Ext JS, LLC.
37770 * Originally Released Under LGPL - original licence link has changed is not relivant.
37773 * <script type="text/javascript">
37777 * @class Roo.menu.MenuMgr
37778 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37781 Roo.menu.MenuMgr = function(){
37782 var menus, active, groups = {}, attached = false, lastShow = new Date();
37784 // private - called when first menu is created
37787 active = new Roo.util.MixedCollection();
37788 Roo.get(document).addKeyListener(27, function(){
37789 if(active.length > 0){
37796 function hideAll(){
37797 if(active && active.length > 0){
37798 var c = active.clone();
37799 c.each(function(m){
37806 function onHide(m){
37808 if(active.length < 1){
37809 Roo.get(document).un("mousedown", onMouseDown);
37815 function onShow(m){
37816 var last = active.last();
37817 lastShow = new Date();
37820 Roo.get(document).on("mousedown", onMouseDown);
37824 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37825 m.parentMenu.activeChild = m;
37826 }else if(last && last.isVisible()){
37827 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37832 function onBeforeHide(m){
37834 m.activeChild.hide();
37836 if(m.autoHideTimer){
37837 clearTimeout(m.autoHideTimer);
37838 delete m.autoHideTimer;
37843 function onBeforeShow(m){
37844 var pm = m.parentMenu;
37845 if(!pm && !m.allowOtherMenus){
37847 }else if(pm && pm.activeChild && active != m){
37848 pm.activeChild.hide();
37853 function onMouseDown(e){
37854 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37860 function onBeforeCheck(mi, state){
37862 var g = groups[mi.group];
37863 for(var i = 0, l = g.length; i < l; i++){
37865 g[i].setChecked(false);
37874 * Hides all menus that are currently visible
37876 hideAll : function(){
37881 register : function(menu){
37885 menus[menu.id] = menu;
37886 menu.on("beforehide", onBeforeHide);
37887 menu.on("hide", onHide);
37888 menu.on("beforeshow", onBeforeShow);
37889 menu.on("show", onShow);
37890 var g = menu.group;
37891 if(g && menu.events["checkchange"]){
37895 groups[g].push(menu);
37896 menu.on("checkchange", onCheck);
37901 * Returns a {@link Roo.menu.Menu} object
37902 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37903 * be used to generate and return a new Menu instance.
37905 get : function(menu){
37906 if(typeof menu == "string"){ // menu id
37907 return menus[menu];
37908 }else if(menu.events){ // menu instance
37910 }else if(typeof menu.length == 'number'){ // array of menu items?
37911 return new Roo.menu.Menu({items:menu});
37912 }else{ // otherwise, must be a config
37913 return new Roo.menu.Menu(menu);
37918 unregister : function(menu){
37919 delete menus[menu.id];
37920 menu.un("beforehide", onBeforeHide);
37921 menu.un("hide", onHide);
37922 menu.un("beforeshow", onBeforeShow);
37923 menu.un("show", onShow);
37924 var g = menu.group;
37925 if(g && menu.events["checkchange"]){
37926 groups[g].remove(menu);
37927 menu.un("checkchange", onCheck);
37932 registerCheckable : function(menuItem){
37933 var g = menuItem.group;
37938 groups[g].push(menuItem);
37939 menuItem.on("beforecheckchange", onBeforeCheck);
37944 unregisterCheckable : function(menuItem){
37945 var g = menuItem.group;
37947 groups[g].remove(menuItem);
37948 menuItem.un("beforecheckchange", onBeforeCheck);
37954 * Ext JS Library 1.1.1
37955 * Copyright(c) 2006-2007, Ext JS, LLC.
37957 * Originally Released Under LGPL - original licence link has changed is not relivant.
37960 * <script type="text/javascript">
37965 * @class Roo.menu.BaseItem
37966 * @extends Roo.Component
37967 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37968 * management and base configuration options shared by all menu components.
37970 * Creates a new BaseItem
37971 * @param {Object} config Configuration options
37973 Roo.menu.BaseItem = function(config){
37974 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37979 * Fires when this item is clicked
37980 * @param {Roo.menu.BaseItem} this
37981 * @param {Roo.EventObject} e
37986 * Fires when this item is activated
37987 * @param {Roo.menu.BaseItem} this
37991 * @event deactivate
37992 * Fires when this item is deactivated
37993 * @param {Roo.menu.BaseItem} this
37999 this.on("click", this.handler, this.scope, true);
38003 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38005 * @cfg {Function} handler
38006 * A function that will handle the click event of this menu item (defaults to undefined)
38009 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38011 canActivate : false,
38014 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38019 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38021 activeClass : "x-menu-item-active",
38023 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38025 hideOnClick : true,
38027 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38032 ctype: "Roo.menu.BaseItem",
38035 actionMode : "container",
38038 render : function(container, parentMenu){
38039 this.parentMenu = parentMenu;
38040 Roo.menu.BaseItem.superclass.render.call(this, container);
38041 this.container.menuItemId = this.id;
38045 onRender : function(container, position){
38046 this.el = Roo.get(this.el);
38047 container.dom.appendChild(this.el.dom);
38051 onClick : function(e){
38052 if(!this.disabled && this.fireEvent("click", this, e) !== false
38053 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38054 this.handleClick(e);
38061 activate : function(){
38065 var li = this.container;
38066 li.addClass(this.activeClass);
38067 this.region = li.getRegion().adjust(2, 2, -2, -2);
38068 this.fireEvent("activate", this);
38073 deactivate : function(){
38074 this.container.removeClass(this.activeClass);
38075 this.fireEvent("deactivate", this);
38079 shouldDeactivate : function(e){
38080 return !this.region || !this.region.contains(e.getPoint());
38084 handleClick : function(e){
38085 if(this.hideOnClick){
38086 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38091 expandMenu : function(autoActivate){
38096 hideMenu : function(){
38101 * Ext JS Library 1.1.1
38102 * Copyright(c) 2006-2007, Ext JS, LLC.
38104 * Originally Released Under LGPL - original licence link has changed is not relivant.
38107 * <script type="text/javascript">
38111 * @class Roo.menu.Adapter
38112 * @extends Roo.menu.BaseItem
38113 * 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.
38114 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38116 * Creates a new Adapter
38117 * @param {Object} config Configuration options
38119 Roo.menu.Adapter = function(component, config){
38120 Roo.menu.Adapter.superclass.constructor.call(this, config);
38121 this.component = component;
38123 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38125 canActivate : true,
38128 onRender : function(container, position){
38129 this.component.render(container);
38130 this.el = this.component.getEl();
38134 activate : function(){
38138 this.component.focus();
38139 this.fireEvent("activate", this);
38144 deactivate : function(){
38145 this.fireEvent("deactivate", this);
38149 disable : function(){
38150 this.component.disable();
38151 Roo.menu.Adapter.superclass.disable.call(this);
38155 enable : function(){
38156 this.component.enable();
38157 Roo.menu.Adapter.superclass.enable.call(this);
38161 * Ext JS Library 1.1.1
38162 * Copyright(c) 2006-2007, Ext JS, LLC.
38164 * Originally Released Under LGPL - original licence link has changed is not relivant.
38167 * <script type="text/javascript">
38171 * @class Roo.menu.TextItem
38172 * @extends Roo.menu.BaseItem
38173 * Adds a static text string to a menu, usually used as either a heading or group separator.
38174 * Note: old style constructor with text is still supported.
38177 * Creates a new TextItem
38178 * @param {Object} cfg Configuration
38180 Roo.menu.TextItem = function(cfg){
38181 if (typeof(cfg) == 'string') {
38184 Roo.apply(this,cfg);
38187 Roo.menu.TextItem.superclass.constructor.call(this);
38190 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38192 * @cfg {Boolean} text Text to show on item.
38197 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38199 hideOnClick : false,
38201 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38203 itemCls : "x-menu-text",
38206 onRender : function(){
38207 var s = document.createElement("span");
38208 s.className = this.itemCls;
38209 s.innerHTML = this.text;
38211 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38215 * Ext JS Library 1.1.1
38216 * Copyright(c) 2006-2007, Ext JS, LLC.
38218 * Originally Released Under LGPL - original licence link has changed is not relivant.
38221 * <script type="text/javascript">
38225 * @class Roo.menu.Separator
38226 * @extends Roo.menu.BaseItem
38227 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38228 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38230 * @param {Object} config Configuration options
38232 Roo.menu.Separator = function(config){
38233 Roo.menu.Separator.superclass.constructor.call(this, config);
38236 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38238 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38240 itemCls : "x-menu-sep",
38242 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38244 hideOnClick : false,
38247 onRender : function(li){
38248 var s = document.createElement("span");
38249 s.className = this.itemCls;
38250 s.innerHTML = " ";
38252 li.addClass("x-menu-sep-li");
38253 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38257 * Ext JS Library 1.1.1
38258 * Copyright(c) 2006-2007, Ext JS, LLC.
38260 * Originally Released Under LGPL - original licence link has changed is not relivant.
38263 * <script type="text/javascript">
38266 * @class Roo.menu.Item
38267 * @extends Roo.menu.BaseItem
38268 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38269 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38270 * activation and click handling.
38272 * Creates a new Item
38273 * @param {Object} config Configuration options
38275 Roo.menu.Item = function(config){
38276 Roo.menu.Item.superclass.constructor.call(this, config);
38278 this.menu = Roo.menu.MenuMgr.get(this.menu);
38281 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38284 * @cfg {String} text
38285 * The text to show on the menu item.
38289 * @cfg {String} HTML to render in menu
38290 * The text to show on the menu item (HTML version).
38294 * @cfg {String} icon
38295 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38299 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38301 itemCls : "x-menu-item",
38303 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38305 canActivate : true,
38307 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38310 // doc'd in BaseItem
38314 ctype: "Roo.menu.Item",
38317 onRender : function(container, position){
38318 var el = document.createElement("a");
38319 el.hideFocus = true;
38320 el.unselectable = "on";
38321 el.href = this.href || "#";
38322 if(this.hrefTarget){
38323 el.target = this.hrefTarget;
38325 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38327 var html = this.html.length ? this.html : String.format('{0}',this.text);
38329 el.innerHTML = String.format(
38330 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38331 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38333 Roo.menu.Item.superclass.onRender.call(this, container, position);
38337 * Sets the text to display in this menu item
38338 * @param {String} text The text to display
38339 * @param {Boolean} isHTML true to indicate text is pure html.
38341 setText : function(text, isHTML){
38349 var html = this.html.length ? this.html : String.format('{0}',this.text);
38351 this.el.update(String.format(
38352 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38353 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38354 this.parentMenu.autoWidth();
38359 handleClick : function(e){
38360 if(!this.href){ // if no link defined, stop the event automatically
38363 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38367 activate : function(autoExpand){
38368 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38378 shouldDeactivate : function(e){
38379 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38380 if(this.menu && this.menu.isVisible()){
38381 return !this.menu.getEl().getRegion().contains(e.getPoint());
38389 deactivate : function(){
38390 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38395 expandMenu : function(autoActivate){
38396 if(!this.disabled && this.menu){
38397 clearTimeout(this.hideTimer);
38398 delete this.hideTimer;
38399 if(!this.menu.isVisible() && !this.showTimer){
38400 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38401 }else if (this.menu.isVisible() && autoActivate){
38402 this.menu.tryActivate(0, 1);
38408 deferExpand : function(autoActivate){
38409 delete this.showTimer;
38410 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38412 this.menu.tryActivate(0, 1);
38417 hideMenu : function(){
38418 clearTimeout(this.showTimer);
38419 delete this.showTimer;
38420 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38421 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38426 deferHide : function(){
38427 delete this.hideTimer;
38432 * Ext JS Library 1.1.1
38433 * Copyright(c) 2006-2007, Ext JS, LLC.
38435 * Originally Released Under LGPL - original licence link has changed is not relivant.
38438 * <script type="text/javascript">
38442 * @class Roo.menu.CheckItem
38443 * @extends Roo.menu.Item
38444 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38446 * Creates a new CheckItem
38447 * @param {Object} config Configuration options
38449 Roo.menu.CheckItem = function(config){
38450 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38453 * @event beforecheckchange
38454 * Fires before the checked value is set, providing an opportunity to cancel if needed
38455 * @param {Roo.menu.CheckItem} this
38456 * @param {Boolean} checked The new checked value that will be set
38458 "beforecheckchange" : true,
38460 * @event checkchange
38461 * Fires after the checked value has been set
38462 * @param {Roo.menu.CheckItem} this
38463 * @param {Boolean} checked The checked value that was set
38465 "checkchange" : true
38467 if(this.checkHandler){
38468 this.on('checkchange', this.checkHandler, this.scope);
38471 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38473 * @cfg {String} group
38474 * All check items with the same group name will automatically be grouped into a single-select
38475 * radio button group (defaults to '')
38478 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38480 itemCls : "x-menu-item x-menu-check-item",
38482 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38484 groupClass : "x-menu-group-item",
38487 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38488 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38489 * initialized with checked = true will be rendered as checked.
38494 ctype: "Roo.menu.CheckItem",
38497 onRender : function(c){
38498 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38500 this.el.addClass(this.groupClass);
38502 Roo.menu.MenuMgr.registerCheckable(this);
38504 this.checked = false;
38505 this.setChecked(true, true);
38510 destroy : function(){
38512 Roo.menu.MenuMgr.unregisterCheckable(this);
38514 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38518 * Set the checked state of this item
38519 * @param {Boolean} checked The new checked value
38520 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38522 setChecked : function(state, suppressEvent){
38523 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38524 if(this.container){
38525 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38527 this.checked = state;
38528 if(suppressEvent !== true){
38529 this.fireEvent("checkchange", this, state);
38535 handleClick : function(e){
38536 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38537 this.setChecked(!this.checked);
38539 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38543 * Ext JS Library 1.1.1
38544 * Copyright(c) 2006-2007, Ext JS, LLC.
38546 * Originally Released Under LGPL - original licence link has changed is not relivant.
38549 * <script type="text/javascript">
38553 * @class Roo.menu.DateItem
38554 * @extends Roo.menu.Adapter
38555 * A menu item that wraps the {@link Roo.DatPicker} component.
38557 * Creates a new DateItem
38558 * @param {Object} config Configuration options
38560 Roo.menu.DateItem = function(config){
38561 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38562 /** The Roo.DatePicker object @type Roo.DatePicker */
38563 this.picker = this.component;
38564 this.addEvents({select: true});
38566 this.picker.on("render", function(picker){
38567 picker.getEl().swallowEvent("click");
38568 picker.container.addClass("x-menu-date-item");
38571 this.picker.on("select", this.onSelect, this);
38574 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38576 onSelect : function(picker, date){
38577 this.fireEvent("select", this, date, picker);
38578 Roo.menu.DateItem.superclass.handleClick.call(this);
38582 * Ext JS Library 1.1.1
38583 * Copyright(c) 2006-2007, Ext JS, LLC.
38585 * Originally Released Under LGPL - original licence link has changed is not relivant.
38588 * <script type="text/javascript">
38592 * @class Roo.menu.ColorItem
38593 * @extends Roo.menu.Adapter
38594 * A menu item that wraps the {@link Roo.ColorPalette} component.
38596 * Creates a new ColorItem
38597 * @param {Object} config Configuration options
38599 Roo.menu.ColorItem = function(config){
38600 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38601 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38602 this.palette = this.component;
38603 this.relayEvents(this.palette, ["select"]);
38604 if(this.selectHandler){
38605 this.on('select', this.selectHandler, this.scope);
38608 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38610 * Ext JS Library 1.1.1
38611 * Copyright(c) 2006-2007, Ext JS, LLC.
38613 * Originally Released Under LGPL - original licence link has changed is not relivant.
38616 * <script type="text/javascript">
38621 * @class Roo.menu.DateMenu
38622 * @extends Roo.menu.Menu
38623 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38625 * Creates a new DateMenu
38626 * @param {Object} config Configuration options
38628 Roo.menu.DateMenu = function(config){
38629 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38631 var di = new Roo.menu.DateItem(config);
38634 * The {@link Roo.DatePicker} instance for this DateMenu
38637 this.picker = di.picker;
38640 * @param {DatePicker} picker
38641 * @param {Date} date
38643 this.relayEvents(di, ["select"]);
38644 this.on('beforeshow', function(){
38646 this.picker.hideMonthPicker(false);
38650 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38654 * Ext JS Library 1.1.1
38655 * Copyright(c) 2006-2007, Ext JS, LLC.
38657 * Originally Released Under LGPL - original licence link has changed is not relivant.
38660 * <script type="text/javascript">
38665 * @class Roo.menu.ColorMenu
38666 * @extends Roo.menu.Menu
38667 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38669 * Creates a new ColorMenu
38670 * @param {Object} config Configuration options
38672 Roo.menu.ColorMenu = function(config){
38673 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38675 var ci = new Roo.menu.ColorItem(config);
38678 * The {@link Roo.ColorPalette} instance for this ColorMenu
38679 * @type ColorPalette
38681 this.palette = ci.palette;
38684 * @param {ColorPalette} palette
38685 * @param {String} color
38687 this.relayEvents(ci, ["select"]);
38689 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38691 * Ext JS Library 1.1.1
38692 * Copyright(c) 2006-2007, Ext JS, LLC.
38694 * Originally Released Under LGPL - original licence link has changed is not relivant.
38697 * <script type="text/javascript">
38701 * @class Roo.form.Field
38702 * @extends Roo.BoxComponent
38703 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38705 * Creates a new Field
38706 * @param {Object} config Configuration options
38708 Roo.form.Field = function(config){
38709 Roo.form.Field.superclass.constructor.call(this, config);
38712 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38714 * @cfg {String} fieldLabel Label to use when rendering a form.
38717 * @cfg {String} qtip Mouse over tip
38721 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38723 invalidClass : "x-form-invalid",
38725 * @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")
38727 invalidText : "The value in this field is invalid",
38729 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38731 focusClass : "x-form-focus",
38733 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38734 automatic validation (defaults to "keyup").
38736 validationEvent : "keyup",
38738 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38740 validateOnBlur : true,
38742 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38744 validationDelay : 250,
38746 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38747 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38749 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38751 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38753 fieldClass : "x-form-field",
38755 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38758 ----------- ----------------------------------------------------------------------
38759 qtip Display a quick tip when the user hovers over the field
38760 title Display a default browser title attribute popup
38761 under Add a block div beneath the field containing the error text
38762 side Add an error icon to the right of the field with a popup on hover
38763 [element id] Add the error text directly to the innerHTML of the specified element
38766 msgTarget : 'qtip',
38768 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38773 * @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.
38778 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38783 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38785 inputType : undefined,
38788 * @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).
38790 tabIndex : undefined,
38793 isFormField : true,
38798 * @property {Roo.Element} fieldEl
38799 * Element Containing the rendered Field (with label etc.)
38802 * @cfg {Mixed} value A value to initialize this field with.
38807 * @cfg {String} name The field's HTML name attribute.
38810 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38813 loadedValue : false,
38817 initComponent : function(){
38818 Roo.form.Field.superclass.initComponent.call(this);
38822 * Fires when this field receives input focus.
38823 * @param {Roo.form.Field} this
38828 * Fires when this field loses input focus.
38829 * @param {Roo.form.Field} this
38833 * @event specialkey
38834 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38835 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38836 * @param {Roo.form.Field} this
38837 * @param {Roo.EventObject} e The event object
38842 * Fires just before the field blurs if the field value has changed.
38843 * @param {Roo.form.Field} this
38844 * @param {Mixed} newValue The new value
38845 * @param {Mixed} oldValue The original value
38850 * Fires after the field has been marked as invalid.
38851 * @param {Roo.form.Field} this
38852 * @param {String} msg The validation message
38857 * Fires after the field has been validated with no errors.
38858 * @param {Roo.form.Field} this
38863 * Fires after the key up
38864 * @param {Roo.form.Field} this
38865 * @param {Roo.EventObject} e The event Object
38872 * Returns the name attribute of the field if available
38873 * @return {String} name The field name
38875 getName: function(){
38876 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38880 onRender : function(ct, position){
38881 Roo.form.Field.superclass.onRender.call(this, ct, position);
38883 var cfg = this.getAutoCreate();
38885 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38887 if (!cfg.name.length) {
38890 if(this.inputType){
38891 cfg.type = this.inputType;
38893 this.el = ct.createChild(cfg, position);
38895 var type = this.el.dom.type;
38897 if(type == 'password'){
38900 this.el.addClass('x-form-'+type);
38903 this.el.dom.readOnly = true;
38905 if(this.tabIndex !== undefined){
38906 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38909 this.el.addClass([this.fieldClass, this.cls]);
38914 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38915 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38916 * @return {Roo.form.Field} this
38918 applyTo : function(target){
38919 this.allowDomMove = false;
38920 this.el = Roo.get(target);
38921 this.render(this.el.dom.parentNode);
38926 initValue : function(){
38927 if(this.value !== undefined){
38928 this.setValue(this.value);
38929 }else if(this.el.dom.value.length > 0){
38930 this.setValue(this.el.dom.value);
38935 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38936 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38938 isDirty : function() {
38939 if(this.disabled) {
38942 return String(this.getValue()) !== String(this.originalValue);
38946 * stores the current value in loadedValue
38948 resetHasChanged : function()
38950 this.loadedValue = String(this.getValue());
38953 * checks the current value against the 'loaded' value.
38954 * Note - will return false if 'resetHasChanged' has not been called first.
38956 hasChanged : function()
38958 if(this.disabled || this.readOnly) {
38961 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38967 afterRender : function(){
38968 Roo.form.Field.superclass.afterRender.call(this);
38973 fireKey : function(e){
38974 //Roo.log('field ' + e.getKey());
38975 if(e.isNavKeyPress()){
38976 this.fireEvent("specialkey", this, e);
38981 * Resets the current field value to the originally loaded value and clears any validation messages
38983 reset : function(){
38984 this.setValue(this.resetValue);
38985 this.originalValue = this.getValue();
38986 this.clearInvalid();
38990 initEvents : function(){
38991 // safari killled keypress - so keydown is now used..
38992 this.el.on("keydown" , this.fireKey, this);
38993 this.el.on("focus", this.onFocus, this);
38994 this.el.on("blur", this.onBlur, this);
38995 this.el.relayEvent('keyup', this);
38997 // reference to original value for reset
38998 this.originalValue = this.getValue();
38999 this.resetValue = this.getValue();
39003 onFocus : function(){
39004 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39005 this.el.addClass(this.focusClass);
39007 if(!this.hasFocus){
39008 this.hasFocus = true;
39009 this.startValue = this.getValue();
39010 this.fireEvent("focus", this);
39014 beforeBlur : Roo.emptyFn,
39017 onBlur : function(){
39019 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39020 this.el.removeClass(this.focusClass);
39022 this.hasFocus = false;
39023 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39026 var v = this.getValue();
39027 if(String(v) !== String(this.startValue)){
39028 this.fireEvent('change', this, v, this.startValue);
39030 this.fireEvent("blur", this);
39034 * Returns whether or not the field value is currently valid
39035 * @param {Boolean} preventMark True to disable marking the field invalid
39036 * @return {Boolean} True if the value is valid, else false
39038 isValid : function(preventMark){
39042 var restore = this.preventMark;
39043 this.preventMark = preventMark === true;
39044 var v = this.validateValue(this.processValue(this.getRawValue()));
39045 this.preventMark = restore;
39050 * Validates the field value
39051 * @return {Boolean} True if the value is valid, else false
39053 validate : function(){
39054 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39055 this.clearInvalid();
39061 processValue : function(value){
39066 // Subclasses should provide the validation implementation by overriding this
39067 validateValue : function(value){
39072 * Mark this field as invalid
39073 * @param {String} msg The validation message
39075 markInvalid : function(msg){
39076 if(!this.rendered || this.preventMark){ // not rendered
39080 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39082 obj.el.addClass(this.invalidClass);
39083 msg = msg || this.invalidText;
39084 switch(this.msgTarget){
39086 obj.el.dom.qtip = msg;
39087 obj.el.dom.qclass = 'x-form-invalid-tip';
39088 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39089 Roo.QuickTips.enable();
39093 this.el.dom.title = msg;
39097 var elp = this.el.findParent('.x-form-element', 5, true);
39098 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39099 this.errorEl.setWidth(elp.getWidth(true)-20);
39101 this.errorEl.update(msg);
39102 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39105 if(!this.errorIcon){
39106 var elp = this.el.findParent('.x-form-element', 5, true);
39107 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39109 this.alignErrorIcon();
39110 this.errorIcon.dom.qtip = msg;
39111 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39112 this.errorIcon.show();
39113 this.on('resize', this.alignErrorIcon, this);
39116 var t = Roo.getDom(this.msgTarget);
39118 t.style.display = this.msgDisplay;
39121 this.fireEvent('invalid', this, msg);
39125 alignErrorIcon : function(){
39126 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39130 * Clear any invalid styles/messages for this field
39132 clearInvalid : function(){
39133 if(!this.rendered || this.preventMark){ // not rendered
39136 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39138 obj.el.removeClass(this.invalidClass);
39139 switch(this.msgTarget){
39141 obj.el.dom.qtip = '';
39144 this.el.dom.title = '';
39148 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39152 if(this.errorIcon){
39153 this.errorIcon.dom.qtip = '';
39154 this.errorIcon.hide();
39155 this.un('resize', this.alignErrorIcon, this);
39159 var t = Roo.getDom(this.msgTarget);
39161 t.style.display = 'none';
39164 this.fireEvent('valid', this);
39168 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39169 * @return {Mixed} value The field value
39171 getRawValue : function(){
39172 var v = this.el.getValue();
39178 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39179 * @return {Mixed} value The field value
39181 getValue : function(){
39182 var v = this.el.getValue();
39188 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39189 * @param {Mixed} value The value to set
39191 setRawValue : function(v){
39192 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39196 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39197 * @param {Mixed} value The value to set
39199 setValue : function(v){
39202 this.el.dom.value = (v === null || v === undefined ? '' : v);
39207 adjustSize : function(w, h){
39208 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39209 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39213 adjustWidth : function(tag, w){
39214 tag = tag.toLowerCase();
39215 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39216 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39217 if(tag == 'input'){
39220 if(tag == 'textarea'){
39223 }else if(Roo.isOpera){
39224 if(tag == 'input'){
39227 if(tag == 'textarea'){
39237 // anything other than normal should be considered experimental
39238 Roo.form.Field.msgFx = {
39240 show: function(msgEl, f){
39241 msgEl.setDisplayed('block');
39244 hide : function(msgEl, f){
39245 msgEl.setDisplayed(false).update('');
39250 show: function(msgEl, f){
39251 msgEl.slideIn('t', {stopFx:true});
39254 hide : function(msgEl, f){
39255 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39260 show: function(msgEl, f){
39261 msgEl.fixDisplay();
39262 msgEl.alignTo(f.el, 'tl-tr');
39263 msgEl.slideIn('l', {stopFx:true});
39266 hide : function(msgEl, f){
39267 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39272 * Ext JS Library 1.1.1
39273 * Copyright(c) 2006-2007, Ext JS, LLC.
39275 * Originally Released Under LGPL - original licence link has changed is not relivant.
39278 * <script type="text/javascript">
39283 * @class Roo.form.TextField
39284 * @extends Roo.form.Field
39285 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39286 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39288 * Creates a new TextField
39289 * @param {Object} config Configuration options
39291 Roo.form.TextField = function(config){
39292 Roo.form.TextField.superclass.constructor.call(this, config);
39296 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39297 * according to the default logic, but this event provides a hook for the developer to apply additional
39298 * logic at runtime to resize the field if needed.
39299 * @param {Roo.form.Field} this This text field
39300 * @param {Number} width The new field width
39306 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39308 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39312 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39316 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39320 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39324 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39328 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39330 disableKeyFilter : false,
39332 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39336 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39340 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39342 maxLength : Number.MAX_VALUE,
39344 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39346 minLengthText : "The minimum length for this field is {0}",
39348 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39350 maxLengthText : "The maximum length for this field is {0}",
39352 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39354 selectOnFocus : false,
39356 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39358 blankText : "This field is required",
39360 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39361 * If available, this function will be called only after the basic validators all return true, and will be passed the
39362 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39366 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39367 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39368 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39372 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39376 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39382 initEvents : function()
39384 if (this.emptyText) {
39385 this.el.attr('placeholder', this.emptyText);
39388 Roo.form.TextField.superclass.initEvents.call(this);
39389 if(this.validationEvent == 'keyup'){
39390 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39391 this.el.on('keyup', this.filterValidation, this);
39393 else if(this.validationEvent !== false){
39394 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39397 if(this.selectOnFocus){
39398 this.on("focus", this.preFocus, this);
39401 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39402 this.el.on("keypress", this.filterKeys, this);
39405 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39406 this.el.on("click", this.autoSize, this);
39408 if(this.el.is('input[type=password]') && Roo.isSafari){
39409 this.el.on('keydown', this.SafariOnKeyDown, this);
39413 processValue : function(value){
39414 if(this.stripCharsRe){
39415 var newValue = value.replace(this.stripCharsRe, '');
39416 if(newValue !== value){
39417 this.setRawValue(newValue);
39424 filterValidation : function(e){
39425 if(!e.isNavKeyPress()){
39426 this.validationTask.delay(this.validationDelay);
39431 onKeyUp : function(e){
39432 if(!e.isNavKeyPress()){
39438 * Resets the current field value to the originally-loaded value and clears any validation messages.
39441 reset : function(){
39442 Roo.form.TextField.superclass.reset.call(this);
39448 preFocus : function(){
39450 if(this.selectOnFocus){
39451 this.el.dom.select();
39457 filterKeys : function(e){
39458 var k = e.getKey();
39459 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39462 var c = e.getCharCode(), cc = String.fromCharCode(c);
39463 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39466 if(!this.maskRe.test(cc)){
39471 setValue : function(v){
39473 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39479 * Validates a value according to the field's validation rules and marks the field as invalid
39480 * if the validation fails
39481 * @param {Mixed} value The value to validate
39482 * @return {Boolean} True if the value is valid, else false
39484 validateValue : function(value){
39485 if(value.length < 1) { // if it's blank
39486 if(this.allowBlank){
39487 this.clearInvalid();
39490 this.markInvalid(this.blankText);
39494 if(value.length < this.minLength){
39495 this.markInvalid(String.format(this.minLengthText, this.minLength));
39498 if(value.length > this.maxLength){
39499 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39503 var vt = Roo.form.VTypes;
39504 if(!vt[this.vtype](value, this)){
39505 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39509 if(typeof this.validator == "function"){
39510 var msg = this.validator(value);
39512 this.markInvalid(msg);
39516 if(this.regex && !this.regex.test(value)){
39517 this.markInvalid(this.regexText);
39524 * Selects text in this field
39525 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39526 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39528 selectText : function(start, end){
39529 var v = this.getRawValue();
39531 start = start === undefined ? 0 : start;
39532 end = end === undefined ? v.length : end;
39533 var d = this.el.dom;
39534 if(d.setSelectionRange){
39535 d.setSelectionRange(start, end);
39536 }else if(d.createTextRange){
39537 var range = d.createTextRange();
39538 range.moveStart("character", start);
39539 range.moveEnd("character", v.length-end);
39546 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39547 * This only takes effect if grow = true, and fires the autosize event.
39549 autoSize : function(){
39550 if(!this.grow || !this.rendered){
39554 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39557 var v = el.dom.value;
39558 var d = document.createElement('div');
39559 d.appendChild(document.createTextNode(v));
39563 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39564 this.el.setWidth(w);
39565 this.fireEvent("autosize", this, w);
39569 SafariOnKeyDown : function(event)
39571 // this is a workaround for a password hang bug on chrome/ webkit.
39573 var isSelectAll = false;
39575 if(this.el.dom.selectionEnd > 0){
39576 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39578 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39579 event.preventDefault();
39584 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39586 event.preventDefault();
39587 // this is very hacky as keydown always get's upper case.
39589 var cc = String.fromCharCode(event.getCharCode());
39592 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39600 * Ext JS Library 1.1.1
39601 * Copyright(c) 2006-2007, Ext JS, LLC.
39603 * Originally Released Under LGPL - original licence link has changed is not relivant.
39606 * <script type="text/javascript">
39610 * @class Roo.form.Hidden
39611 * @extends Roo.form.TextField
39612 * Simple Hidden element used on forms
39614 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39617 * Creates a new Hidden form element.
39618 * @param {Object} config Configuration options
39623 // easy hidden field...
39624 Roo.form.Hidden = function(config){
39625 Roo.form.Hidden.superclass.constructor.call(this, config);
39628 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39630 inputType: 'hidden',
39633 labelSeparator: '',
39635 itemCls : 'x-form-item-display-none'
39643 * Ext JS Library 1.1.1
39644 * Copyright(c) 2006-2007, Ext JS, LLC.
39646 * Originally Released Under LGPL - original licence link has changed is not relivant.
39649 * <script type="text/javascript">
39653 * @class Roo.form.TriggerField
39654 * @extends Roo.form.TextField
39655 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39656 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39657 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39658 * for which you can provide a custom implementation. For example:
39660 var trigger = new Roo.form.TriggerField();
39661 trigger.onTriggerClick = myTriggerFn;
39662 trigger.applyTo('my-field');
39665 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39666 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39667 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39668 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39670 * Create a new TriggerField.
39671 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39672 * to the base TextField)
39674 Roo.form.TriggerField = function(config){
39675 this.mimicing = false;
39676 Roo.form.TriggerField.superclass.constructor.call(this, config);
39679 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39681 * @cfg {String} triggerClass A CSS class to apply to the trigger
39684 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39685 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39687 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39689 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39693 /** @cfg {Boolean} grow @hide */
39694 /** @cfg {Number} growMin @hide */
39695 /** @cfg {Number} growMax @hide */
39701 autoSize: Roo.emptyFn,
39705 deferHeight : true,
39708 actionMode : 'wrap',
39710 onResize : function(w, h){
39711 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39712 if(typeof w == 'number'){
39713 var x = w - this.trigger.getWidth();
39714 this.el.setWidth(this.adjustWidth('input', x));
39715 this.trigger.setStyle('left', x+'px');
39720 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39723 getResizeEl : function(){
39728 getPositionEl : function(){
39733 alignErrorIcon : function(){
39734 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39738 onRender : function(ct, position){
39739 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39740 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39741 this.trigger = this.wrap.createChild(this.triggerConfig ||
39742 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39743 if(this.hideTrigger){
39744 this.trigger.setDisplayed(false);
39746 this.initTrigger();
39748 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39753 initTrigger : function(){
39754 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39755 this.trigger.addClassOnOver('x-form-trigger-over');
39756 this.trigger.addClassOnClick('x-form-trigger-click');
39760 onDestroy : function(){
39762 this.trigger.removeAllListeners();
39763 this.trigger.remove();
39766 this.wrap.remove();
39768 Roo.form.TriggerField.superclass.onDestroy.call(this);
39772 onFocus : function(){
39773 Roo.form.TriggerField.superclass.onFocus.call(this);
39774 if(!this.mimicing){
39775 this.wrap.addClass('x-trigger-wrap-focus');
39776 this.mimicing = true;
39777 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39778 if(this.monitorTab){
39779 this.el.on("keydown", this.checkTab, this);
39785 checkTab : function(e){
39786 if(e.getKey() == e.TAB){
39787 this.triggerBlur();
39792 onBlur : function(){
39797 mimicBlur : function(e, t){
39798 if(!this.wrap.contains(t) && this.validateBlur()){
39799 this.triggerBlur();
39804 triggerBlur : function(){
39805 this.mimicing = false;
39806 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39807 if(this.monitorTab){
39808 this.el.un("keydown", this.checkTab, this);
39810 this.wrap.removeClass('x-trigger-wrap-focus');
39811 Roo.form.TriggerField.superclass.onBlur.call(this);
39815 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39816 validateBlur : function(e, t){
39821 onDisable : function(){
39822 Roo.form.TriggerField.superclass.onDisable.call(this);
39824 this.wrap.addClass('x-item-disabled');
39829 onEnable : function(){
39830 Roo.form.TriggerField.superclass.onEnable.call(this);
39832 this.wrap.removeClass('x-item-disabled');
39837 onShow : function(){
39838 var ae = this.getActionEl();
39841 ae.dom.style.display = '';
39842 ae.dom.style.visibility = 'visible';
39848 onHide : function(){
39849 var ae = this.getActionEl();
39850 ae.dom.style.display = 'none';
39854 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39855 * by an implementing function.
39857 * @param {EventObject} e
39859 onTriggerClick : Roo.emptyFn
39862 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39863 // to be extended by an implementing class. For an example of implementing this class, see the custom
39864 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39865 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39866 initComponent : function(){
39867 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39869 this.triggerConfig = {
39870 tag:'span', cls:'x-form-twin-triggers', cn:[
39871 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39872 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39876 getTrigger : function(index){
39877 return this.triggers[index];
39880 initTrigger : function(){
39881 var ts = this.trigger.select('.x-form-trigger', true);
39882 this.wrap.setStyle('overflow', 'hidden');
39883 var triggerField = this;
39884 ts.each(function(t, all, index){
39885 t.hide = function(){
39886 var w = triggerField.wrap.getWidth();
39887 this.dom.style.display = 'none';
39888 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39890 t.show = function(){
39891 var w = triggerField.wrap.getWidth();
39892 this.dom.style.display = '';
39893 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39895 var triggerIndex = 'Trigger'+(index+1);
39897 if(this['hide'+triggerIndex]){
39898 t.dom.style.display = 'none';
39900 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39901 t.addClassOnOver('x-form-trigger-over');
39902 t.addClassOnClick('x-form-trigger-click');
39904 this.triggers = ts.elements;
39907 onTrigger1Click : Roo.emptyFn,
39908 onTrigger2Click : Roo.emptyFn
39911 * Ext JS Library 1.1.1
39912 * Copyright(c) 2006-2007, Ext JS, LLC.
39914 * Originally Released Under LGPL - original licence link has changed is not relivant.
39917 * <script type="text/javascript">
39921 * @class Roo.form.TextArea
39922 * @extends Roo.form.TextField
39923 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39924 * support for auto-sizing.
39926 * Creates a new TextArea
39927 * @param {Object} config Configuration options
39929 Roo.form.TextArea = function(config){
39930 Roo.form.TextArea.superclass.constructor.call(this, config);
39931 // these are provided exchanges for backwards compat
39932 // minHeight/maxHeight were replaced by growMin/growMax to be
39933 // compatible with TextField growing config values
39934 if(this.minHeight !== undefined){
39935 this.growMin = this.minHeight;
39937 if(this.maxHeight !== undefined){
39938 this.growMax = this.maxHeight;
39942 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39944 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39948 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39952 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39953 * in the field (equivalent to setting overflow: hidden, defaults to false)
39955 preventScrollbars: false,
39957 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39958 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39962 onRender : function(ct, position){
39964 this.defaultAutoCreate = {
39966 style:"width:300px;height:60px;",
39967 autocomplete: "new-password"
39970 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39972 this.textSizeEl = Roo.DomHelper.append(document.body, {
39973 tag: "pre", cls: "x-form-grow-sizer"
39975 if(this.preventScrollbars){
39976 this.el.setStyle("overflow", "hidden");
39978 this.el.setHeight(this.growMin);
39982 onDestroy : function(){
39983 if(this.textSizeEl){
39984 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39986 Roo.form.TextArea.superclass.onDestroy.call(this);
39990 onKeyUp : function(e){
39991 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39997 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39998 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40000 autoSize : function(){
40001 if(!this.grow || !this.textSizeEl){
40005 var v = el.dom.value;
40006 var ts = this.textSizeEl;
40009 ts.appendChild(document.createTextNode(v));
40012 Roo.fly(ts).setWidth(this.el.getWidth());
40014 v = "  ";
40017 v = v.replace(/\n/g, '<p> </p>');
40019 v += " \n ";
40022 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40023 if(h != this.lastHeight){
40024 this.lastHeight = h;
40025 this.el.setHeight(h);
40026 this.fireEvent("autosize", this, h);
40031 * Ext JS Library 1.1.1
40032 * Copyright(c) 2006-2007, Ext JS, LLC.
40034 * Originally Released Under LGPL - original licence link has changed is not relivant.
40037 * <script type="text/javascript">
40042 * @class Roo.form.NumberField
40043 * @extends Roo.form.TextField
40044 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40046 * Creates a new NumberField
40047 * @param {Object} config Configuration options
40049 Roo.form.NumberField = function(config){
40050 Roo.form.NumberField.superclass.constructor.call(this, config);
40053 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40055 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40057 fieldClass: "x-form-field x-form-num-field",
40059 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40061 allowDecimals : true,
40063 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40065 decimalSeparator : ".",
40067 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40069 decimalPrecision : 2,
40071 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40073 allowNegative : true,
40075 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40077 minValue : Number.NEGATIVE_INFINITY,
40079 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40081 maxValue : Number.MAX_VALUE,
40083 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40085 minText : "The minimum value for this field is {0}",
40087 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40089 maxText : "The maximum value for this field is {0}",
40091 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40092 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40094 nanText : "{0} is not a valid number",
40097 initEvents : function(){
40098 Roo.form.NumberField.superclass.initEvents.call(this);
40099 var allowed = "0123456789";
40100 if(this.allowDecimals){
40101 allowed += this.decimalSeparator;
40103 if(this.allowNegative){
40106 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40107 var keyPress = function(e){
40108 var k = e.getKey();
40109 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40112 var c = e.getCharCode();
40113 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40117 this.el.on("keypress", keyPress, this);
40121 validateValue : function(value){
40122 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40125 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40128 var num = this.parseValue(value);
40130 this.markInvalid(String.format(this.nanText, value));
40133 if(num < this.minValue){
40134 this.markInvalid(String.format(this.minText, this.minValue));
40137 if(num > this.maxValue){
40138 this.markInvalid(String.format(this.maxText, this.maxValue));
40144 getValue : function(){
40145 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40149 parseValue : function(value){
40150 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40151 return isNaN(value) ? '' : value;
40155 fixPrecision : function(value){
40156 var nan = isNaN(value);
40157 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40158 return nan ? '' : value;
40160 return parseFloat(value).toFixed(this.decimalPrecision);
40163 setValue : function(v){
40164 v = this.fixPrecision(v);
40165 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40169 decimalPrecisionFcn : function(v){
40170 return Math.floor(v);
40173 beforeBlur : function(){
40174 var v = this.parseValue(this.getRawValue());
40181 * Ext JS Library 1.1.1
40182 * Copyright(c) 2006-2007, Ext JS, LLC.
40184 * Originally Released Under LGPL - original licence link has changed is not relivant.
40187 * <script type="text/javascript">
40191 * @class Roo.form.DateField
40192 * @extends Roo.form.TriggerField
40193 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40195 * Create a new DateField
40196 * @param {Object} config
40198 Roo.form.DateField = function(config){
40199 Roo.form.DateField.superclass.constructor.call(this, config);
40205 * Fires when a date is selected
40206 * @param {Roo.form.DateField} combo This combo box
40207 * @param {Date} date The date selected
40214 if(typeof this.minValue == "string") {
40215 this.minValue = this.parseDate(this.minValue);
40217 if(typeof this.maxValue == "string") {
40218 this.maxValue = this.parseDate(this.maxValue);
40220 this.ddMatch = null;
40221 if(this.disabledDates){
40222 var dd = this.disabledDates;
40224 for(var i = 0; i < dd.length; i++){
40226 if(i != dd.length-1) {
40230 this.ddMatch = new RegExp(re + ")");
40234 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40236 * @cfg {String} format
40237 * The default date format string which can be overriden for localization support. The format must be
40238 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40242 * @cfg {String} altFormats
40243 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40244 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40246 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40248 * @cfg {Array} disabledDays
40249 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40251 disabledDays : null,
40253 * @cfg {String} disabledDaysText
40254 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40256 disabledDaysText : "Disabled",
40258 * @cfg {Array} disabledDates
40259 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40260 * expression so they are very powerful. Some examples:
40262 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40263 * <li>["03/08", "09/16"] would disable those days for every year</li>
40264 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40265 * <li>["03/../2006"] would disable every day in March 2006</li>
40266 * <li>["^03"] would disable every day in every March</li>
40268 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40269 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40271 disabledDates : null,
40273 * @cfg {String} disabledDatesText
40274 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40276 disabledDatesText : "Disabled",
40278 * @cfg {Date/String} minValue
40279 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40280 * valid format (defaults to null).
40284 * @cfg {Date/String} maxValue
40285 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40286 * valid format (defaults to null).
40290 * @cfg {String} minText
40291 * The error text to display when the date in the cell is before minValue (defaults to
40292 * 'The date in this field must be after {minValue}').
40294 minText : "The date in this field must be equal to or after {0}",
40296 * @cfg {String} maxText
40297 * The error text to display when the date in the cell is after maxValue (defaults to
40298 * 'The date in this field must be before {maxValue}').
40300 maxText : "The date in this field must be equal to or before {0}",
40302 * @cfg {String} invalidText
40303 * The error text to display when the date in the field is invalid (defaults to
40304 * '{value} is not a valid date - it must be in the format {format}').
40306 invalidText : "{0} is not a valid date - it must be in the format {1}",
40308 * @cfg {String} triggerClass
40309 * An additional CSS class used to style the trigger button. The trigger will always get the
40310 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40311 * which displays a calendar icon).
40313 triggerClass : 'x-form-date-trigger',
40317 * @cfg {Boolean} useIso
40318 * if enabled, then the date field will use a hidden field to store the
40319 * real value as iso formated date. default (false)
40323 * @cfg {String/Object} autoCreate
40324 * A DomHelper element spec, or true for a default element spec (defaults to
40325 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40328 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40331 hiddenField: false,
40333 onRender : function(ct, position)
40335 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40337 //this.el.dom.removeAttribute('name');
40338 Roo.log("Changing name?");
40339 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40340 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40342 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40343 // prevent input submission
40344 this.hiddenName = this.name;
40351 validateValue : function(value)
40353 value = this.formatDate(value);
40354 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40355 Roo.log('super failed');
40358 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40361 var svalue = value;
40362 value = this.parseDate(value);
40364 Roo.log('parse date failed' + svalue);
40365 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40368 var time = value.getTime();
40369 if(this.minValue && time < this.minValue.getTime()){
40370 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40373 if(this.maxValue && time > this.maxValue.getTime()){
40374 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40377 if(this.disabledDays){
40378 var day = value.getDay();
40379 for(var i = 0; i < this.disabledDays.length; i++) {
40380 if(day === this.disabledDays[i]){
40381 this.markInvalid(this.disabledDaysText);
40386 var fvalue = this.formatDate(value);
40387 if(this.ddMatch && this.ddMatch.test(fvalue)){
40388 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40395 // Provides logic to override the default TriggerField.validateBlur which just returns true
40396 validateBlur : function(){
40397 return !this.menu || !this.menu.isVisible();
40400 getName: function()
40402 // returns hidden if it's set..
40403 if (!this.rendered) {return ''};
40404 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40409 * Returns the current date value of the date field.
40410 * @return {Date} The date value
40412 getValue : function(){
40414 return this.hiddenField ?
40415 this.hiddenField.value :
40416 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40420 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40421 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40422 * (the default format used is "m/d/y").
40425 //All of these calls set the same date value (May 4, 2006)
40427 //Pass a date object:
40428 var dt = new Date('5/4/06');
40429 dateField.setValue(dt);
40431 //Pass a date string (default format):
40432 dateField.setValue('5/4/06');
40434 //Pass a date string (custom format):
40435 dateField.format = 'Y-m-d';
40436 dateField.setValue('2006-5-4');
40438 * @param {String/Date} date The date or valid date string
40440 setValue : function(date){
40441 if (this.hiddenField) {
40442 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40444 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40445 // make sure the value field is always stored as a date..
40446 this.value = this.parseDate(date);
40452 parseDate : function(value){
40453 if(!value || value instanceof Date){
40456 var v = Date.parseDate(value, this.format);
40457 if (!v && this.useIso) {
40458 v = Date.parseDate(value, 'Y-m-d');
40460 if(!v && this.altFormats){
40461 if(!this.altFormatsArray){
40462 this.altFormatsArray = this.altFormats.split("|");
40464 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40465 v = Date.parseDate(value, this.altFormatsArray[i]);
40472 formatDate : function(date, fmt){
40473 return (!date || !(date instanceof Date)) ?
40474 date : date.dateFormat(fmt || this.format);
40479 select: function(m, d){
40482 this.fireEvent('select', this, d);
40484 show : function(){ // retain focus styling
40488 this.focus.defer(10, this);
40489 var ml = this.menuListeners;
40490 this.menu.un("select", ml.select, this);
40491 this.menu.un("show", ml.show, this);
40492 this.menu.un("hide", ml.hide, this);
40497 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40498 onTriggerClick : function(){
40502 if(this.menu == null){
40503 this.menu = new Roo.menu.DateMenu();
40505 Roo.apply(this.menu.picker, {
40506 showClear: this.allowBlank,
40507 minDate : this.minValue,
40508 maxDate : this.maxValue,
40509 disabledDatesRE : this.ddMatch,
40510 disabledDatesText : this.disabledDatesText,
40511 disabledDays : this.disabledDays,
40512 disabledDaysText : this.disabledDaysText,
40513 format : this.useIso ? 'Y-m-d' : this.format,
40514 minText : String.format(this.minText, this.formatDate(this.minValue)),
40515 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40517 this.menu.on(Roo.apply({}, this.menuListeners, {
40520 this.menu.picker.setValue(this.getValue() || new Date());
40521 this.menu.show(this.el, "tl-bl?");
40524 beforeBlur : function(){
40525 var v = this.parseDate(this.getRawValue());
40535 isDirty : function() {
40536 if(this.disabled) {
40540 if(typeof(this.startValue) === 'undefined'){
40544 return String(this.getValue()) !== String(this.startValue);
40549 * Ext JS Library 1.1.1
40550 * Copyright(c) 2006-2007, Ext JS, LLC.
40552 * Originally Released Under LGPL - original licence link has changed is not relivant.
40555 * <script type="text/javascript">
40559 * @class Roo.form.MonthField
40560 * @extends Roo.form.TriggerField
40561 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40563 * Create a new MonthField
40564 * @param {Object} config
40566 Roo.form.MonthField = function(config){
40568 Roo.form.MonthField.superclass.constructor.call(this, config);
40574 * Fires when a date is selected
40575 * @param {Roo.form.MonthFieeld} combo This combo box
40576 * @param {Date} date The date selected
40583 if(typeof this.minValue == "string") {
40584 this.minValue = this.parseDate(this.minValue);
40586 if(typeof this.maxValue == "string") {
40587 this.maxValue = this.parseDate(this.maxValue);
40589 this.ddMatch = null;
40590 if(this.disabledDates){
40591 var dd = this.disabledDates;
40593 for(var i = 0; i < dd.length; i++){
40595 if(i != dd.length-1) {
40599 this.ddMatch = new RegExp(re + ")");
40603 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40605 * @cfg {String} format
40606 * The default date format string which can be overriden for localization support. The format must be
40607 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40611 * @cfg {String} altFormats
40612 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40613 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40615 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40617 * @cfg {Array} disabledDays
40618 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40620 disabledDays : [0,1,2,3,4,5,6],
40622 * @cfg {String} disabledDaysText
40623 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40625 disabledDaysText : "Disabled",
40627 * @cfg {Array} disabledDates
40628 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40629 * expression so they are very powerful. Some examples:
40631 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40632 * <li>["03/08", "09/16"] would disable those days for every year</li>
40633 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40634 * <li>["03/../2006"] would disable every day in March 2006</li>
40635 * <li>["^03"] would disable every day in every March</li>
40637 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40638 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40640 disabledDates : null,
40642 * @cfg {String} disabledDatesText
40643 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40645 disabledDatesText : "Disabled",
40647 * @cfg {Date/String} minValue
40648 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40649 * valid format (defaults to null).
40653 * @cfg {Date/String} maxValue
40654 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40655 * valid format (defaults to null).
40659 * @cfg {String} minText
40660 * The error text to display when the date in the cell is before minValue (defaults to
40661 * 'The date in this field must be after {minValue}').
40663 minText : "The date in this field must be equal to or after {0}",
40665 * @cfg {String} maxTextf
40666 * The error text to display when the date in the cell is after maxValue (defaults to
40667 * 'The date in this field must be before {maxValue}').
40669 maxText : "The date in this field must be equal to or before {0}",
40671 * @cfg {String} invalidText
40672 * The error text to display when the date in the field is invalid (defaults to
40673 * '{value} is not a valid date - it must be in the format {format}').
40675 invalidText : "{0} is not a valid date - it must be in the format {1}",
40677 * @cfg {String} triggerClass
40678 * An additional CSS class used to style the trigger button. The trigger will always get the
40679 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40680 * which displays a calendar icon).
40682 triggerClass : 'x-form-date-trigger',
40686 * @cfg {Boolean} useIso
40687 * if enabled, then the date field will use a hidden field to store the
40688 * real value as iso formated date. default (true)
40692 * @cfg {String/Object} autoCreate
40693 * A DomHelper element spec, or true for a default element spec (defaults to
40694 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40697 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40700 hiddenField: false,
40702 hideMonthPicker : false,
40704 onRender : function(ct, position)
40706 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40708 this.el.dom.removeAttribute('name');
40709 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40711 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40712 // prevent input submission
40713 this.hiddenName = this.name;
40720 validateValue : function(value)
40722 value = this.formatDate(value);
40723 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40726 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40729 var svalue = value;
40730 value = this.parseDate(value);
40732 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40735 var time = value.getTime();
40736 if(this.minValue && time < this.minValue.getTime()){
40737 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40740 if(this.maxValue && time > this.maxValue.getTime()){
40741 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40744 /*if(this.disabledDays){
40745 var day = value.getDay();
40746 for(var i = 0; i < this.disabledDays.length; i++) {
40747 if(day === this.disabledDays[i]){
40748 this.markInvalid(this.disabledDaysText);
40754 var fvalue = this.formatDate(value);
40755 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40756 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40764 // Provides logic to override the default TriggerField.validateBlur which just returns true
40765 validateBlur : function(){
40766 return !this.menu || !this.menu.isVisible();
40770 * Returns the current date value of the date field.
40771 * @return {Date} The date value
40773 getValue : function(){
40777 return this.hiddenField ?
40778 this.hiddenField.value :
40779 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40783 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40784 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40785 * (the default format used is "m/d/y").
40788 //All of these calls set the same date value (May 4, 2006)
40790 //Pass a date object:
40791 var dt = new Date('5/4/06');
40792 monthField.setValue(dt);
40794 //Pass a date string (default format):
40795 monthField.setValue('5/4/06');
40797 //Pass a date string (custom format):
40798 monthField.format = 'Y-m-d';
40799 monthField.setValue('2006-5-4');
40801 * @param {String/Date} date The date or valid date string
40803 setValue : function(date){
40804 Roo.log('month setValue' + date);
40805 // can only be first of month..
40807 var val = this.parseDate(date);
40809 if (this.hiddenField) {
40810 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40812 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40813 this.value = this.parseDate(date);
40817 parseDate : function(value){
40818 if(!value || value instanceof Date){
40819 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40822 var v = Date.parseDate(value, this.format);
40823 if (!v && this.useIso) {
40824 v = Date.parseDate(value, 'Y-m-d');
40828 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40832 if(!v && this.altFormats){
40833 if(!this.altFormatsArray){
40834 this.altFormatsArray = this.altFormats.split("|");
40836 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40837 v = Date.parseDate(value, this.altFormatsArray[i]);
40844 formatDate : function(date, fmt){
40845 return (!date || !(date instanceof Date)) ?
40846 date : date.dateFormat(fmt || this.format);
40851 select: function(m, d){
40853 this.fireEvent('select', this, d);
40855 show : function(){ // retain focus styling
40859 this.focus.defer(10, this);
40860 var ml = this.menuListeners;
40861 this.menu.un("select", ml.select, this);
40862 this.menu.un("show", ml.show, this);
40863 this.menu.un("hide", ml.hide, this);
40867 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40868 onTriggerClick : function(){
40872 if(this.menu == null){
40873 this.menu = new Roo.menu.DateMenu();
40877 Roo.apply(this.menu.picker, {
40879 showClear: this.allowBlank,
40880 minDate : this.minValue,
40881 maxDate : this.maxValue,
40882 disabledDatesRE : this.ddMatch,
40883 disabledDatesText : this.disabledDatesText,
40885 format : this.useIso ? 'Y-m-d' : this.format,
40886 minText : String.format(this.minText, this.formatDate(this.minValue)),
40887 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40890 this.menu.on(Roo.apply({}, this.menuListeners, {
40898 // hide month picker get's called when we called by 'before hide';
40900 var ignorehide = true;
40901 p.hideMonthPicker = function(disableAnim){
40905 if(this.monthPicker){
40906 Roo.log("hideMonthPicker called");
40907 if(disableAnim === true){
40908 this.monthPicker.hide();
40910 this.monthPicker.slideOut('t', {duration:.2});
40911 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40912 p.fireEvent("select", this, this.value);
40918 Roo.log('picker set value');
40919 Roo.log(this.getValue());
40920 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40921 m.show(this.el, 'tl-bl?');
40922 ignorehide = false;
40923 // this will trigger hideMonthPicker..
40926 // hidden the day picker
40927 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40933 p.showMonthPicker.defer(100, p);
40939 beforeBlur : function(){
40940 var v = this.parseDate(this.getRawValue());
40946 /** @cfg {Boolean} grow @hide */
40947 /** @cfg {Number} growMin @hide */
40948 /** @cfg {Number} growMax @hide */
40955 * Ext JS Library 1.1.1
40956 * Copyright(c) 2006-2007, Ext JS, LLC.
40958 * Originally Released Under LGPL - original licence link has changed is not relivant.
40961 * <script type="text/javascript">
40966 * @class Roo.form.ComboBox
40967 * @extends Roo.form.TriggerField
40968 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40970 * Create a new ComboBox.
40971 * @param {Object} config Configuration options
40973 Roo.form.ComboBox = function(config){
40974 Roo.form.ComboBox.superclass.constructor.call(this, config);
40978 * Fires when the dropdown list is expanded
40979 * @param {Roo.form.ComboBox} combo This combo box
40984 * Fires when the dropdown list is collapsed
40985 * @param {Roo.form.ComboBox} combo This combo box
40989 * @event beforeselect
40990 * Fires before a list item is selected. Return false to cancel the selection.
40991 * @param {Roo.form.ComboBox} combo This combo box
40992 * @param {Roo.data.Record} record The data record returned from the underlying store
40993 * @param {Number} index The index of the selected item in the dropdown list
40995 'beforeselect' : true,
40998 * Fires when a list item is selected
40999 * @param {Roo.form.ComboBox} combo This combo box
41000 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41001 * @param {Number} index The index of the selected item in the dropdown list
41005 * @event beforequery
41006 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41007 * The event object passed has these properties:
41008 * @param {Roo.form.ComboBox} combo This combo box
41009 * @param {String} query The query
41010 * @param {Boolean} forceAll true to force "all" query
41011 * @param {Boolean} cancel true to cancel the query
41012 * @param {Object} e The query event object
41014 'beforequery': true,
41017 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41018 * @param {Roo.form.ComboBox} combo This combo box
41023 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41024 * @param {Roo.form.ComboBox} combo This combo box
41025 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41031 if(this.transform){
41032 this.allowDomMove = false;
41033 var s = Roo.getDom(this.transform);
41034 if(!this.hiddenName){
41035 this.hiddenName = s.name;
41038 this.mode = 'local';
41039 var d = [], opts = s.options;
41040 for(var i = 0, len = opts.length;i < len; i++){
41042 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41044 this.value = value;
41046 d.push([value, o.text]);
41048 this.store = new Roo.data.SimpleStore({
41050 fields: ['value', 'text'],
41053 this.valueField = 'value';
41054 this.displayField = 'text';
41056 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41057 if(!this.lazyRender){
41058 this.target = true;
41059 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41060 s.parentNode.removeChild(s); // remove it
41061 this.render(this.el.parentNode);
41063 s.parentNode.removeChild(s); // remove it
41068 this.store = Roo.factory(this.store, Roo.data);
41071 this.selectedIndex = -1;
41072 if(this.mode == 'local'){
41073 if(config.queryDelay === undefined){
41074 this.queryDelay = 10;
41076 if(config.minChars === undefined){
41082 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41084 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41087 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41088 * rendering into an Roo.Editor, defaults to false)
41091 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41092 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41095 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41098 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41099 * the dropdown list (defaults to undefined, with no header element)
41103 * @cfg {String/Roo.Template} tpl The template to use to render the output
41107 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41109 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41111 listWidth: undefined,
41113 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41114 * mode = 'remote' or 'text' if mode = 'local')
41116 displayField: undefined,
41118 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41119 * mode = 'remote' or 'value' if mode = 'local').
41120 * Note: use of a valueField requires the user make a selection
41121 * in order for a value to be mapped.
41123 valueField: undefined,
41127 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41128 * field's data value (defaults to the underlying DOM element's name)
41130 hiddenName: undefined,
41132 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41136 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41138 selectedClass: 'x-combo-selected',
41140 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41141 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41142 * which displays a downward arrow icon).
41144 triggerClass : 'x-form-arrow-trigger',
41146 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41150 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41151 * anchor positions (defaults to 'tl-bl')
41153 listAlign: 'tl-bl?',
41155 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41159 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41160 * query specified by the allQuery config option (defaults to 'query')
41162 triggerAction: 'query',
41164 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41165 * (defaults to 4, does not apply if editable = false)
41169 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41170 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41174 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41175 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41179 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41180 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41184 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41185 * when editable = true (defaults to false)
41187 selectOnFocus:false,
41189 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41191 queryParam: 'query',
41193 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41194 * when mode = 'remote' (defaults to 'Loading...')
41196 loadingText: 'Loading...',
41198 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41202 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41206 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41207 * traditional select (defaults to true)
41211 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41215 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41219 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41220 * listWidth has a higher value)
41224 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41225 * allow the user to set arbitrary text into the field (defaults to false)
41227 forceSelection:false,
41229 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41230 * if typeAhead = true (defaults to 250)
41232 typeAheadDelay : 250,
41234 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41235 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41237 valueNotFoundText : undefined,
41239 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41241 blockFocus : false,
41244 * @cfg {Boolean} disableClear Disable showing of clear button.
41246 disableClear : false,
41248 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41250 alwaysQuery : false,
41256 // element that contains real text value.. (when hidden is used..)
41259 onRender : function(ct, position){
41260 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41261 if(this.hiddenName){
41262 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41264 this.hiddenField.value =
41265 this.hiddenValue !== undefined ? this.hiddenValue :
41266 this.value !== undefined ? this.value : '';
41268 // prevent input submission
41269 this.el.dom.removeAttribute('name');
41274 this.el.dom.setAttribute('autocomplete', 'off');
41277 var cls = 'x-combo-list';
41279 this.list = new Roo.Layer({
41280 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41283 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41284 this.list.setWidth(lw);
41285 this.list.swallowEvent('mousewheel');
41286 this.assetHeight = 0;
41289 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41290 this.assetHeight += this.header.getHeight();
41293 this.innerList = this.list.createChild({cls:cls+'-inner'});
41294 this.innerList.on('mouseover', this.onViewOver, this);
41295 this.innerList.on('mousemove', this.onViewMove, this);
41296 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41298 if(this.allowBlank && !this.pageSize && !this.disableClear){
41299 this.footer = this.list.createChild({cls:cls+'-ft'});
41300 this.pageTb = new Roo.Toolbar(this.footer);
41304 this.footer = this.list.createChild({cls:cls+'-ft'});
41305 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41306 {pageSize: this.pageSize});
41310 if (this.pageTb && this.allowBlank && !this.disableClear) {
41312 this.pageTb.add(new Roo.Toolbar.Fill(), {
41313 cls: 'x-btn-icon x-btn-clear',
41315 handler: function()
41318 _this.clearValue();
41319 _this.onSelect(false, -1);
41324 this.assetHeight += this.footer.getHeight();
41329 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41332 this.view = new Roo.View(this.innerList, this.tpl, {
41333 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41336 this.view.on('click', this.onViewClick, this);
41338 this.store.on('beforeload', this.onBeforeLoad, this);
41339 this.store.on('load', this.onLoad, this);
41340 this.store.on('loadexception', this.onLoadException, this);
41342 if(this.resizable){
41343 this.resizer = new Roo.Resizable(this.list, {
41344 pinned:true, handles:'se'
41346 this.resizer.on('resize', function(r, w, h){
41347 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41348 this.listWidth = w;
41349 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41350 this.restrictHeight();
41352 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41354 if(!this.editable){
41355 this.editable = true;
41356 this.setEditable(false);
41360 if (typeof(this.events.add.listeners) != 'undefined') {
41362 this.addicon = this.wrap.createChild(
41363 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41365 this.addicon.on('click', function(e) {
41366 this.fireEvent('add', this);
41369 if (typeof(this.events.edit.listeners) != 'undefined') {
41371 this.editicon = this.wrap.createChild(
41372 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41373 if (this.addicon) {
41374 this.editicon.setStyle('margin-left', '40px');
41376 this.editicon.on('click', function(e) {
41378 // we fire even if inothing is selected..
41379 this.fireEvent('edit', this, this.lastData );
41389 initEvents : function(){
41390 Roo.form.ComboBox.superclass.initEvents.call(this);
41392 this.keyNav = new Roo.KeyNav(this.el, {
41393 "up" : function(e){
41394 this.inKeyMode = true;
41398 "down" : function(e){
41399 if(!this.isExpanded()){
41400 this.onTriggerClick();
41402 this.inKeyMode = true;
41407 "enter" : function(e){
41408 this.onViewClick();
41412 "esc" : function(e){
41416 "tab" : function(e){
41417 this.onViewClick(false);
41418 this.fireEvent("specialkey", this, e);
41424 doRelay : function(foo, bar, hname){
41425 if(hname == 'down' || this.scope.isExpanded()){
41426 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41433 this.queryDelay = Math.max(this.queryDelay || 10,
41434 this.mode == 'local' ? 10 : 250);
41435 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41436 if(this.typeAhead){
41437 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41439 if(this.editable !== false){
41440 this.el.on("keyup", this.onKeyUp, this);
41442 if(this.forceSelection){
41443 this.on('blur', this.doForce, this);
41447 onDestroy : function(){
41449 this.view.setStore(null);
41450 this.view.el.removeAllListeners();
41451 this.view.el.remove();
41452 this.view.purgeListeners();
41455 this.list.destroy();
41458 this.store.un('beforeload', this.onBeforeLoad, this);
41459 this.store.un('load', this.onLoad, this);
41460 this.store.un('loadexception', this.onLoadException, this);
41462 Roo.form.ComboBox.superclass.onDestroy.call(this);
41466 fireKey : function(e){
41467 if(e.isNavKeyPress() && !this.list.isVisible()){
41468 this.fireEvent("specialkey", this, e);
41473 onResize: function(w, h){
41474 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41476 if(typeof w != 'number'){
41477 // we do not handle it!?!?
41480 var tw = this.trigger.getWidth();
41481 tw += this.addicon ? this.addicon.getWidth() : 0;
41482 tw += this.editicon ? this.editicon.getWidth() : 0;
41484 this.el.setWidth( this.adjustWidth('input', x));
41486 this.trigger.setStyle('left', x+'px');
41488 if(this.list && this.listWidth === undefined){
41489 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41490 this.list.setWidth(lw);
41491 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41499 * Allow or prevent the user from directly editing the field text. If false is passed,
41500 * the user will only be able to select from the items defined in the dropdown list. This method
41501 * is the runtime equivalent of setting the 'editable' config option at config time.
41502 * @param {Boolean} value True to allow the user to directly edit the field text
41504 setEditable : function(value){
41505 if(value == this.editable){
41508 this.editable = value;
41510 this.el.dom.setAttribute('readOnly', true);
41511 this.el.on('mousedown', this.onTriggerClick, this);
41512 this.el.addClass('x-combo-noedit');
41514 this.el.dom.setAttribute('readOnly', false);
41515 this.el.un('mousedown', this.onTriggerClick, this);
41516 this.el.removeClass('x-combo-noedit');
41521 onBeforeLoad : function(){
41522 if(!this.hasFocus){
41525 this.innerList.update(this.loadingText ?
41526 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41527 this.restrictHeight();
41528 this.selectedIndex = -1;
41532 onLoad : function(){
41533 if(!this.hasFocus){
41536 if(this.store.getCount() > 0){
41538 this.restrictHeight();
41539 if(this.lastQuery == this.allQuery){
41541 this.el.dom.select();
41543 if(!this.selectByValue(this.value, true)){
41544 this.select(0, true);
41548 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41549 this.taTask.delay(this.typeAheadDelay);
41553 this.onEmptyResults();
41558 onLoadException : function()
41561 Roo.log(this.store.reader.jsonData);
41562 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41563 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41569 onTypeAhead : function(){
41570 if(this.store.getCount() > 0){
41571 var r = this.store.getAt(0);
41572 var newValue = r.data[this.displayField];
41573 var len = newValue.length;
41574 var selStart = this.getRawValue().length;
41575 if(selStart != len){
41576 this.setRawValue(newValue);
41577 this.selectText(selStart, newValue.length);
41583 onSelect : function(record, index){
41584 if(this.fireEvent('beforeselect', this, record, index) !== false){
41585 this.setFromData(index > -1 ? record.data : false);
41587 this.fireEvent('select', this, record, index);
41592 * Returns the currently selected field value or empty string if no value is set.
41593 * @return {String} value The selected value
41595 getValue : function(){
41596 if(this.valueField){
41597 return typeof this.value != 'undefined' ? this.value : '';
41599 return Roo.form.ComboBox.superclass.getValue.call(this);
41603 * Clears any text/value currently set in the field
41605 clearValue : function(){
41606 if(this.hiddenField){
41607 this.hiddenField.value = '';
41610 this.setRawValue('');
41611 this.lastSelectionText = '';
41616 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41617 * will be displayed in the field. If the value does not match the data value of an existing item,
41618 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41619 * Otherwise the field will be blank (although the value will still be set).
41620 * @param {String} value The value to match
41622 setValue : function(v){
41624 if(this.valueField){
41625 var r = this.findRecord(this.valueField, v);
41627 text = r.data[this.displayField];
41628 }else if(this.valueNotFoundText !== undefined){
41629 text = this.valueNotFoundText;
41632 this.lastSelectionText = text;
41633 if(this.hiddenField){
41634 this.hiddenField.value = v;
41636 Roo.form.ComboBox.superclass.setValue.call(this, text);
41640 * @property {Object} the last set data for the element
41645 * Sets the value of the field based on a object which is related to the record format for the store.
41646 * @param {Object} value the value to set as. or false on reset?
41648 setFromData : function(o){
41649 var dv = ''; // display value
41650 var vv = ''; // value value..
41652 if (this.displayField) {
41653 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41655 // this is an error condition!!!
41656 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41659 if(this.valueField){
41660 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41662 if(this.hiddenField){
41663 this.hiddenField.value = vv;
41665 this.lastSelectionText = dv;
41666 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41670 // no hidden field.. - we store the value in 'value', but still display
41671 // display field!!!!
41672 this.lastSelectionText = dv;
41673 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41679 reset : function(){
41680 // overridden so that last data is reset..
41681 this.setValue(this.resetValue);
41682 this.originalValue = this.getValue();
41683 this.clearInvalid();
41684 this.lastData = false;
41686 this.view.clearSelections();
41690 findRecord : function(prop, value){
41692 if(this.store.getCount() > 0){
41693 this.store.each(function(r){
41694 if(r.data[prop] == value){
41704 getName: function()
41706 // returns hidden if it's set..
41707 if (!this.rendered) {return ''};
41708 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41712 onViewMove : function(e, t){
41713 this.inKeyMode = false;
41717 onViewOver : function(e, t){
41718 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41721 var item = this.view.findItemFromChild(t);
41723 var index = this.view.indexOf(item);
41724 this.select(index, false);
41729 onViewClick : function(doFocus)
41731 var index = this.view.getSelectedIndexes()[0];
41732 var r = this.store.getAt(index);
41734 this.onSelect(r, index);
41736 if(doFocus !== false && !this.blockFocus){
41742 restrictHeight : function(){
41743 this.innerList.dom.style.height = '';
41744 var inner = this.innerList.dom;
41745 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41746 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41747 this.list.beginUpdate();
41748 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41749 this.list.alignTo(this.el, this.listAlign);
41750 this.list.endUpdate();
41754 onEmptyResults : function(){
41759 * Returns true if the dropdown list is expanded, else false.
41761 isExpanded : function(){
41762 return this.list.isVisible();
41766 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41767 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41768 * @param {String} value The data value of the item to select
41769 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41770 * selected item if it is not currently in view (defaults to true)
41771 * @return {Boolean} True if the value matched an item in the list, else false
41773 selectByValue : function(v, scrollIntoView){
41774 if(v !== undefined && v !== null){
41775 var r = this.findRecord(this.valueField || this.displayField, v);
41777 this.select(this.store.indexOf(r), scrollIntoView);
41785 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41786 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41787 * @param {Number} index The zero-based index of the list item to select
41788 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41789 * selected item if it is not currently in view (defaults to true)
41791 select : function(index, scrollIntoView){
41792 this.selectedIndex = index;
41793 this.view.select(index);
41794 if(scrollIntoView !== false){
41795 var el = this.view.getNode(index);
41797 this.innerList.scrollChildIntoView(el, false);
41803 selectNext : function(){
41804 var ct = this.store.getCount();
41806 if(this.selectedIndex == -1){
41808 }else if(this.selectedIndex < ct-1){
41809 this.select(this.selectedIndex+1);
41815 selectPrev : function(){
41816 var ct = this.store.getCount();
41818 if(this.selectedIndex == -1){
41820 }else if(this.selectedIndex != 0){
41821 this.select(this.selectedIndex-1);
41827 onKeyUp : function(e){
41828 if(this.editable !== false && !e.isSpecialKey()){
41829 this.lastKey = e.getKey();
41830 this.dqTask.delay(this.queryDelay);
41835 validateBlur : function(){
41836 return !this.list || !this.list.isVisible();
41840 initQuery : function(){
41841 this.doQuery(this.getRawValue());
41845 doForce : function(){
41846 if(this.el.dom.value.length > 0){
41847 this.el.dom.value =
41848 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41854 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41855 * query allowing the query action to be canceled if needed.
41856 * @param {String} query The SQL query to execute
41857 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41858 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41859 * saved in the current store (defaults to false)
41861 doQuery : function(q, forceAll){
41862 if(q === undefined || q === null){
41867 forceAll: forceAll,
41871 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41875 forceAll = qe.forceAll;
41876 if(forceAll === true || (q.length >= this.minChars)){
41877 if(this.lastQuery != q || this.alwaysQuery){
41878 this.lastQuery = q;
41879 if(this.mode == 'local'){
41880 this.selectedIndex = -1;
41882 this.store.clearFilter();
41884 this.store.filter(this.displayField, q);
41888 this.store.baseParams[this.queryParam] = q;
41890 params: this.getParams(q)
41895 this.selectedIndex = -1;
41902 getParams : function(q){
41904 //p[this.queryParam] = q;
41907 p.limit = this.pageSize;
41913 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41915 collapse : function(){
41916 if(!this.isExpanded()){
41920 Roo.get(document).un('mousedown', this.collapseIf, this);
41921 Roo.get(document).un('mousewheel', this.collapseIf, this);
41922 if (!this.editable) {
41923 Roo.get(document).un('keydown', this.listKeyPress, this);
41925 this.fireEvent('collapse', this);
41929 collapseIf : function(e){
41930 if(!e.within(this.wrap) && !e.within(this.list)){
41936 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41938 expand : function(){
41939 if(this.isExpanded() || !this.hasFocus){
41942 this.list.alignTo(this.el, this.listAlign);
41944 Roo.get(document).on('mousedown', this.collapseIf, this);
41945 Roo.get(document).on('mousewheel', this.collapseIf, this);
41946 if (!this.editable) {
41947 Roo.get(document).on('keydown', this.listKeyPress, this);
41950 this.fireEvent('expand', this);
41954 // Implements the default empty TriggerField.onTriggerClick function
41955 onTriggerClick : function(){
41959 if(this.isExpanded()){
41961 if (!this.blockFocus) {
41966 this.hasFocus = true;
41967 if(this.triggerAction == 'all') {
41968 this.doQuery(this.allQuery, true);
41970 this.doQuery(this.getRawValue());
41972 if (!this.blockFocus) {
41977 listKeyPress : function(e)
41979 //Roo.log('listkeypress');
41980 // scroll to first matching element based on key pres..
41981 if (e.isSpecialKey()) {
41984 var k = String.fromCharCode(e.getKey()).toUpperCase();
41987 var csel = this.view.getSelectedNodes();
41988 var cselitem = false;
41990 var ix = this.view.indexOf(csel[0]);
41991 cselitem = this.store.getAt(ix);
41992 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41998 this.store.each(function(v) {
42000 // start at existing selection.
42001 if (cselitem.id == v.id) {
42007 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42008 match = this.store.indexOf(v);
42013 if (match === false) {
42014 return true; // no more action?
42017 this.view.select(match);
42018 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42019 sn.scrollIntoView(sn.dom.parentNode, false);
42023 * @cfg {Boolean} grow
42027 * @cfg {Number} growMin
42031 * @cfg {Number} growMax
42039 * Copyright(c) 2010-2012, Roo J Solutions Limited
42046 * @class Roo.form.ComboBoxArray
42047 * @extends Roo.form.TextField
42048 * A facebook style adder... for lists of email / people / countries etc...
42049 * pick multiple items from a combo box, and shows each one.
42051 * Fred [x] Brian [x] [Pick another |v]
42054 * For this to work: it needs various extra information
42055 * - normal combo problay has
42057 * + displayField, valueField
42059 * For our purpose...
42062 * If we change from 'extends' to wrapping...
42069 * Create a new ComboBoxArray.
42070 * @param {Object} config Configuration options
42074 Roo.form.ComboBoxArray = function(config)
42078 * @event beforeremove
42079 * Fires before remove the value from the list
42080 * @param {Roo.form.ComboBoxArray} _self This combo box array
42081 * @param {Roo.form.ComboBoxArray.Item} item removed item
42083 'beforeremove' : true,
42086 * Fires when remove the value from the list
42087 * @param {Roo.form.ComboBoxArray} _self This combo box array
42088 * @param {Roo.form.ComboBoxArray.Item} item removed item
42095 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42097 this.items = new Roo.util.MixedCollection(false);
42099 // construct the child combo...
42109 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42112 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42117 // behavies liek a hiddne field
42118 inputType: 'hidden',
42120 * @cfg {Number} width The width of the box that displays the selected element
42127 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42131 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42133 hiddenName : false,
42136 // private the array of items that are displayed..
42138 // private - the hidden field el.
42140 // private - the filed el..
42143 //validateValue : function() { return true; }, // all values are ok!
42144 //onAddClick: function() { },
42146 onRender : function(ct, position)
42149 // create the standard hidden element
42150 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42153 // give fake names to child combo;
42154 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42155 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42157 this.combo = Roo.factory(this.combo, Roo.form);
42158 this.combo.onRender(ct, position);
42159 if (typeof(this.combo.width) != 'undefined') {
42160 this.combo.onResize(this.combo.width,0);
42163 this.combo.initEvents();
42165 // assigned so form know we need to do this..
42166 this.store = this.combo.store;
42167 this.valueField = this.combo.valueField;
42168 this.displayField = this.combo.displayField ;
42171 this.combo.wrap.addClass('x-cbarray-grp');
42173 var cbwrap = this.combo.wrap.createChild(
42174 {tag: 'div', cls: 'x-cbarray-cb'},
42179 this.hiddenEl = this.combo.wrap.createChild({
42180 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42182 this.el = this.combo.wrap.createChild({
42183 tag: 'input', type:'hidden' , name: this.name, value : ''
42185 // this.el.dom.removeAttribute("name");
42188 this.outerWrap = this.combo.wrap;
42189 this.wrap = cbwrap;
42191 this.outerWrap.setWidth(this.width);
42192 this.outerWrap.dom.removeChild(this.el.dom);
42194 this.wrap.dom.appendChild(this.el.dom);
42195 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42196 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42198 this.combo.trigger.setStyle('position','relative');
42199 this.combo.trigger.setStyle('left', '0px');
42200 this.combo.trigger.setStyle('top', '2px');
42202 this.combo.el.setStyle('vertical-align', 'text-bottom');
42204 //this.trigger.setStyle('vertical-align', 'top');
42206 // this should use the code from combo really... on('add' ....)
42210 this.adder = this.outerWrap.createChild(
42211 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42213 this.adder.on('click', function(e) {
42214 _t.fireEvent('adderclick', this, e);
42218 //this.adder.on('click', this.onAddClick, _t);
42221 this.combo.on('select', function(cb, rec, ix) {
42222 this.addItem(rec.data);
42225 cb.el.dom.value = '';
42226 //cb.lastData = rec.data;
42235 getName: function()
42237 // returns hidden if it's set..
42238 if (!this.rendered) {return ''};
42239 return this.hiddenName ? this.hiddenName : this.name;
42244 onResize: function(w, h){
42247 // not sure if this is needed..
42248 //this.combo.onResize(w,h);
42250 if(typeof w != 'number'){
42251 // we do not handle it!?!?
42254 var tw = this.combo.trigger.getWidth();
42255 tw += this.addicon ? this.addicon.getWidth() : 0;
42256 tw += this.editicon ? this.editicon.getWidth() : 0;
42258 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42260 this.combo.trigger.setStyle('left', '0px');
42262 if(this.list && this.listWidth === undefined){
42263 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42264 this.list.setWidth(lw);
42265 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42272 addItem: function(rec)
42274 var valueField = this.combo.valueField;
42275 var displayField = this.combo.displayField;
42276 if (this.items.indexOfKey(rec[valueField]) > -1) {
42277 //console.log("GOT " + rec.data.id);
42281 var x = new Roo.form.ComboBoxArray.Item({
42282 //id : rec[this.idField],
42284 displayField : displayField ,
42285 tipField : displayField ,
42289 this.items.add(rec[valueField],x);
42290 // add it before the element..
42291 this.updateHiddenEl();
42292 x.render(this.outerWrap, this.wrap.dom);
42293 // add the image handler..
42296 updateHiddenEl : function()
42299 if (!this.hiddenEl) {
42303 var idField = this.combo.valueField;
42305 this.items.each(function(f) {
42306 ar.push(f.data[idField]);
42309 this.hiddenEl.dom.value = ar.join(',');
42315 this.items.clear();
42317 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42321 this.el.dom.value = '';
42322 if (this.hiddenEl) {
42323 this.hiddenEl.dom.value = '';
42327 getValue: function()
42329 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42331 setValue: function(v) // not a valid action - must use addItems..
42338 if (this.store.isLocal && (typeof(v) == 'string')) {
42339 // then we can use the store to find the values..
42340 // comma seperated at present.. this needs to allow JSON based encoding..
42341 this.hiddenEl.value = v;
42343 Roo.each(v.split(','), function(k) {
42344 Roo.log("CHECK " + this.valueField + ',' + k);
42345 var li = this.store.query(this.valueField, k);
42350 add[this.valueField] = k;
42351 add[this.displayField] = li.item(0).data[this.displayField];
42357 if (typeof(v) == 'object' ) {
42358 // then let's assume it's an array of objects..
42359 Roo.each(v, function(l) {
42367 setFromData: function(v)
42369 // this recieves an object, if setValues is called.
42371 this.el.dom.value = v[this.displayField];
42372 this.hiddenEl.dom.value = v[this.valueField];
42373 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42376 var kv = v[this.valueField];
42377 var dv = v[this.displayField];
42378 kv = typeof(kv) != 'string' ? '' : kv;
42379 dv = typeof(dv) != 'string' ? '' : dv;
42382 var keys = kv.split(',');
42383 var display = dv.split(',');
42384 for (var i = 0 ; i < keys.length; i++) {
42387 add[this.valueField] = keys[i];
42388 add[this.displayField] = display[i];
42396 * Validates the combox array value
42397 * @return {Boolean} True if the value is valid, else false
42399 validate : function(){
42400 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42401 this.clearInvalid();
42407 validateValue : function(value){
42408 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42416 isDirty : function() {
42417 if(this.disabled) {
42422 var d = Roo.decode(String(this.originalValue));
42424 return String(this.getValue()) !== String(this.originalValue);
42427 var originalValue = [];
42429 for (var i = 0; i < d.length; i++){
42430 originalValue.push(d[i][this.valueField]);
42433 return String(this.getValue()) !== String(originalValue.join(','));
42442 * @class Roo.form.ComboBoxArray.Item
42443 * @extends Roo.BoxComponent
42444 * A selected item in the list
42445 * Fred [x] Brian [x] [Pick another |v]
42448 * Create a new item.
42449 * @param {Object} config Configuration options
42452 Roo.form.ComboBoxArray.Item = function(config) {
42453 config.id = Roo.id();
42454 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42457 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42460 displayField : false,
42464 defaultAutoCreate : {
42466 cls: 'x-cbarray-item',
42473 src : Roo.BLANK_IMAGE_URL ,
42481 onRender : function(ct, position)
42483 Roo.form.Field.superclass.onRender.call(this, ct, position);
42486 var cfg = this.getAutoCreate();
42487 this.el = ct.createChild(cfg, position);
42490 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42492 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42493 this.cb.renderer(this.data) :
42494 String.format('{0}',this.data[this.displayField]);
42497 this.el.child('div').dom.setAttribute('qtip',
42498 String.format('{0}',this.data[this.tipField])
42501 this.el.child('img').on('click', this.remove, this);
42505 remove : function()
42507 if(this.cb.disabled){
42511 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42512 this.cb.items.remove(this);
42513 this.el.child('img').un('click', this.remove, this);
42515 this.cb.updateHiddenEl();
42517 this.cb.fireEvent('remove', this.cb, this);
42523 * Ext JS Library 1.1.1
42524 * Copyright(c) 2006-2007, Ext JS, LLC.
42526 * Originally Released Under LGPL - original licence link has changed is not relivant.
42529 * <script type="text/javascript">
42532 * @class Roo.form.Checkbox
42533 * @extends Roo.form.Field
42534 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42536 * Creates a new Checkbox
42537 * @param {Object} config Configuration options
42539 Roo.form.Checkbox = function(config){
42540 Roo.form.Checkbox.superclass.constructor.call(this, config);
42544 * Fires when the checkbox is checked or unchecked.
42545 * @param {Roo.form.Checkbox} this This checkbox
42546 * @param {Boolean} checked The new checked value
42552 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42554 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42556 focusClass : undefined,
42558 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42560 fieldClass: "x-form-field",
42562 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42566 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42567 * {tag: "input", type: "checkbox", autocomplete: "off"})
42569 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42571 * @cfg {String} boxLabel The text that appears beside the checkbox
42575 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42579 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42581 valueOff: '0', // value when not checked..
42583 actionMode : 'viewEl',
42586 itemCls : 'x-menu-check-item x-form-item',
42587 groupClass : 'x-menu-group-item',
42588 inputType : 'hidden',
42591 inSetChecked: false, // check that we are not calling self...
42593 inputElement: false, // real input element?
42594 basedOn: false, // ????
42596 isFormField: true, // not sure where this is needed!!!!
42598 onResize : function(){
42599 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42600 if(!this.boxLabel){
42601 this.el.alignTo(this.wrap, 'c-c');
42605 initEvents : function(){
42606 Roo.form.Checkbox.superclass.initEvents.call(this);
42607 this.el.on("click", this.onClick, this);
42608 this.el.on("change", this.onClick, this);
42612 getResizeEl : function(){
42616 getPositionEl : function(){
42621 onRender : function(ct, position){
42622 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42624 if(this.inputValue !== undefined){
42625 this.el.dom.value = this.inputValue;
42628 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42629 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42630 var viewEl = this.wrap.createChild({
42631 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42632 this.viewEl = viewEl;
42633 this.wrap.on('click', this.onClick, this);
42635 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42636 this.el.on('propertychange', this.setFromHidden, this); //ie
42641 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42642 // viewEl.on('click', this.onClick, this);
42644 //if(this.checked){
42645 this.setChecked(this.checked);
42647 //this.checked = this.el.dom;
42653 initValue : Roo.emptyFn,
42656 * Returns the checked state of the checkbox.
42657 * @return {Boolean} True if checked, else false
42659 getValue : function(){
42661 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42663 return this.valueOff;
42668 onClick : function(){
42669 if (this.disabled) {
42672 this.setChecked(!this.checked);
42674 //if(this.el.dom.checked != this.checked){
42675 // this.setValue(this.el.dom.checked);
42680 * Sets the checked state of the checkbox.
42681 * On is always based on a string comparison between inputValue and the param.
42682 * @param {Boolean/String} value - the value to set
42683 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42685 setValue : function(v,suppressEvent){
42688 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42689 //if(this.el && this.el.dom){
42690 // this.el.dom.checked = this.checked;
42691 // this.el.dom.defaultChecked = this.checked;
42693 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42694 //this.fireEvent("check", this, this.checked);
42697 setChecked : function(state,suppressEvent)
42699 if (this.inSetChecked) {
42700 this.checked = state;
42706 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42708 this.checked = state;
42709 if(suppressEvent !== true){
42710 this.fireEvent('check', this, state);
42712 this.inSetChecked = true;
42713 this.el.dom.value = state ? this.inputValue : this.valueOff;
42714 this.inSetChecked = false;
42717 // handle setting of hidden value by some other method!!?!?
42718 setFromHidden: function()
42723 //console.log("SET FROM HIDDEN");
42724 //alert('setFrom hidden');
42725 this.setValue(this.el.dom.value);
42728 onDestroy : function()
42731 Roo.get(this.viewEl).remove();
42734 Roo.form.Checkbox.superclass.onDestroy.call(this);
42737 setBoxLabel : function(str)
42739 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42744 * Ext JS Library 1.1.1
42745 * Copyright(c) 2006-2007, Ext JS, LLC.
42747 * Originally Released Under LGPL - original licence link has changed is not relivant.
42750 * <script type="text/javascript">
42754 * @class Roo.form.Radio
42755 * @extends Roo.form.Checkbox
42756 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42757 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42759 * Creates a new Radio
42760 * @param {Object} config Configuration options
42762 Roo.form.Radio = function(){
42763 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42765 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42766 inputType: 'radio',
42769 * If this radio is part of a group, it will return the selected value
42772 getGroupValue : function(){
42773 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42777 onRender : function(ct, position){
42778 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42780 if(this.inputValue !== undefined){
42781 this.el.dom.value = this.inputValue;
42784 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42785 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42786 //var viewEl = this.wrap.createChild({
42787 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42788 //this.viewEl = viewEl;
42789 //this.wrap.on('click', this.onClick, this);
42791 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42792 //this.el.on('propertychange', this.setFromHidden, this); //ie
42797 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42798 // viewEl.on('click', this.onClick, this);
42801 this.el.dom.checked = 'checked' ;
42807 });//<script type="text/javascript">
42810 * Based Ext JS Library 1.1.1
42811 * Copyright(c) 2006-2007, Ext JS, LLC.
42817 * @class Roo.HtmlEditorCore
42818 * @extends Roo.Component
42819 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42821 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42824 Roo.HtmlEditorCore = function(config){
42827 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42832 * @event initialize
42833 * Fires when the editor is fully initialized (including the iframe)
42834 * @param {Roo.HtmlEditorCore} this
42839 * Fires when the editor is first receives the focus. Any insertion must wait
42840 * until after this event.
42841 * @param {Roo.HtmlEditorCore} this
42845 * @event beforesync
42846 * Fires before the textarea is updated with content from the editor iframe. Return false
42847 * to cancel the sync.
42848 * @param {Roo.HtmlEditorCore} this
42849 * @param {String} html
42853 * @event beforepush
42854 * Fires before the iframe editor is updated with content from the textarea. Return false
42855 * to cancel the push.
42856 * @param {Roo.HtmlEditorCore} this
42857 * @param {String} html
42862 * Fires when the textarea is updated with content from the editor iframe.
42863 * @param {Roo.HtmlEditorCore} this
42864 * @param {String} html
42869 * Fires when the iframe editor is updated with content from the textarea.
42870 * @param {Roo.HtmlEditorCore} this
42871 * @param {String} html
42876 * @event editorevent
42877 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42878 * @param {Roo.HtmlEditorCore} this
42884 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42886 // defaults : white / black...
42887 this.applyBlacklists();
42894 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42898 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42904 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42909 * @cfg {Number} height (in pixels)
42913 * @cfg {Number} width (in pixels)
42918 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42921 stylesheets: false,
42926 // private properties
42927 validationEvent : false,
42929 initialized : false,
42931 sourceEditMode : false,
42932 onFocus : Roo.emptyFn,
42934 hideMode:'offsets',
42938 // blacklist + whitelisted elements..
42945 * Protected method that will not generally be called directly. It
42946 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42947 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42949 getDocMarkup : function(){
42953 // inherit styels from page...??
42954 if (this.stylesheets === false) {
42956 Roo.get(document.head).select('style').each(function(node) {
42957 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42960 Roo.get(document.head).select('link').each(function(node) {
42961 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42964 } else if (!this.stylesheets.length) {
42966 st = '<style type="text/css">' +
42967 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42970 st = '<style type="text/css">' +
42975 st += '<style type="text/css">' +
42976 'IMG { cursor: pointer } ' +
42979 var cls = 'roo-htmleditor-body';
42981 if(this.bodyCls.length){
42982 cls += ' ' + this.bodyCls;
42985 return '<html><head>' + st +
42986 //<style type="text/css">' +
42987 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42989 ' </head><body class="' + cls + '"></body></html>';
42993 onRender : function(ct, position)
42996 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42997 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43000 this.el.dom.style.border = '0 none';
43001 this.el.dom.setAttribute('tabIndex', -1);
43002 this.el.addClass('x-hidden hide');
43006 if(Roo.isIE){ // fix IE 1px bogus margin
43007 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43011 this.frameId = Roo.id();
43015 var iframe = this.owner.wrap.createChild({
43017 cls: 'form-control', // bootstrap..
43019 name: this.frameId,
43020 frameBorder : 'no',
43021 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43026 this.iframe = iframe.dom;
43028 this.assignDocWin();
43030 this.doc.designMode = 'on';
43033 this.doc.write(this.getDocMarkup());
43037 var task = { // must defer to wait for browser to be ready
43039 //console.log("run task?" + this.doc.readyState);
43040 this.assignDocWin();
43041 if(this.doc.body || this.doc.readyState == 'complete'){
43043 this.doc.designMode="on";
43047 Roo.TaskMgr.stop(task);
43048 this.initEditor.defer(10, this);
43055 Roo.TaskMgr.start(task);
43060 onResize : function(w, h)
43062 Roo.log('resize: ' +w + ',' + h );
43063 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43067 if(typeof w == 'number'){
43069 this.iframe.style.width = w + 'px';
43071 if(typeof h == 'number'){
43073 this.iframe.style.height = h + 'px';
43075 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43082 * Toggles the editor between standard and source edit mode.
43083 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43085 toggleSourceEdit : function(sourceEditMode){
43087 this.sourceEditMode = sourceEditMode === true;
43089 if(this.sourceEditMode){
43091 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43094 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43095 //this.iframe.className = '';
43098 //this.setSize(this.owner.wrap.getSize());
43099 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43106 * Protected method that will not generally be called directly. If you need/want
43107 * custom HTML cleanup, this is the method you should override.
43108 * @param {String} html The HTML to be cleaned
43109 * return {String} The cleaned HTML
43111 cleanHtml : function(html){
43112 html = String(html);
43113 if(html.length > 5){
43114 if(Roo.isSafari){ // strip safari nonsense
43115 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43118 if(html == ' '){
43125 * HTML Editor -> Textarea
43126 * Protected method that will not generally be called directly. Syncs the contents
43127 * of the editor iframe with the textarea.
43129 syncValue : function(){
43130 if(this.initialized){
43131 var bd = (this.doc.body || this.doc.documentElement);
43132 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43133 var html = bd.innerHTML;
43135 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43136 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43138 html = '<div style="'+m[0]+'">' + html + '</div>';
43141 html = this.cleanHtml(html);
43142 // fix up the special chars.. normaly like back quotes in word...
43143 // however we do not want to do this with chinese..
43144 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43145 var cc = b.charCodeAt();
43147 (cc >= 0x4E00 && cc < 0xA000 ) ||
43148 (cc >= 0x3400 && cc < 0x4E00 ) ||
43149 (cc >= 0xf900 && cc < 0xfb00 )
43155 if(this.owner.fireEvent('beforesync', this, html) !== false){
43156 this.el.dom.value = html;
43157 this.owner.fireEvent('sync', this, html);
43163 * Protected method that will not generally be called directly. Pushes the value of the textarea
43164 * into the iframe editor.
43166 pushValue : function(){
43167 if(this.initialized){
43168 var v = this.el.dom.value.trim();
43170 // if(v.length < 1){
43174 if(this.owner.fireEvent('beforepush', this, v) !== false){
43175 var d = (this.doc.body || this.doc.documentElement);
43177 this.cleanUpPaste();
43178 this.el.dom.value = d.innerHTML;
43179 this.owner.fireEvent('push', this, v);
43185 deferFocus : function(){
43186 this.focus.defer(10, this);
43190 focus : function(){
43191 if(this.win && !this.sourceEditMode){
43198 assignDocWin: function()
43200 var iframe = this.iframe;
43203 this.doc = iframe.contentWindow.document;
43204 this.win = iframe.contentWindow;
43206 // if (!Roo.get(this.frameId)) {
43209 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43210 // this.win = Roo.get(this.frameId).dom.contentWindow;
43212 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43216 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43217 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43222 initEditor : function(){
43223 //console.log("INIT EDITOR");
43224 this.assignDocWin();
43228 this.doc.designMode="on";
43230 this.doc.write(this.getDocMarkup());
43233 var dbody = (this.doc.body || this.doc.documentElement);
43234 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43235 // this copies styles from the containing element into thsi one..
43236 // not sure why we need all of this..
43237 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43239 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43240 //ss['background-attachment'] = 'fixed'; // w3c
43241 dbody.bgProperties = 'fixed'; // ie
43242 //Roo.DomHelper.applyStyles(dbody, ss);
43243 Roo.EventManager.on(this.doc, {
43244 //'mousedown': this.onEditorEvent,
43245 'mouseup': this.onEditorEvent,
43246 'dblclick': this.onEditorEvent,
43247 'click': this.onEditorEvent,
43248 'keyup': this.onEditorEvent,
43253 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43255 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43256 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43258 this.initialized = true;
43260 this.owner.fireEvent('initialize', this);
43265 onDestroy : function(){
43271 //for (var i =0; i < this.toolbars.length;i++) {
43272 // // fixme - ask toolbars for heights?
43273 // this.toolbars[i].onDestroy();
43276 //this.wrap.dom.innerHTML = '';
43277 //this.wrap.remove();
43282 onFirstFocus : function(){
43284 this.assignDocWin();
43287 this.activated = true;
43290 if(Roo.isGecko){ // prevent silly gecko errors
43292 var s = this.win.getSelection();
43293 if(!s.focusNode || s.focusNode.nodeType != 3){
43294 var r = s.getRangeAt(0);
43295 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43300 this.execCmd('useCSS', true);
43301 this.execCmd('styleWithCSS', false);
43304 this.owner.fireEvent('activate', this);
43308 adjustFont: function(btn){
43309 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43310 //if(Roo.isSafari){ // safari
43313 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43314 if(Roo.isSafari){ // safari
43315 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43316 v = (v < 10) ? 10 : v;
43317 v = (v > 48) ? 48 : v;
43318 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43323 v = Math.max(1, v+adjust);
43325 this.execCmd('FontSize', v );
43328 onEditorEvent : function(e)
43330 this.owner.fireEvent('editorevent', this, e);
43331 // this.updateToolbar();
43332 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43335 insertTag : function(tg)
43337 // could be a bit smarter... -> wrap the current selected tRoo..
43338 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43340 range = this.createRange(this.getSelection());
43341 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43342 wrappingNode.appendChild(range.extractContents());
43343 range.insertNode(wrappingNode);
43350 this.execCmd("formatblock", tg);
43354 insertText : function(txt)
43358 var range = this.createRange();
43359 range.deleteContents();
43360 //alert(Sender.getAttribute('label'));
43362 range.insertNode(this.doc.createTextNode(txt));
43368 * Executes a Midas editor command on the editor document and performs necessary focus and
43369 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43370 * @param {String} cmd The Midas command
43371 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43373 relayCmd : function(cmd, value){
43375 this.execCmd(cmd, value);
43376 this.owner.fireEvent('editorevent', this);
43377 //this.updateToolbar();
43378 this.owner.deferFocus();
43382 * Executes a Midas editor command directly on the editor document.
43383 * For visual commands, you should use {@link #relayCmd} instead.
43384 * <b>This should only be called after the editor is initialized.</b>
43385 * @param {String} cmd The Midas command
43386 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43388 execCmd : function(cmd, value){
43389 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43396 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43398 * @param {String} text | dom node..
43400 insertAtCursor : function(text)
43403 if(!this.activated){
43409 var r = this.doc.selection.createRange();
43420 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43424 // from jquery ui (MIT licenced)
43426 var win = this.win;
43428 if (win.getSelection && win.getSelection().getRangeAt) {
43429 range = win.getSelection().getRangeAt(0);
43430 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43431 range.insertNode(node);
43432 } else if (win.document.selection && win.document.selection.createRange) {
43433 // no firefox support
43434 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43435 win.document.selection.createRange().pasteHTML(txt);
43437 // no firefox support
43438 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43439 this.execCmd('InsertHTML', txt);
43448 mozKeyPress : function(e){
43450 var c = e.getCharCode(), cmd;
43453 c = String.fromCharCode(c).toLowerCase();
43467 this.cleanUpPaste.defer(100, this);
43475 e.preventDefault();
43483 fixKeys : function(){ // load time branching for fastest keydown performance
43485 return function(e){
43486 var k = e.getKey(), r;
43489 r = this.doc.selection.createRange();
43492 r.pasteHTML('    ');
43499 r = this.doc.selection.createRange();
43501 var target = r.parentElement();
43502 if(!target || target.tagName.toLowerCase() != 'li'){
43504 r.pasteHTML('<br />');
43510 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43511 this.cleanUpPaste.defer(100, this);
43517 }else if(Roo.isOpera){
43518 return function(e){
43519 var k = e.getKey();
43523 this.execCmd('InsertHTML','    ');
43526 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43527 this.cleanUpPaste.defer(100, this);
43532 }else if(Roo.isSafari){
43533 return function(e){
43534 var k = e.getKey();
43538 this.execCmd('InsertText','\t');
43542 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43543 this.cleanUpPaste.defer(100, this);
43551 getAllAncestors: function()
43553 var p = this.getSelectedNode();
43556 a.push(p); // push blank onto stack..
43557 p = this.getParentElement();
43561 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43565 a.push(this.doc.body);
43569 lastSelNode : false,
43572 getSelection : function()
43574 this.assignDocWin();
43575 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43578 getSelectedNode: function()
43580 // this may only work on Gecko!!!
43582 // should we cache this!!!!
43587 var range = this.createRange(this.getSelection()).cloneRange();
43590 var parent = range.parentElement();
43592 var testRange = range.duplicate();
43593 testRange.moveToElementText(parent);
43594 if (testRange.inRange(range)) {
43597 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43600 parent = parent.parentElement;
43605 // is ancestor a text element.
43606 var ac = range.commonAncestorContainer;
43607 if (ac.nodeType == 3) {
43608 ac = ac.parentNode;
43611 var ar = ac.childNodes;
43614 var other_nodes = [];
43615 var has_other_nodes = false;
43616 for (var i=0;i<ar.length;i++) {
43617 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43620 // fullly contained node.
43622 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43627 // probably selected..
43628 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43629 other_nodes.push(ar[i]);
43633 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43638 has_other_nodes = true;
43640 if (!nodes.length && other_nodes.length) {
43641 nodes= other_nodes;
43643 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43649 createRange: function(sel)
43651 // this has strange effects when using with
43652 // top toolbar - not sure if it's a great idea.
43653 //this.editor.contentWindow.focus();
43654 if (typeof sel != "undefined") {
43656 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43658 return this.doc.createRange();
43661 return this.doc.createRange();
43664 getParentElement: function()
43667 this.assignDocWin();
43668 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43670 var range = this.createRange(sel);
43673 var p = range.commonAncestorContainer;
43674 while (p.nodeType == 3) { // text node
43685 * Range intersection.. the hard stuff...
43689 * [ -- selected range --- ]
43693 * if end is before start or hits it. fail.
43694 * if start is after end or hits it fail.
43696 * if either hits (but other is outside. - then it's not
43702 // @see http://www.thismuchiknow.co.uk/?p=64.
43703 rangeIntersectsNode : function(range, node)
43705 var nodeRange = node.ownerDocument.createRange();
43707 nodeRange.selectNode(node);
43709 nodeRange.selectNodeContents(node);
43712 var rangeStartRange = range.cloneRange();
43713 rangeStartRange.collapse(true);
43715 var rangeEndRange = range.cloneRange();
43716 rangeEndRange.collapse(false);
43718 var nodeStartRange = nodeRange.cloneRange();
43719 nodeStartRange.collapse(true);
43721 var nodeEndRange = nodeRange.cloneRange();
43722 nodeEndRange.collapse(false);
43724 return rangeStartRange.compareBoundaryPoints(
43725 Range.START_TO_START, nodeEndRange) == -1 &&
43726 rangeEndRange.compareBoundaryPoints(
43727 Range.START_TO_START, nodeStartRange) == 1;
43731 rangeCompareNode : function(range, node)
43733 var nodeRange = node.ownerDocument.createRange();
43735 nodeRange.selectNode(node);
43737 nodeRange.selectNodeContents(node);
43741 range.collapse(true);
43743 nodeRange.collapse(true);
43745 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43746 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43748 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43750 var nodeIsBefore = ss == 1;
43751 var nodeIsAfter = ee == -1;
43753 if (nodeIsBefore && nodeIsAfter) {
43756 if (!nodeIsBefore && nodeIsAfter) {
43757 return 1; //right trailed.
43760 if (nodeIsBefore && !nodeIsAfter) {
43761 return 2; // left trailed.
43767 // private? - in a new class?
43768 cleanUpPaste : function()
43770 // cleans up the whole document..
43771 Roo.log('cleanuppaste');
43773 this.cleanUpChildren(this.doc.body);
43774 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43775 if (clean != this.doc.body.innerHTML) {
43776 this.doc.body.innerHTML = clean;
43781 cleanWordChars : function(input) {// change the chars to hex code
43782 var he = Roo.HtmlEditorCore;
43784 var output = input;
43785 Roo.each(he.swapCodes, function(sw) {
43786 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43788 output = output.replace(swapper, sw[1]);
43795 cleanUpChildren : function (n)
43797 if (!n.childNodes.length) {
43800 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43801 this.cleanUpChild(n.childNodes[i]);
43808 cleanUpChild : function (node)
43811 //console.log(node);
43812 if (node.nodeName == "#text") {
43813 // clean up silly Windows -- stuff?
43816 if (node.nodeName == "#comment") {
43817 node.parentNode.removeChild(node);
43818 // clean up silly Windows -- stuff?
43821 var lcname = node.tagName.toLowerCase();
43822 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43823 // whitelist of tags..
43825 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43827 node.parentNode.removeChild(node);
43832 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43834 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43835 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43837 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43838 // remove_keep_children = true;
43841 if (remove_keep_children) {
43842 this.cleanUpChildren(node);
43843 // inserts everything just before this node...
43844 while (node.childNodes.length) {
43845 var cn = node.childNodes[0];
43846 node.removeChild(cn);
43847 node.parentNode.insertBefore(cn, node);
43849 node.parentNode.removeChild(node);
43853 if (!node.attributes || !node.attributes.length) {
43854 this.cleanUpChildren(node);
43858 function cleanAttr(n,v)
43861 if (v.match(/^\./) || v.match(/^\//)) {
43864 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
43867 if (v.match(/^#/)) {
43870 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43871 node.removeAttribute(n);
43875 var cwhite = this.cwhite;
43876 var cblack = this.cblack;
43878 function cleanStyle(n,v)
43880 if (v.match(/expression/)) { //XSS?? should we even bother..
43881 node.removeAttribute(n);
43885 var parts = v.split(/;/);
43888 Roo.each(parts, function(p) {
43889 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43893 var l = p.split(':').shift().replace(/\s+/g,'');
43894 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43896 if ( cwhite.length && cblack.indexOf(l) > -1) {
43897 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43898 //node.removeAttribute(n);
43902 // only allow 'c whitelisted system attributes'
43903 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43904 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43905 //node.removeAttribute(n);
43915 if (clean.length) {
43916 node.setAttribute(n, clean.join(';'));
43918 node.removeAttribute(n);
43924 for (var i = node.attributes.length-1; i > -1 ; i--) {
43925 var a = node.attributes[i];
43928 if (a.name.toLowerCase().substr(0,2)=='on') {
43929 node.removeAttribute(a.name);
43932 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43933 node.removeAttribute(a.name);
43936 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43937 cleanAttr(a.name,a.value); // fixme..
43940 if (a.name == 'style') {
43941 cleanStyle(a.name,a.value);
43944 /// clean up MS crap..
43945 // tecnically this should be a list of valid class'es..
43948 if (a.name == 'class') {
43949 if (a.value.match(/^Mso/)) {
43950 node.className = '';
43953 if (a.value.match(/^body$/)) {
43954 node.className = '';
43965 this.cleanUpChildren(node);
43971 * Clean up MS wordisms...
43973 cleanWord : function(node)
43978 this.cleanWord(this.doc.body);
43981 if (node.nodeName == "#text") {
43982 // clean up silly Windows -- stuff?
43985 if (node.nodeName == "#comment") {
43986 node.parentNode.removeChild(node);
43987 // clean up silly Windows -- stuff?
43991 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43992 node.parentNode.removeChild(node);
43996 // remove - but keep children..
43997 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43998 while (node.childNodes.length) {
43999 var cn = node.childNodes[0];
44000 node.removeChild(cn);
44001 node.parentNode.insertBefore(cn, node);
44003 node.parentNode.removeChild(node);
44004 this.iterateChildren(node, this.cleanWord);
44008 if (node.className.length) {
44010 var cn = node.className.split(/\W+/);
44012 Roo.each(cn, function(cls) {
44013 if (cls.match(/Mso[a-zA-Z]+/)) {
44018 node.className = cna.length ? cna.join(' ') : '';
44020 node.removeAttribute("class");
44024 if (node.hasAttribute("lang")) {
44025 node.removeAttribute("lang");
44028 if (node.hasAttribute("style")) {
44030 var styles = node.getAttribute("style").split(";");
44032 Roo.each(styles, function(s) {
44033 if (!s.match(/:/)) {
44036 var kv = s.split(":");
44037 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44040 // what ever is left... we allow.
44043 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44044 if (!nstyle.length) {
44045 node.removeAttribute('style');
44048 this.iterateChildren(node, this.cleanWord);
44054 * iterateChildren of a Node, calling fn each time, using this as the scole..
44055 * @param {DomNode} node node to iterate children of.
44056 * @param {Function} fn method of this class to call on each item.
44058 iterateChildren : function(node, fn)
44060 if (!node.childNodes.length) {
44063 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44064 fn.call(this, node.childNodes[i])
44070 * cleanTableWidths.
44072 * Quite often pasting from word etc.. results in tables with column and widths.
44073 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44076 cleanTableWidths : function(node)
44081 this.cleanTableWidths(this.doc.body);
44086 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44089 Roo.log(node.tagName);
44090 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44091 this.iterateChildren(node, this.cleanTableWidths);
44094 if (node.hasAttribute('width')) {
44095 node.removeAttribute('width');
44099 if (node.hasAttribute("style")) {
44102 var styles = node.getAttribute("style").split(";");
44104 Roo.each(styles, function(s) {
44105 if (!s.match(/:/)) {
44108 var kv = s.split(":");
44109 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44112 // what ever is left... we allow.
44115 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44116 if (!nstyle.length) {
44117 node.removeAttribute('style');
44121 this.iterateChildren(node, this.cleanTableWidths);
44129 domToHTML : function(currentElement, depth, nopadtext) {
44131 depth = depth || 0;
44132 nopadtext = nopadtext || false;
44134 if (!currentElement) {
44135 return this.domToHTML(this.doc.body);
44138 //Roo.log(currentElement);
44140 var allText = false;
44141 var nodeName = currentElement.nodeName;
44142 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44144 if (nodeName == '#text') {
44146 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44151 if (nodeName != 'BODY') {
44154 // Prints the node tagName, such as <A>, <IMG>, etc
44157 for(i = 0; i < currentElement.attributes.length;i++) {
44159 var aname = currentElement.attributes.item(i).name;
44160 if (!currentElement.attributes.item(i).value.length) {
44163 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44166 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44175 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44178 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44183 // Traverse the tree
44185 var currentElementChild = currentElement.childNodes.item(i);
44186 var allText = true;
44187 var innerHTML = '';
44189 while (currentElementChild) {
44190 // Formatting code (indent the tree so it looks nice on the screen)
44191 var nopad = nopadtext;
44192 if (lastnode == 'SPAN') {
44196 if (currentElementChild.nodeName == '#text') {
44197 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44198 toadd = nopadtext ? toadd : toadd.trim();
44199 if (!nopad && toadd.length > 80) {
44200 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44202 innerHTML += toadd;
44205 currentElementChild = currentElement.childNodes.item(i);
44211 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44213 // Recursively traverse the tree structure of the child node
44214 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44215 lastnode = currentElementChild.nodeName;
44217 currentElementChild=currentElement.childNodes.item(i);
44223 // The remaining code is mostly for formatting the tree
44224 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44229 ret+= "</"+tagName+">";
44235 applyBlacklists : function()
44237 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44238 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44242 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44243 if (b.indexOf(tag) > -1) {
44246 this.white.push(tag);
44250 Roo.each(w, function(tag) {
44251 if (b.indexOf(tag) > -1) {
44254 if (this.white.indexOf(tag) > -1) {
44257 this.white.push(tag);
44262 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44263 if (w.indexOf(tag) > -1) {
44266 this.black.push(tag);
44270 Roo.each(b, function(tag) {
44271 if (w.indexOf(tag) > -1) {
44274 if (this.black.indexOf(tag) > -1) {
44277 this.black.push(tag);
44282 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44283 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44287 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44288 if (b.indexOf(tag) > -1) {
44291 this.cwhite.push(tag);
44295 Roo.each(w, function(tag) {
44296 if (b.indexOf(tag) > -1) {
44299 if (this.cwhite.indexOf(tag) > -1) {
44302 this.cwhite.push(tag);
44307 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44308 if (w.indexOf(tag) > -1) {
44311 this.cblack.push(tag);
44315 Roo.each(b, function(tag) {
44316 if (w.indexOf(tag) > -1) {
44319 if (this.cblack.indexOf(tag) > -1) {
44322 this.cblack.push(tag);
44327 setStylesheets : function(stylesheets)
44329 if(typeof(stylesheets) == 'string'){
44330 Roo.get(this.iframe.contentDocument.head).createChild({
44332 rel : 'stylesheet',
44341 Roo.each(stylesheets, function(s) {
44346 Roo.get(_this.iframe.contentDocument.head).createChild({
44348 rel : 'stylesheet',
44357 removeStylesheets : function()
44361 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44366 setStyle : function(style)
44368 Roo.get(this.iframe.contentDocument.head).createChild({
44377 // hide stuff that is not compatible
44391 * @event specialkey
44395 * @cfg {String} fieldClass @hide
44398 * @cfg {String} focusClass @hide
44401 * @cfg {String} autoCreate @hide
44404 * @cfg {String} inputType @hide
44407 * @cfg {String} invalidClass @hide
44410 * @cfg {String} invalidText @hide
44413 * @cfg {String} msgFx @hide
44416 * @cfg {String} validateOnBlur @hide
44420 Roo.HtmlEditorCore.white = [
44421 'area', 'br', 'img', 'input', 'hr', 'wbr',
44423 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44424 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44425 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44426 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44427 'table', 'ul', 'xmp',
44429 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44432 'dir', 'menu', 'ol', 'ul', 'dl',
44438 Roo.HtmlEditorCore.black = [
44439 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44441 'base', 'basefont', 'bgsound', 'blink', 'body',
44442 'frame', 'frameset', 'head', 'html', 'ilayer',
44443 'iframe', 'layer', 'link', 'meta', 'object',
44444 'script', 'style' ,'title', 'xml' // clean later..
44446 Roo.HtmlEditorCore.clean = [
44447 'script', 'style', 'title', 'xml'
44449 Roo.HtmlEditorCore.remove = [
44454 Roo.HtmlEditorCore.ablack = [
44458 Roo.HtmlEditorCore.aclean = [
44459 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44463 Roo.HtmlEditorCore.pwhite= [
44464 'http', 'https', 'mailto'
44467 // white listed style attributes.
44468 Roo.HtmlEditorCore.cwhite= [
44469 // 'text-align', /// default is to allow most things..
44475 // black listed style attributes.
44476 Roo.HtmlEditorCore.cblack= [
44477 // 'font-size' -- this can be set by the project
44481 Roo.HtmlEditorCore.swapCodes =[
44492 //<script type="text/javascript">
44495 * Ext JS Library 1.1.1
44496 * Copyright(c) 2006-2007, Ext JS, LLC.
44502 Roo.form.HtmlEditor = function(config){
44506 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44508 if (!this.toolbars) {
44509 this.toolbars = [];
44511 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44517 * @class Roo.form.HtmlEditor
44518 * @extends Roo.form.Field
44519 * Provides a lightweight HTML Editor component.
44521 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44523 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44524 * supported by this editor.</b><br/><br/>
44525 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44526 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44528 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44530 * @cfg {Boolean} clearUp
44534 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44539 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44544 * @cfg {Number} height (in pixels)
44548 * @cfg {Number} width (in pixels)
44553 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44556 stylesheets: false,
44560 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44565 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44571 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44576 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44584 // private properties
44585 validationEvent : false,
44587 initialized : false,
44590 onFocus : Roo.emptyFn,
44592 hideMode:'offsets',
44594 actionMode : 'container', // defaults to hiding it...
44596 defaultAutoCreate : { // modified by initCompnoent..
44598 style:"width:500px;height:300px;",
44599 autocomplete: "new-password"
44603 initComponent : function(){
44606 * @event initialize
44607 * Fires when the editor is fully initialized (including the iframe)
44608 * @param {HtmlEditor} this
44613 * Fires when the editor is first receives the focus. Any insertion must wait
44614 * until after this event.
44615 * @param {HtmlEditor} this
44619 * @event beforesync
44620 * Fires before the textarea is updated with content from the editor iframe. Return false
44621 * to cancel the sync.
44622 * @param {HtmlEditor} this
44623 * @param {String} html
44627 * @event beforepush
44628 * Fires before the iframe editor is updated with content from the textarea. Return false
44629 * to cancel the push.
44630 * @param {HtmlEditor} this
44631 * @param {String} html
44636 * Fires when the textarea is updated with content from the editor iframe.
44637 * @param {HtmlEditor} this
44638 * @param {String} html
44643 * Fires when the iframe editor is updated with content from the textarea.
44644 * @param {HtmlEditor} this
44645 * @param {String} html
44649 * @event editmodechange
44650 * Fires when the editor switches edit modes
44651 * @param {HtmlEditor} this
44652 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44654 editmodechange: true,
44656 * @event editorevent
44657 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44658 * @param {HtmlEditor} this
44662 * @event firstfocus
44663 * Fires when on first focus - needed by toolbars..
44664 * @param {HtmlEditor} this
44669 * Auto save the htmlEditor value as a file into Events
44670 * @param {HtmlEditor} this
44674 * @event savedpreview
44675 * preview the saved version of htmlEditor
44676 * @param {HtmlEditor} this
44678 savedpreview: true,
44681 * @event stylesheetsclick
44682 * Fires when press the Sytlesheets button
44683 * @param {Roo.HtmlEditorCore} this
44685 stylesheetsclick: true
44687 this.defaultAutoCreate = {
44689 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44690 autocomplete: "new-password"
44695 * Protected method that will not generally be called directly. It
44696 * is called when the editor creates its toolbar. Override this method if you need to
44697 * add custom toolbar buttons.
44698 * @param {HtmlEditor} editor
44700 createToolbar : function(editor){
44701 Roo.log("create toolbars");
44702 if (!editor.toolbars || !editor.toolbars.length) {
44703 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44706 for (var i =0 ; i < editor.toolbars.length;i++) {
44707 editor.toolbars[i] = Roo.factory(
44708 typeof(editor.toolbars[i]) == 'string' ?
44709 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44710 Roo.form.HtmlEditor);
44711 editor.toolbars[i].init(editor);
44719 onRender : function(ct, position)
44722 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44724 this.wrap = this.el.wrap({
44725 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44728 this.editorcore.onRender(ct, position);
44730 if (this.resizable) {
44731 this.resizeEl = new Roo.Resizable(this.wrap, {
44735 minHeight : this.height,
44736 height: this.height,
44737 handles : this.resizable,
44740 resize : function(r, w, h) {
44741 _t.onResize(w,h); // -something
44747 this.createToolbar(this);
44751 this.setSize(this.wrap.getSize());
44753 if (this.resizeEl) {
44754 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44755 // should trigger onReize..
44758 this.keyNav = new Roo.KeyNav(this.el, {
44760 "tab" : function(e){
44761 e.preventDefault();
44763 var value = this.getValue();
44765 var start = this.el.dom.selectionStart;
44766 var end = this.el.dom.selectionEnd;
44770 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44771 this.el.dom.setSelectionRange(end + 1, end + 1);
44775 var f = value.substring(0, start).split("\t");
44777 if(f.pop().length != 0){
44781 this.setValue(f.join("\t") + value.substring(end));
44782 this.el.dom.setSelectionRange(start - 1, start - 1);
44786 "home" : function(e){
44787 e.preventDefault();
44789 var curr = this.el.dom.selectionStart;
44790 var lines = this.getValue().split("\n");
44797 this.el.dom.setSelectionRange(0, 0);
44803 for (var i = 0; i < lines.length;i++) {
44804 pos += lines[i].length;
44814 pos -= lines[i].length;
44820 this.el.dom.setSelectionRange(pos, pos);
44824 this.el.dom.selectionStart = pos;
44825 this.el.dom.selectionEnd = curr;
44828 "end" : function(e){
44829 e.preventDefault();
44831 var curr = this.el.dom.selectionStart;
44832 var lines = this.getValue().split("\n");
44839 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44845 for (var i = 0; i < lines.length;i++) {
44847 pos += lines[i].length;
44861 this.el.dom.setSelectionRange(pos, pos);
44865 this.el.dom.selectionStart = curr;
44866 this.el.dom.selectionEnd = pos;
44871 doRelay : function(foo, bar, hname){
44872 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44878 // if(this.autosave && this.w){
44879 // this.autoSaveFn = setInterval(this.autosave, 1000);
44884 onResize : function(w, h)
44886 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44891 if(typeof w == 'number'){
44892 var aw = w - this.wrap.getFrameWidth('lr');
44893 this.el.setWidth(this.adjustWidth('textarea', aw));
44896 if(typeof h == 'number'){
44898 for (var i =0; i < this.toolbars.length;i++) {
44899 // fixme - ask toolbars for heights?
44900 tbh += this.toolbars[i].tb.el.getHeight();
44901 if (this.toolbars[i].footer) {
44902 tbh += this.toolbars[i].footer.el.getHeight();
44909 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44910 ah -= 5; // knock a few pixes off for look..
44912 this.el.setHeight(this.adjustWidth('textarea', ah));
44916 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44917 this.editorcore.onResize(ew,eh);
44922 * Toggles the editor between standard and source edit mode.
44923 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44925 toggleSourceEdit : function(sourceEditMode)
44927 this.editorcore.toggleSourceEdit(sourceEditMode);
44929 if(this.editorcore.sourceEditMode){
44930 Roo.log('editor - showing textarea');
44933 // Roo.log(this.syncValue());
44934 this.editorcore.syncValue();
44935 this.el.removeClass('x-hidden');
44936 this.el.dom.removeAttribute('tabIndex');
44939 for (var i = 0; i < this.toolbars.length; i++) {
44940 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44941 this.toolbars[i].tb.hide();
44942 this.toolbars[i].footer.hide();
44947 Roo.log('editor - hiding textarea');
44949 // Roo.log(this.pushValue());
44950 this.editorcore.pushValue();
44952 this.el.addClass('x-hidden');
44953 this.el.dom.setAttribute('tabIndex', -1);
44955 for (var i = 0; i < this.toolbars.length; i++) {
44956 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44957 this.toolbars[i].tb.show();
44958 this.toolbars[i].footer.show();
44962 //this.deferFocus();
44965 this.setSize(this.wrap.getSize());
44966 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44968 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44971 // private (for BoxComponent)
44972 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44974 // private (for BoxComponent)
44975 getResizeEl : function(){
44979 // private (for BoxComponent)
44980 getPositionEl : function(){
44985 initEvents : function(){
44986 this.originalValue = this.getValue();
44990 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44993 markInvalid : Roo.emptyFn,
44995 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44998 clearInvalid : Roo.emptyFn,
45000 setValue : function(v){
45001 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45002 this.editorcore.pushValue();
45007 deferFocus : function(){
45008 this.focus.defer(10, this);
45012 focus : function(){
45013 this.editorcore.focus();
45019 onDestroy : function(){
45025 for (var i =0; i < this.toolbars.length;i++) {
45026 // fixme - ask toolbars for heights?
45027 this.toolbars[i].onDestroy();
45030 this.wrap.dom.innerHTML = '';
45031 this.wrap.remove();
45036 onFirstFocus : function(){
45037 //Roo.log("onFirstFocus");
45038 this.editorcore.onFirstFocus();
45039 for (var i =0; i < this.toolbars.length;i++) {
45040 this.toolbars[i].onFirstFocus();
45046 syncValue : function()
45048 this.editorcore.syncValue();
45051 pushValue : function()
45053 this.editorcore.pushValue();
45056 setStylesheets : function(stylesheets)
45058 this.editorcore.setStylesheets(stylesheets);
45061 removeStylesheets : function()
45063 this.editorcore.removeStylesheets();
45067 // hide stuff that is not compatible
45081 * @event specialkey
45085 * @cfg {String} fieldClass @hide
45088 * @cfg {String} focusClass @hide
45091 * @cfg {String} autoCreate @hide
45094 * @cfg {String} inputType @hide
45097 * @cfg {String} invalidClass @hide
45100 * @cfg {String} invalidText @hide
45103 * @cfg {String} msgFx @hide
45106 * @cfg {String} validateOnBlur @hide
45110 // <script type="text/javascript">
45113 * Ext JS Library 1.1.1
45114 * Copyright(c) 2006-2007, Ext JS, LLC.
45120 * @class Roo.form.HtmlEditorToolbar1
45125 new Roo.form.HtmlEditor({
45128 new Roo.form.HtmlEditorToolbar1({
45129 disable : { fonts: 1 , format: 1, ..., ... , ...],
45135 * @cfg {Object} disable List of elements to disable..
45136 * @cfg {Array} btns List of additional buttons.
45140 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45143 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45146 Roo.apply(this, config);
45148 // default disabled, based on 'good practice'..
45149 this.disable = this.disable || {};
45150 Roo.applyIf(this.disable, {
45153 specialElements : true
45157 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45158 // dont call parent... till later.
45161 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45168 editorcore : false,
45170 * @cfg {Object} disable List of toolbar elements to disable
45177 * @cfg {String} createLinkText The default text for the create link prompt
45179 createLinkText : 'Please enter the URL for the link:',
45181 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45183 defaultLinkValue : 'http:/'+'/',
45187 * @cfg {Array} fontFamilies An array of available font families
45205 // "á" , ?? a acute?
45210 "°" // , // degrees
45212 // "é" , // e ecute
45213 // "ú" , // u ecute?
45216 specialElements : [
45218 text: "Insert Table",
45221 ihtml : '<table><tr><td>Cell</td></tr></table>'
45225 text: "Insert Image",
45228 ihtml : '<img src="about:blank"/>'
45237 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45238 "input:submit", "input:button", "select", "textarea", "label" ],
45241 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45243 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45251 * @cfg {String} defaultFont default font to use.
45253 defaultFont: 'tahoma',
45255 fontSelect : false,
45258 formatCombo : false,
45260 init : function(editor)
45262 this.editor = editor;
45263 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45264 var editorcore = this.editorcore;
45268 var fid = editorcore.frameId;
45270 function btn(id, toggle, handler){
45271 var xid = fid + '-'+ id ;
45275 cls : 'x-btn-icon x-edit-'+id,
45276 enableToggle:toggle !== false,
45277 scope: _t, // was editor...
45278 handler:handler||_t.relayBtnCmd,
45279 clickEvent:'mousedown',
45280 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45287 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45289 // stop form submits
45290 tb.el.on('click', function(e){
45291 e.preventDefault(); // what does this do?
45294 if(!this.disable.font) { // && !Roo.isSafari){
45295 /* why no safari for fonts
45296 editor.fontSelect = tb.el.createChild({
45299 cls:'x-font-select',
45300 html: this.createFontOptions()
45303 editor.fontSelect.on('change', function(){
45304 var font = editor.fontSelect.dom.value;
45305 editor.relayCmd('fontname', font);
45306 editor.deferFocus();
45310 editor.fontSelect.dom,
45316 if(!this.disable.formats){
45317 this.formatCombo = new Roo.form.ComboBox({
45318 store: new Roo.data.SimpleStore({
45321 data : this.formats // from states.js
45325 //autoCreate : {tag: "div", size: "20"},
45326 displayField:'tag',
45330 triggerAction: 'all',
45331 emptyText:'Add tag',
45332 selectOnFocus:true,
45335 'select': function(c, r, i) {
45336 editorcore.insertTag(r.get('tag'));
45342 tb.addField(this.formatCombo);
45346 if(!this.disable.format){
45351 btn('strikethrough')
45354 if(!this.disable.fontSize){
45359 btn('increasefontsize', false, editorcore.adjustFont),
45360 btn('decreasefontsize', false, editorcore.adjustFont)
45365 if(!this.disable.colors){
45368 id:editorcore.frameId +'-forecolor',
45369 cls:'x-btn-icon x-edit-forecolor',
45370 clickEvent:'mousedown',
45371 tooltip: this.buttonTips['forecolor'] || undefined,
45373 menu : new Roo.menu.ColorMenu({
45374 allowReselect: true,
45375 focus: Roo.emptyFn,
45378 selectHandler: function(cp, color){
45379 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45380 editor.deferFocus();
45383 clickEvent:'mousedown'
45386 id:editorcore.frameId +'backcolor',
45387 cls:'x-btn-icon x-edit-backcolor',
45388 clickEvent:'mousedown',
45389 tooltip: this.buttonTips['backcolor'] || undefined,
45391 menu : new Roo.menu.ColorMenu({
45392 focus: Roo.emptyFn,
45395 allowReselect: true,
45396 selectHandler: function(cp, color){
45398 editorcore.execCmd('useCSS', false);
45399 editorcore.execCmd('hilitecolor', color);
45400 editorcore.execCmd('useCSS', true);
45401 editor.deferFocus();
45403 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45404 Roo.isSafari || Roo.isIE ? '#'+color : color);
45405 editor.deferFocus();
45409 clickEvent:'mousedown'
45414 // now add all the items...
45417 if(!this.disable.alignments){
45420 btn('justifyleft'),
45421 btn('justifycenter'),
45422 btn('justifyright')
45426 //if(!Roo.isSafari){
45427 if(!this.disable.links){
45430 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45434 if(!this.disable.lists){
45437 btn('insertorderedlist'),
45438 btn('insertunorderedlist')
45441 if(!this.disable.sourceEdit){
45444 btn('sourceedit', true, function(btn){
45445 this.toggleSourceEdit(btn.pressed);
45452 // special menu.. - needs to be tidied up..
45453 if (!this.disable.special) {
45456 cls: 'x-edit-none',
45462 for (var i =0; i < this.specialChars.length; i++) {
45463 smenu.menu.items.push({
45465 html: this.specialChars[i],
45466 handler: function(a,b) {
45467 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45468 //editor.insertAtCursor(a.html);
45482 if (!this.disable.cleanStyles) {
45484 cls: 'x-btn-icon x-btn-clear',
45490 for (var i =0; i < this.cleanStyles.length; i++) {
45491 cmenu.menu.items.push({
45492 actiontype : this.cleanStyles[i],
45493 html: 'Remove ' + this.cleanStyles[i],
45494 handler: function(a,b) {
45497 var c = Roo.get(editorcore.doc.body);
45498 c.select('[style]').each(function(s) {
45499 s.dom.style.removeProperty(a.actiontype);
45501 editorcore.syncValue();
45506 cmenu.menu.items.push({
45507 actiontype : 'tablewidths',
45508 html: 'Remove Table Widths',
45509 handler: function(a,b) {
45510 editorcore.cleanTableWidths();
45511 editorcore.syncValue();
45515 cmenu.menu.items.push({
45516 actiontype : 'word',
45517 html: 'Remove MS Word Formating',
45518 handler: function(a,b) {
45519 editorcore.cleanWord();
45520 editorcore.syncValue();
45525 cmenu.menu.items.push({
45526 actiontype : 'all',
45527 html: 'Remove All Styles',
45528 handler: function(a,b) {
45530 var c = Roo.get(editorcore.doc.body);
45531 c.select('[style]').each(function(s) {
45532 s.dom.removeAttribute('style');
45534 editorcore.syncValue();
45539 cmenu.menu.items.push({
45540 actiontype : 'all',
45541 html: 'Remove All CSS Classes',
45542 handler: function(a,b) {
45544 var c = Roo.get(editorcore.doc.body);
45545 c.select('[class]').each(function(s) {
45546 s.dom.className = '';
45548 editorcore.syncValue();
45553 cmenu.menu.items.push({
45554 actiontype : 'tidy',
45555 html: 'Tidy HTML Source',
45556 handler: function(a,b) {
45557 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45558 editorcore.syncValue();
45567 if (!this.disable.specialElements) {
45570 cls: 'x-edit-none',
45575 for (var i =0; i < this.specialElements.length; i++) {
45576 semenu.menu.items.push(
45578 handler: function(a,b) {
45579 editor.insertAtCursor(this.ihtml);
45581 }, this.specialElements[i])
45593 for(var i =0; i< this.btns.length;i++) {
45594 var b = Roo.factory(this.btns[i],Roo.form);
45595 b.cls = 'x-edit-none';
45597 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45598 b.cls += ' x-init-enable';
45601 b.scope = editorcore;
45609 // disable everything...
45611 this.tb.items.each(function(item){
45614 item.id != editorcore.frameId+ '-sourceedit' &&
45615 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45621 this.rendered = true;
45623 // the all the btns;
45624 editor.on('editorevent', this.updateToolbar, this);
45625 // other toolbars need to implement this..
45626 //editor.on('editmodechange', this.updateToolbar, this);
45630 relayBtnCmd : function(btn) {
45631 this.editorcore.relayCmd(btn.cmd);
45633 // private used internally
45634 createLink : function(){
45635 Roo.log("create link?");
45636 var url = prompt(this.createLinkText, this.defaultLinkValue);
45637 if(url && url != 'http:/'+'/'){
45638 this.editorcore.relayCmd('createlink', url);
45644 * Protected method that will not generally be called directly. It triggers
45645 * a toolbar update by reading the markup state of the current selection in the editor.
45647 updateToolbar: function(){
45649 if(!this.editorcore.activated){
45650 this.editor.onFirstFocus();
45654 var btns = this.tb.items.map,
45655 doc = this.editorcore.doc,
45656 frameId = this.editorcore.frameId;
45658 if(!this.disable.font && !Roo.isSafari){
45660 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45661 if(name != this.fontSelect.dom.value){
45662 this.fontSelect.dom.value = name;
45666 if(!this.disable.format){
45667 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45668 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45669 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45670 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45672 if(!this.disable.alignments){
45673 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45674 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45675 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45677 if(!Roo.isSafari && !this.disable.lists){
45678 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45679 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45682 var ans = this.editorcore.getAllAncestors();
45683 if (this.formatCombo) {
45686 var store = this.formatCombo.store;
45687 this.formatCombo.setValue("");
45688 for (var i =0; i < ans.length;i++) {
45689 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45691 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45699 // hides menus... - so this cant be on a menu...
45700 Roo.menu.MenuMgr.hideAll();
45702 //this.editorsyncValue();
45706 createFontOptions : function(){
45707 var buf = [], fs = this.fontFamilies, ff, lc;
45711 for(var i = 0, len = fs.length; i< len; i++){
45713 lc = ff.toLowerCase();
45715 '<option value="',lc,'" style="font-family:',ff,';"',
45716 (this.defaultFont == lc ? ' selected="true">' : '>'),
45721 return buf.join('');
45724 toggleSourceEdit : function(sourceEditMode){
45726 Roo.log("toolbar toogle");
45727 if(sourceEditMode === undefined){
45728 sourceEditMode = !this.sourceEditMode;
45730 this.sourceEditMode = sourceEditMode === true;
45731 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45732 // just toggle the button?
45733 if(btn.pressed !== this.sourceEditMode){
45734 btn.toggle(this.sourceEditMode);
45738 if(sourceEditMode){
45739 Roo.log("disabling buttons");
45740 this.tb.items.each(function(item){
45741 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45747 Roo.log("enabling buttons");
45748 if(this.editorcore.initialized){
45749 this.tb.items.each(function(item){
45755 Roo.log("calling toggole on editor");
45756 // tell the editor that it's been pressed..
45757 this.editor.toggleSourceEdit(sourceEditMode);
45761 * Object collection of toolbar tooltips for the buttons in the editor. The key
45762 * is the command id associated with that button and the value is a valid QuickTips object.
45767 title: 'Bold (Ctrl+B)',
45768 text: 'Make the selected text bold.',
45769 cls: 'x-html-editor-tip'
45772 title: 'Italic (Ctrl+I)',
45773 text: 'Make the selected text italic.',
45774 cls: 'x-html-editor-tip'
45782 title: 'Bold (Ctrl+B)',
45783 text: 'Make the selected text bold.',
45784 cls: 'x-html-editor-tip'
45787 title: 'Italic (Ctrl+I)',
45788 text: 'Make the selected text italic.',
45789 cls: 'x-html-editor-tip'
45792 title: 'Underline (Ctrl+U)',
45793 text: 'Underline the selected text.',
45794 cls: 'x-html-editor-tip'
45797 title: 'Strikethrough',
45798 text: 'Strikethrough the selected text.',
45799 cls: 'x-html-editor-tip'
45801 increasefontsize : {
45802 title: 'Grow Text',
45803 text: 'Increase the font size.',
45804 cls: 'x-html-editor-tip'
45806 decreasefontsize : {
45807 title: 'Shrink Text',
45808 text: 'Decrease the font size.',
45809 cls: 'x-html-editor-tip'
45812 title: 'Text Highlight Color',
45813 text: 'Change the background color of the selected text.',
45814 cls: 'x-html-editor-tip'
45817 title: 'Font Color',
45818 text: 'Change the color of the selected text.',
45819 cls: 'x-html-editor-tip'
45822 title: 'Align Text Left',
45823 text: 'Align text to the left.',
45824 cls: 'x-html-editor-tip'
45827 title: 'Center Text',
45828 text: 'Center text in the editor.',
45829 cls: 'x-html-editor-tip'
45832 title: 'Align Text Right',
45833 text: 'Align text to the right.',
45834 cls: 'x-html-editor-tip'
45836 insertunorderedlist : {
45837 title: 'Bullet List',
45838 text: 'Start a bulleted list.',
45839 cls: 'x-html-editor-tip'
45841 insertorderedlist : {
45842 title: 'Numbered List',
45843 text: 'Start a numbered list.',
45844 cls: 'x-html-editor-tip'
45847 title: 'Hyperlink',
45848 text: 'Make the selected text a hyperlink.',
45849 cls: 'x-html-editor-tip'
45852 title: 'Source Edit',
45853 text: 'Switch to source editing mode.',
45854 cls: 'x-html-editor-tip'
45858 onDestroy : function(){
45861 this.tb.items.each(function(item){
45863 item.menu.removeAll();
45865 item.menu.el.destroy();
45873 onFirstFocus: function() {
45874 this.tb.items.each(function(item){
45883 // <script type="text/javascript">
45886 * Ext JS Library 1.1.1
45887 * Copyright(c) 2006-2007, Ext JS, LLC.
45894 * @class Roo.form.HtmlEditor.ToolbarContext
45899 new Roo.form.HtmlEditor({
45902 { xtype: 'ToolbarStandard', styles : {} }
45903 { xtype: 'ToolbarContext', disable : {} }
45909 * @config : {Object} disable List of elements to disable.. (not done yet.)
45910 * @config : {Object} styles Map of styles available.
45914 Roo.form.HtmlEditor.ToolbarContext = function(config)
45917 Roo.apply(this, config);
45918 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45919 // dont call parent... till later.
45920 this.styles = this.styles || {};
45925 Roo.form.HtmlEditor.ToolbarContext.types = {
45937 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46003 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46008 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46018 style : 'fontFamily',
46019 displayField: 'display',
46020 optname : 'font-family',
46069 // should we really allow this??
46070 // should this just be
46081 style : 'fontFamily',
46082 displayField: 'display',
46083 optname : 'font-family',
46090 style : 'fontFamily',
46091 displayField: 'display',
46092 optname : 'font-family',
46099 style : 'fontFamily',
46100 displayField: 'display',
46101 optname : 'font-family',
46112 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46113 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46115 Roo.form.HtmlEditor.ToolbarContext.options = {
46117 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46118 [ 'Courier New', 'Courier New'],
46119 [ 'Tahoma', 'Tahoma'],
46120 [ 'Times New Roman,serif', 'Times'],
46121 [ 'Verdana','Verdana' ]
46125 // fixme - these need to be configurable..
46128 //Roo.form.HtmlEditor.ToolbarContext.types
46131 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46138 editorcore : false,
46140 * @cfg {Object} disable List of toolbar elements to disable
46145 * @cfg {Object} styles List of styles
46146 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46148 * These must be defined in the page, so they get rendered correctly..
46159 init : function(editor)
46161 this.editor = editor;
46162 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46163 var editorcore = this.editorcore;
46165 var fid = editorcore.frameId;
46167 function btn(id, toggle, handler){
46168 var xid = fid + '-'+ id ;
46172 cls : 'x-btn-icon x-edit-'+id,
46173 enableToggle:toggle !== false,
46174 scope: editorcore, // was editor...
46175 handler:handler||editorcore.relayBtnCmd,
46176 clickEvent:'mousedown',
46177 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46181 // create a new element.
46182 var wdiv = editor.wrap.createChild({
46184 }, editor.wrap.dom.firstChild.nextSibling, true);
46186 // can we do this more than once??
46188 // stop form submits
46191 // disable everything...
46192 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46193 this.toolbars = {};
46195 for (var i in ty) {
46197 this.toolbars[i] = this.buildToolbar(ty[i],i);
46199 this.tb = this.toolbars.BODY;
46201 this.buildFooter();
46202 this.footer.show();
46203 editor.on('hide', function( ) { this.footer.hide() }, this);
46204 editor.on('show', function( ) { this.footer.show() }, this);
46207 this.rendered = true;
46209 // the all the btns;
46210 editor.on('editorevent', this.updateToolbar, this);
46211 // other toolbars need to implement this..
46212 //editor.on('editmodechange', this.updateToolbar, this);
46218 * Protected method that will not generally be called directly. It triggers
46219 * a toolbar update by reading the markup state of the current selection in the editor.
46221 * Note you can force an update by calling on('editorevent', scope, false)
46223 updateToolbar: function(editor,ev,sel){
46226 // capture mouse up - this is handy for selecting images..
46227 // perhaps should go somewhere else...
46228 if(!this.editorcore.activated){
46229 this.editor.onFirstFocus();
46235 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46236 // selectNode - might want to handle IE?
46238 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46239 ev.target && ev.target.tagName == 'IMG') {
46240 // they have click on an image...
46241 // let's see if we can change the selection...
46244 var nodeRange = sel.ownerDocument.createRange();
46246 nodeRange.selectNode(sel);
46248 nodeRange.selectNodeContents(sel);
46250 //nodeRange.collapse(true);
46251 var s = this.editorcore.win.getSelection();
46252 s.removeAllRanges();
46253 s.addRange(nodeRange);
46257 var updateFooter = sel ? false : true;
46260 var ans = this.editorcore.getAllAncestors();
46263 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46266 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46267 sel = sel ? sel : this.editorcore.doc.body;
46268 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46271 // pick a menu that exists..
46272 var tn = sel.tagName.toUpperCase();
46273 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46275 tn = sel.tagName.toUpperCase();
46277 var lastSel = this.tb.selectedNode;
46279 this.tb.selectedNode = sel;
46281 // if current menu does not match..
46283 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46286 ///console.log("show: " + tn);
46287 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46290 this.tb.items.first().el.innerHTML = tn + ': ';
46293 // update attributes
46294 if (this.tb.fields) {
46295 this.tb.fields.each(function(e) {
46297 e.setValue(sel.style[e.stylename]);
46300 e.setValue(sel.getAttribute(e.attrname));
46304 var hasStyles = false;
46305 for(var i in this.styles) {
46312 var st = this.tb.fields.item(0);
46314 st.store.removeAll();
46317 var cn = sel.className.split(/\s+/);
46320 if (this.styles['*']) {
46322 Roo.each(this.styles['*'], function(v) {
46323 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46326 if (this.styles[tn]) {
46327 Roo.each(this.styles[tn], function(v) {
46328 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46332 st.store.loadData(avs);
46336 // flag our selected Node.
46337 this.tb.selectedNode = sel;
46340 Roo.menu.MenuMgr.hideAll();
46344 if (!updateFooter) {
46345 //this.footDisp.dom.innerHTML = '';
46348 // update the footer
46352 this.footerEls = ans.reverse();
46353 Roo.each(this.footerEls, function(a,i) {
46354 if (!a) { return; }
46355 html += html.length ? ' > ' : '';
46357 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46362 var sz = this.footDisp.up('td').getSize();
46363 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46364 this.footDisp.dom.style.marginLeft = '5px';
46366 this.footDisp.dom.style.overflow = 'hidden';
46368 this.footDisp.dom.innerHTML = html;
46370 //this.editorsyncValue();
46377 onDestroy : function(){
46380 this.tb.items.each(function(item){
46382 item.menu.removeAll();
46384 item.menu.el.destroy();
46392 onFirstFocus: function() {
46393 // need to do this for all the toolbars..
46394 this.tb.items.each(function(item){
46398 buildToolbar: function(tlist, nm)
46400 var editor = this.editor;
46401 var editorcore = this.editorcore;
46402 // create a new element.
46403 var wdiv = editor.wrap.createChild({
46405 }, editor.wrap.dom.firstChild.nextSibling, true);
46408 var tb = new Roo.Toolbar(wdiv);
46411 tb.add(nm+ ": ");
46414 for(var i in this.styles) {
46419 if (styles && styles.length) {
46421 // this needs a multi-select checkbox...
46422 tb.addField( new Roo.form.ComboBox({
46423 store: new Roo.data.SimpleStore({
46425 fields: ['val', 'selected'],
46428 name : '-roo-edit-className',
46429 attrname : 'className',
46430 displayField: 'val',
46434 triggerAction: 'all',
46435 emptyText:'Select Style',
46436 selectOnFocus:true,
46439 'select': function(c, r, i) {
46440 // initial support only for on class per el..
46441 tb.selectedNode.className = r ? r.get('val') : '';
46442 editorcore.syncValue();
46449 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46450 var tbops = tbc.options;
46452 for (var i in tlist) {
46454 var item = tlist[i];
46455 tb.add(item.title + ": ");
46458 //optname == used so you can configure the options available..
46459 var opts = item.opts ? item.opts : false;
46460 if (item.optname) {
46461 opts = tbops[item.optname];
46466 // opts == pulldown..
46467 tb.addField( new Roo.form.ComboBox({
46468 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46470 fields: ['val', 'display'],
46473 name : '-roo-edit-' + i,
46475 stylename : item.style ? item.style : false,
46476 displayField: item.displayField ? item.displayField : 'val',
46477 valueField : 'val',
46479 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46481 triggerAction: 'all',
46482 emptyText:'Select',
46483 selectOnFocus:true,
46484 width: item.width ? item.width : 130,
46486 'select': function(c, r, i) {
46488 tb.selectedNode.style[c.stylename] = r.get('val');
46491 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46500 tb.addField( new Roo.form.TextField({
46503 //allowBlank:false,
46508 tb.addField( new Roo.form.TextField({
46509 name: '-roo-edit-' + i,
46516 'change' : function(f, nv, ov) {
46517 tb.selectedNode.setAttribute(f.attrname, nv);
46518 editorcore.syncValue();
46531 text: 'Stylesheets',
46534 click : function ()
46536 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46544 text: 'Remove Tag',
46547 click : function ()
46550 // undo does not work.
46552 var sn = tb.selectedNode;
46554 var pn = sn.parentNode;
46556 var stn = sn.childNodes[0];
46557 var en = sn.childNodes[sn.childNodes.length - 1 ];
46558 while (sn.childNodes.length) {
46559 var node = sn.childNodes[0];
46560 sn.removeChild(node);
46562 pn.insertBefore(node, sn);
46565 pn.removeChild(sn);
46566 var range = editorcore.createRange();
46568 range.setStart(stn,0);
46569 range.setEnd(en,0); //????
46570 //range.selectNode(sel);
46573 var selection = editorcore.getSelection();
46574 selection.removeAllRanges();
46575 selection.addRange(range);
46579 //_this.updateToolbar(null, null, pn);
46580 _this.updateToolbar(null, null, null);
46581 _this.footDisp.dom.innerHTML = '';
46591 tb.el.on('click', function(e){
46592 e.preventDefault(); // what does this do?
46594 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46597 // dont need to disable them... as they will get hidden
46602 buildFooter : function()
46605 var fel = this.editor.wrap.createChild();
46606 this.footer = new Roo.Toolbar(fel);
46607 // toolbar has scrolly on left / right?
46608 var footDisp= new Roo.Toolbar.Fill();
46614 handler : function() {
46615 _t.footDisp.scrollTo('left',0,true)
46619 this.footer.add( footDisp );
46624 handler : function() {
46626 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46630 var fel = Roo.get(footDisp.el);
46631 fel.addClass('x-editor-context');
46632 this.footDispWrap = fel;
46633 this.footDispWrap.overflow = 'hidden';
46635 this.footDisp = fel.createChild();
46636 this.footDispWrap.on('click', this.onContextClick, this)
46640 onContextClick : function (ev,dom)
46642 ev.preventDefault();
46643 var cn = dom.className;
46645 if (!cn.match(/x-ed-loc-/)) {
46648 var n = cn.split('-').pop();
46649 var ans = this.footerEls;
46653 var range = this.editorcore.createRange();
46655 range.selectNodeContents(sel);
46656 //range.selectNode(sel);
46659 var selection = this.editorcore.getSelection();
46660 selection.removeAllRanges();
46661 selection.addRange(range);
46665 this.updateToolbar(null, null, sel);
46682 * Ext JS Library 1.1.1
46683 * Copyright(c) 2006-2007, Ext JS, LLC.
46685 * Originally Released Under LGPL - original licence link has changed is not relivant.
46688 * <script type="text/javascript">
46692 * @class Roo.form.BasicForm
46693 * @extends Roo.util.Observable
46694 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46696 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46697 * @param {Object} config Configuration options
46699 Roo.form.BasicForm = function(el, config){
46700 this.allItems = [];
46701 this.childForms = [];
46702 Roo.apply(this, config);
46704 * The Roo.form.Field items in this form.
46705 * @type MixedCollection
46709 this.items = new Roo.util.MixedCollection(false, function(o){
46710 return o.id || (o.id = Roo.id());
46714 * @event beforeaction
46715 * Fires before any action is performed. Return false to cancel the action.
46716 * @param {Form} this
46717 * @param {Action} action The action to be performed
46719 beforeaction: true,
46721 * @event actionfailed
46722 * Fires when an action fails.
46723 * @param {Form} this
46724 * @param {Action} action The action that failed
46726 actionfailed : true,
46728 * @event actioncomplete
46729 * Fires when an action is completed.
46730 * @param {Form} this
46731 * @param {Action} action The action that completed
46733 actioncomplete : true
46738 Roo.form.BasicForm.superclass.constructor.call(this);
46741 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46743 * @cfg {String} method
46744 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46747 * @cfg {DataReader} reader
46748 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46749 * This is optional as there is built-in support for processing JSON.
46752 * @cfg {DataReader} errorReader
46753 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46754 * This is completely optional as there is built-in support for processing JSON.
46757 * @cfg {String} url
46758 * The URL to use for form actions if one isn't supplied in the action options.
46761 * @cfg {Boolean} fileUpload
46762 * Set to true if this form is a file upload.
46766 * @cfg {Object} baseParams
46767 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46772 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46777 activeAction : null,
46780 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46781 * or setValues() data instead of when the form was first created.
46783 trackResetOnLoad : false,
46787 * childForms - used for multi-tab forms
46790 childForms : false,
46793 * allItems - full list of fields.
46799 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46800 * element by passing it or its id or mask the form itself by passing in true.
46803 waitMsgTarget : false,
46806 initEl : function(el){
46807 this.el = Roo.get(el);
46808 this.id = this.el.id || Roo.id();
46809 this.el.on('submit', this.onSubmit, this);
46810 this.el.addClass('x-form');
46814 onSubmit : function(e){
46819 * Returns true if client-side validation on the form is successful.
46822 isValid : function(){
46824 this.items.each(function(f){
46833 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46836 isDirty : function(){
46838 this.items.each(function(f){
46848 * Returns true if any fields in this form have changed since their original load. (New version)
46852 hasChanged : function()
46855 this.items.each(function(f){
46856 if(f.hasChanged()){
46865 * Resets all hasChanged to 'false' -
46866 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46867 * So hasChanged storage is only to be used for this purpose
46870 resetHasChanged : function()
46872 this.items.each(function(f){
46873 f.resetHasChanged();
46880 * Performs a predefined action (submit or load) or custom actions you define on this form.
46881 * @param {String} actionName The name of the action type
46882 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46883 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46884 * accept other config options):
46886 Property Type Description
46887 ---------------- --------------- ----------------------------------------------------------------------------------
46888 url String The url for the action (defaults to the form's url)
46889 method String The form method to use (defaults to the form's method, or POST if not defined)
46890 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46891 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46892 validate the form on the client (defaults to false)
46894 * @return {BasicForm} this
46896 doAction : function(action, options){
46897 if(typeof action == 'string'){
46898 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46900 if(this.fireEvent('beforeaction', this, action) !== false){
46901 this.beforeAction(action);
46902 action.run.defer(100, action);
46908 * Shortcut to do a submit action.
46909 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46910 * @return {BasicForm} this
46912 submit : function(options){
46913 this.doAction('submit', options);
46918 * Shortcut to do a load action.
46919 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46920 * @return {BasicForm} this
46922 load : function(options){
46923 this.doAction('load', options);
46928 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46929 * @param {Record} record The record to edit
46930 * @return {BasicForm} this
46932 updateRecord : function(record){
46933 record.beginEdit();
46934 var fs = record.fields;
46935 fs.each(function(f){
46936 var field = this.findField(f.name);
46938 record.set(f.name, field.getValue());
46946 * Loads an Roo.data.Record into this form.
46947 * @param {Record} record The record to load
46948 * @return {BasicForm} this
46950 loadRecord : function(record){
46951 this.setValues(record.data);
46956 beforeAction : function(action){
46957 var o = action.options;
46960 if(this.waitMsgTarget === true){
46961 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46962 }else if(this.waitMsgTarget){
46963 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46964 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46966 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46972 afterAction : function(action, success){
46973 this.activeAction = null;
46974 var o = action.options;
46976 if(this.waitMsgTarget === true){
46978 }else if(this.waitMsgTarget){
46979 this.waitMsgTarget.unmask();
46981 Roo.MessageBox.updateProgress(1);
46982 Roo.MessageBox.hide();
46989 Roo.callback(o.success, o.scope, [this, action]);
46990 this.fireEvent('actioncomplete', this, action);
46994 // failure condition..
46995 // we have a scenario where updates need confirming.
46996 // eg. if a locking scenario exists..
46997 // we look for { errors : { needs_confirm : true }} in the response.
46999 (typeof(action.result) != 'undefined') &&
47000 (typeof(action.result.errors) != 'undefined') &&
47001 (typeof(action.result.errors.needs_confirm) != 'undefined')
47004 Roo.MessageBox.confirm(
47005 "Change requires confirmation",
47006 action.result.errorMsg,
47011 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47021 Roo.callback(o.failure, o.scope, [this, action]);
47022 // show an error message if no failed handler is set..
47023 if (!this.hasListener('actionfailed')) {
47024 Roo.MessageBox.alert("Error",
47025 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47026 action.result.errorMsg :
47027 "Saving Failed, please check your entries or try again"
47031 this.fireEvent('actionfailed', this, action);
47037 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47038 * @param {String} id The value to search for
47041 findField : function(id){
47042 var field = this.items.get(id);
47044 this.items.each(function(f){
47045 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47051 return field || null;
47055 * Add a secondary form to this one,
47056 * Used to provide tabbed forms. One form is primary, with hidden values
47057 * which mirror the elements from the other forms.
47059 * @param {Roo.form.Form} form to add.
47062 addForm : function(form)
47065 if (this.childForms.indexOf(form) > -1) {
47069 this.childForms.push(form);
47071 Roo.each(form.allItems, function (fe) {
47073 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47074 if (this.findField(n)) { // already added..
47077 var add = new Roo.form.Hidden({
47080 add.render(this.el);
47087 * Mark fields in this form invalid in bulk.
47088 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47089 * @return {BasicForm} this
47091 markInvalid : function(errors){
47092 if(errors instanceof Array){
47093 for(var i = 0, len = errors.length; i < len; i++){
47094 var fieldError = errors[i];
47095 var f = this.findField(fieldError.id);
47097 f.markInvalid(fieldError.msg);
47103 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47104 field.markInvalid(errors[id]);
47108 Roo.each(this.childForms || [], function (f) {
47109 f.markInvalid(errors);
47116 * Set values for fields in this form in bulk.
47117 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47118 * @return {BasicForm} this
47120 setValues : function(values){
47121 if(values instanceof Array){ // array of objects
47122 for(var i = 0, len = values.length; i < len; i++){
47124 var f = this.findField(v.id);
47126 f.setValue(v.value);
47127 if(this.trackResetOnLoad){
47128 f.originalValue = f.getValue();
47132 }else{ // object hash
47135 if(typeof values[id] != 'function' && (field = this.findField(id))){
47137 if (field.setFromData &&
47138 field.valueField &&
47139 field.displayField &&
47140 // combos' with local stores can
47141 // be queried via setValue()
47142 // to set their value..
47143 (field.store && !field.store.isLocal)
47147 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47148 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47149 field.setFromData(sd);
47152 field.setValue(values[id]);
47156 if(this.trackResetOnLoad){
47157 field.originalValue = field.getValue();
47162 this.resetHasChanged();
47165 Roo.each(this.childForms || [], function (f) {
47166 f.setValues(values);
47167 f.resetHasChanged();
47174 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47175 * they are returned as an array.
47176 * @param {Boolean} asString
47179 getValues : function(asString){
47180 if (this.childForms) {
47181 // copy values from the child forms
47182 Roo.each(this.childForms, function (f) {
47183 this.setValues(f.getValues());
47189 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47190 if(asString === true){
47193 return Roo.urlDecode(fs);
47197 * Returns the fields in this form as an object with key/value pairs.
47198 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47201 getFieldValues : function(with_hidden)
47203 if (this.childForms) {
47204 // copy values from the child forms
47205 // should this call getFieldValues - probably not as we do not currently copy
47206 // hidden fields when we generate..
47207 Roo.each(this.childForms, function (f) {
47208 this.setValues(f.getValues());
47213 this.items.each(function(f){
47214 if (!f.getName()) {
47217 var v = f.getValue();
47218 if (f.inputType =='radio') {
47219 if (typeof(ret[f.getName()]) == 'undefined') {
47220 ret[f.getName()] = ''; // empty..
47223 if (!f.el.dom.checked) {
47227 v = f.el.dom.value;
47231 // not sure if this supported any more..
47232 if ((typeof(v) == 'object') && f.getRawValue) {
47233 v = f.getRawValue() ; // dates..
47235 // combo boxes where name != hiddenName...
47236 if (f.name != f.getName()) {
47237 ret[f.name] = f.getRawValue();
47239 ret[f.getName()] = v;
47246 * Clears all invalid messages in this form.
47247 * @return {BasicForm} this
47249 clearInvalid : function(){
47250 this.items.each(function(f){
47254 Roo.each(this.childForms || [], function (f) {
47263 * Resets this form.
47264 * @return {BasicForm} this
47266 reset : function(){
47267 this.items.each(function(f){
47271 Roo.each(this.childForms || [], function (f) {
47274 this.resetHasChanged();
47280 * Add Roo.form components to this form.
47281 * @param {Field} field1
47282 * @param {Field} field2 (optional)
47283 * @param {Field} etc (optional)
47284 * @return {BasicForm} this
47287 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47293 * Removes a field from the items collection (does NOT remove its markup).
47294 * @param {Field} field
47295 * @return {BasicForm} this
47297 remove : function(field){
47298 this.items.remove(field);
47303 * Looks at the fields in this form, checks them for an id attribute,
47304 * and calls applyTo on the existing dom element with that id.
47305 * @return {BasicForm} this
47307 render : function(){
47308 this.items.each(function(f){
47309 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47317 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47318 * @param {Object} values
47319 * @return {BasicForm} this
47321 applyToFields : function(o){
47322 this.items.each(function(f){
47329 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47330 * @param {Object} values
47331 * @return {BasicForm} this
47333 applyIfToFields : function(o){
47334 this.items.each(function(f){
47342 Roo.BasicForm = Roo.form.BasicForm;/*
47344 * Ext JS Library 1.1.1
47345 * Copyright(c) 2006-2007, Ext JS, LLC.
47347 * Originally Released Under LGPL - original licence link has changed is not relivant.
47350 * <script type="text/javascript">
47354 * @class Roo.form.Form
47355 * @extends Roo.form.BasicForm
47356 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47358 * @param {Object} config Configuration options
47360 Roo.form.Form = function(config){
47362 if (config.items) {
47363 xitems = config.items;
47364 delete config.items;
47368 Roo.form.Form.superclass.constructor.call(this, null, config);
47369 this.url = this.url || this.action;
47371 this.root = new Roo.form.Layout(Roo.applyIf({
47375 this.active = this.root;
47377 * Array of all the buttons that have been added to this form via {@link addButton}
47381 this.allItems = [];
47384 * @event clientvalidation
47385 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47386 * @param {Form} this
47387 * @param {Boolean} valid true if the form has passed client-side validation
47389 clientvalidation: true,
47392 * Fires when the form is rendered
47393 * @param {Roo.form.Form} form
47398 if (this.progressUrl) {
47399 // push a hidden field onto the list of fields..
47403 name : 'UPLOAD_IDENTIFIER'
47408 Roo.each(xitems, this.addxtype, this);
47414 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47416 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47419 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47422 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47424 buttonAlign:'center',
47427 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47432 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47433 * This property cascades to child containers if not set.
47438 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47439 * fires a looping event with that state. This is required to bind buttons to the valid
47440 * state using the config value formBind:true on the button.
47442 monitorValid : false,
47445 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47450 * @cfg {String} progressUrl - Url to return progress data
47453 progressUrl : false,
47455 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
47456 * sending a formdata with extra parameters - eg uploaded elements.
47462 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47463 * fields are added and the column is closed. If no fields are passed the column remains open
47464 * until end() is called.
47465 * @param {Object} config The config to pass to the column
47466 * @param {Field} field1 (optional)
47467 * @param {Field} field2 (optional)
47468 * @param {Field} etc (optional)
47469 * @return Column The column container object
47471 column : function(c){
47472 var col = new Roo.form.Column(c);
47474 if(arguments.length > 1){ // duplicate code required because of Opera
47475 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47482 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47483 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47484 * until end() is called.
47485 * @param {Object} config The config to pass to the fieldset
47486 * @param {Field} field1 (optional)
47487 * @param {Field} field2 (optional)
47488 * @param {Field} etc (optional)
47489 * @return FieldSet The fieldset container object
47491 fieldset : function(c){
47492 var fs = new Roo.form.FieldSet(c);
47494 if(arguments.length > 1){ // duplicate code required because of Opera
47495 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47502 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47503 * fields are added and the container is closed. If no fields are passed the container remains open
47504 * until end() is called.
47505 * @param {Object} config The config to pass to the Layout
47506 * @param {Field} field1 (optional)
47507 * @param {Field} field2 (optional)
47508 * @param {Field} etc (optional)
47509 * @return Layout The container object
47511 container : function(c){
47512 var l = new Roo.form.Layout(c);
47514 if(arguments.length > 1){ // duplicate code required because of Opera
47515 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47522 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47523 * @param {Object} container A Roo.form.Layout or subclass of Layout
47524 * @return {Form} this
47526 start : function(c){
47527 // cascade label info
47528 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47529 this.active.stack.push(c);
47530 c.ownerCt = this.active;
47536 * Closes the current open container
47537 * @return {Form} this
47540 if(this.active == this.root){
47543 this.active = this.active.ownerCt;
47548 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47549 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47550 * as the label of the field.
47551 * @param {Field} field1
47552 * @param {Field} field2 (optional)
47553 * @param {Field} etc. (optional)
47554 * @return {Form} this
47557 this.active.stack.push.apply(this.active.stack, arguments);
47558 this.allItems.push.apply(this.allItems,arguments);
47560 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47561 if(a[i].isFormField){
47566 Roo.form.Form.superclass.add.apply(this, r);
47576 * Find any element that has been added to a form, using it's ID or name
47577 * This can include framesets, columns etc. along with regular fields..
47578 * @param {String} id - id or name to find.
47580 * @return {Element} e - or false if nothing found.
47582 findbyId : function(id)
47588 Roo.each(this.allItems, function(f){
47589 if (f.id == id || f.name == id ){
47600 * Render this form into the passed container. This should only be called once!
47601 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47602 * @return {Form} this
47604 render : function(ct)
47610 var o = this.autoCreate || {
47612 method : this.method || 'POST',
47613 id : this.id || Roo.id()
47615 this.initEl(ct.createChild(o));
47617 this.root.render(this.el);
47621 this.items.each(function(f){
47622 f.render('x-form-el-'+f.id);
47625 if(this.buttons.length > 0){
47626 // tables are required to maintain order and for correct IE layout
47627 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47628 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47629 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47631 var tr = tb.getElementsByTagName('tr')[0];
47632 for(var i = 0, len = this.buttons.length; i < len; i++) {
47633 var b = this.buttons[i];
47634 var td = document.createElement('td');
47635 td.className = 'x-form-btn-td';
47636 b.render(tr.appendChild(td));
47639 if(this.monitorValid){ // initialize after render
47640 this.startMonitoring();
47642 this.fireEvent('rendered', this);
47647 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47648 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47649 * object or a valid Roo.DomHelper element config
47650 * @param {Function} handler The function called when the button is clicked
47651 * @param {Object} scope (optional) The scope of the handler function
47652 * @return {Roo.Button}
47654 addButton : function(config, handler, scope){
47658 minWidth: this.minButtonWidth,
47661 if(typeof config == "string"){
47664 Roo.apply(bc, config);
47666 var btn = new Roo.Button(null, bc);
47667 this.buttons.push(btn);
47672 * Adds a series of form elements (using the xtype property as the factory method.
47673 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47674 * @param {Object} config
47677 addxtype : function()
47679 var ar = Array.prototype.slice.call(arguments, 0);
47681 for(var i = 0; i < ar.length; i++) {
47683 continue; // skip -- if this happends something invalid got sent, we
47684 // should ignore it, as basically that interface element will not show up
47685 // and that should be pretty obvious!!
47688 if (Roo.form[ar[i].xtype]) {
47690 var fe = Roo.factory(ar[i], Roo.form);
47696 fe.store.form = this;
47701 this.allItems.push(fe);
47702 if (fe.items && fe.addxtype) {
47703 fe.addxtype.apply(fe, fe.items);
47713 // console.log('adding ' + ar[i].xtype);
47715 if (ar[i].xtype == 'Button') {
47716 //console.log('adding button');
47717 //console.log(ar[i]);
47718 this.addButton(ar[i]);
47719 this.allItems.push(fe);
47723 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47724 alert('end is not supported on xtype any more, use items');
47726 // //console.log('adding end');
47734 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47735 * option "monitorValid"
47737 startMonitoring : function(){
47740 Roo.TaskMgr.start({
47741 run : this.bindHandler,
47742 interval : this.monitorPoll || 200,
47749 * Stops monitoring of the valid state of this form
47751 stopMonitoring : function(){
47752 this.bound = false;
47756 bindHandler : function(){
47758 return false; // stops binding
47761 this.items.each(function(f){
47762 if(!f.isValid(true)){
47767 for(var i = 0, len = this.buttons.length; i < len; i++){
47768 var btn = this.buttons[i];
47769 if(btn.formBind === true && btn.disabled === valid){
47770 btn.setDisabled(!valid);
47773 this.fireEvent('clientvalidation', this, valid);
47787 Roo.Form = Roo.form.Form;
47790 * Ext JS Library 1.1.1
47791 * Copyright(c) 2006-2007, Ext JS, LLC.
47793 * Originally Released Under LGPL - original licence link has changed is not relivant.
47796 * <script type="text/javascript">
47799 // as we use this in bootstrap.
47800 Roo.namespace('Roo.form');
47802 * @class Roo.form.Action
47803 * Internal Class used to handle form actions
47805 * @param {Roo.form.BasicForm} el The form element or its id
47806 * @param {Object} config Configuration options
47811 // define the action interface
47812 Roo.form.Action = function(form, options){
47814 this.options = options || {};
47817 * Client Validation Failed
47820 Roo.form.Action.CLIENT_INVALID = 'client';
47822 * Server Validation Failed
47825 Roo.form.Action.SERVER_INVALID = 'server';
47827 * Connect to Server Failed
47830 Roo.form.Action.CONNECT_FAILURE = 'connect';
47832 * Reading Data from Server Failed
47835 Roo.form.Action.LOAD_FAILURE = 'load';
47837 Roo.form.Action.prototype = {
47839 failureType : undefined,
47840 response : undefined,
47841 result : undefined,
47843 // interface method
47844 run : function(options){
47848 // interface method
47849 success : function(response){
47853 // interface method
47854 handleResponse : function(response){
47858 // default connection failure
47859 failure : function(response){
47861 this.response = response;
47862 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47863 this.form.afterAction(this, false);
47866 processResponse : function(response){
47867 this.response = response;
47868 if(!response.responseText){
47871 this.result = this.handleResponse(response);
47872 return this.result;
47875 // utility functions used internally
47876 getUrl : function(appendParams){
47877 var url = this.options.url || this.form.url || this.form.el.dom.action;
47879 var p = this.getParams();
47881 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47887 getMethod : function(){
47888 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47891 getParams : function(){
47892 var bp = this.form.baseParams;
47893 var p = this.options.params;
47895 if(typeof p == "object"){
47896 p = Roo.urlEncode(Roo.applyIf(p, bp));
47897 }else if(typeof p == 'string' && bp){
47898 p += '&' + Roo.urlEncode(bp);
47901 p = Roo.urlEncode(bp);
47906 createCallback : function(){
47908 success: this.success,
47909 failure: this.failure,
47911 timeout: (this.form.timeout*1000),
47912 upload: this.form.fileUpload ? this.success : undefined
47917 Roo.form.Action.Submit = function(form, options){
47918 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47921 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47924 haveProgress : false,
47925 uploadComplete : false,
47927 // uploadProgress indicator.
47928 uploadProgress : function()
47930 if (!this.form.progressUrl) {
47934 if (!this.haveProgress) {
47935 Roo.MessageBox.progress("Uploading", "Uploading");
47937 if (this.uploadComplete) {
47938 Roo.MessageBox.hide();
47942 this.haveProgress = true;
47944 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47946 var c = new Roo.data.Connection();
47948 url : this.form.progressUrl,
47953 success : function(req){
47954 //console.log(data);
47958 rdata = Roo.decode(req.responseText)
47960 Roo.log("Invalid data from server..");
47964 if (!rdata || !rdata.success) {
47966 Roo.MessageBox.alert(Roo.encode(rdata));
47969 var data = rdata.data;
47971 if (this.uploadComplete) {
47972 Roo.MessageBox.hide();
47977 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47978 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47981 this.uploadProgress.defer(2000,this);
47984 failure: function(data) {
47985 Roo.log('progress url failed ');
47996 // run get Values on the form, so it syncs any secondary forms.
47997 this.form.getValues();
47999 var o = this.options;
48000 var method = this.getMethod();
48001 var isPost = method == 'POST';
48002 if(o.clientValidation === false || this.form.isValid()){
48004 if (this.form.progressUrl) {
48005 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48006 (new Date() * 1) + '' + Math.random());
48011 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48012 form:this.form.el.dom,
48013 url:this.getUrl(!isPost),
48015 params:isPost ? this.getParams() : null,
48016 isUpload: this.form.fileUpload,
48017 formData : this.form.formData
48020 this.uploadProgress();
48022 }else if (o.clientValidation !== false){ // client validation failed
48023 this.failureType = Roo.form.Action.CLIENT_INVALID;
48024 this.form.afterAction(this, false);
48028 success : function(response)
48030 this.uploadComplete= true;
48031 if (this.haveProgress) {
48032 Roo.MessageBox.hide();
48036 var result = this.processResponse(response);
48037 if(result === true || result.success){
48038 this.form.afterAction(this, true);
48042 this.form.markInvalid(result.errors);
48043 this.failureType = Roo.form.Action.SERVER_INVALID;
48045 this.form.afterAction(this, false);
48047 failure : function(response)
48049 this.uploadComplete= true;
48050 if (this.haveProgress) {
48051 Roo.MessageBox.hide();
48054 this.response = response;
48055 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48056 this.form.afterAction(this, false);
48059 handleResponse : function(response){
48060 if(this.form.errorReader){
48061 var rs = this.form.errorReader.read(response);
48064 for(var i = 0, len = rs.records.length; i < len; i++) {
48065 var r = rs.records[i];
48066 errors[i] = r.data;
48069 if(errors.length < 1){
48073 success : rs.success,
48079 ret = Roo.decode(response.responseText);
48083 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
48093 Roo.form.Action.Load = function(form, options){
48094 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
48095 this.reader = this.form.reader;
48098 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
48103 Roo.Ajax.request(Roo.apply(
48104 this.createCallback(), {
48105 method:this.getMethod(),
48106 url:this.getUrl(false),
48107 params:this.getParams()
48111 success : function(response){
48113 var result = this.processResponse(response);
48114 if(result === true || !result.success || !result.data){
48115 this.failureType = Roo.form.Action.LOAD_FAILURE;
48116 this.form.afterAction(this, false);
48119 this.form.clearInvalid();
48120 this.form.setValues(result.data);
48121 this.form.afterAction(this, true);
48124 handleResponse : function(response){
48125 if(this.form.reader){
48126 var rs = this.form.reader.read(response);
48127 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
48129 success : rs.success,
48133 return Roo.decode(response.responseText);
48137 Roo.form.Action.ACTION_TYPES = {
48138 'load' : Roo.form.Action.Load,
48139 'submit' : Roo.form.Action.Submit
48142 * Ext JS Library 1.1.1
48143 * Copyright(c) 2006-2007, Ext JS, LLC.
48145 * Originally Released Under LGPL - original licence link has changed is not relivant.
48148 * <script type="text/javascript">
48152 * @class Roo.form.Layout
48153 * @extends Roo.Component
48154 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48156 * @param {Object} config Configuration options
48158 Roo.form.Layout = function(config){
48160 if (config.items) {
48161 xitems = config.items;
48162 delete config.items;
48164 Roo.form.Layout.superclass.constructor.call(this, config);
48166 Roo.each(xitems, this.addxtype, this);
48170 Roo.extend(Roo.form.Layout, Roo.Component, {
48172 * @cfg {String/Object} autoCreate
48173 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48176 * @cfg {String/Object/Function} style
48177 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48178 * a function which returns such a specification.
48181 * @cfg {String} labelAlign
48182 * Valid values are "left," "top" and "right" (defaults to "left")
48185 * @cfg {Number} labelWidth
48186 * Fixed width in pixels of all field labels (defaults to undefined)
48189 * @cfg {Boolean} clear
48190 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48194 * @cfg {String} labelSeparator
48195 * The separator to use after field labels (defaults to ':')
48197 labelSeparator : ':',
48199 * @cfg {Boolean} hideLabels
48200 * True to suppress the display of field labels in this layout (defaults to false)
48202 hideLabels : false,
48205 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48210 onRender : function(ct, position){
48211 if(this.el){ // from markup
48212 this.el = Roo.get(this.el);
48213 }else { // generate
48214 var cfg = this.getAutoCreate();
48215 this.el = ct.createChild(cfg, position);
48218 this.el.applyStyles(this.style);
48220 if(this.labelAlign){
48221 this.el.addClass('x-form-label-'+this.labelAlign);
48223 if(this.hideLabels){
48224 this.labelStyle = "display:none";
48225 this.elementStyle = "padding-left:0;";
48227 if(typeof this.labelWidth == 'number'){
48228 this.labelStyle = "width:"+this.labelWidth+"px;";
48229 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48231 if(this.labelAlign == 'top'){
48232 this.labelStyle = "width:auto;";
48233 this.elementStyle = "padding-left:0;";
48236 var stack = this.stack;
48237 var slen = stack.length;
48239 if(!this.fieldTpl){
48240 var t = new Roo.Template(
48241 '<div class="x-form-item {5}">',
48242 '<label for="{0}" style="{2}">{1}{4}</label>',
48243 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48245 '</div><div class="x-form-clear-left"></div>'
48247 t.disableFormats = true;
48249 Roo.form.Layout.prototype.fieldTpl = t;
48251 for(var i = 0; i < slen; i++) {
48252 if(stack[i].isFormField){
48253 this.renderField(stack[i]);
48255 this.renderComponent(stack[i]);
48260 this.el.createChild({cls:'x-form-clear'});
48265 renderField : function(f){
48266 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48269 f.labelStyle||this.labelStyle||'', //2
48270 this.elementStyle||'', //3
48271 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48272 f.itemCls||this.itemCls||'' //5
48273 ], true).getPrevSibling());
48277 renderComponent : function(c){
48278 c.render(c.isLayout ? this.el : this.el.createChild());
48281 * Adds a object form elements (using the xtype property as the factory method.)
48282 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48283 * @param {Object} config
48285 addxtype : function(o)
48287 // create the lement.
48288 o.form = this.form;
48289 var fe = Roo.factory(o, Roo.form);
48290 this.form.allItems.push(fe);
48291 this.stack.push(fe);
48293 if (fe.isFormField) {
48294 this.form.items.add(fe);
48302 * @class Roo.form.Column
48303 * @extends Roo.form.Layout
48304 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48306 * @param {Object} config Configuration options
48308 Roo.form.Column = function(config){
48309 Roo.form.Column.superclass.constructor.call(this, config);
48312 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48314 * @cfg {Number/String} width
48315 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48318 * @cfg {String/Object} autoCreate
48319 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48323 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48326 onRender : function(ct, position){
48327 Roo.form.Column.superclass.onRender.call(this, ct, position);
48329 this.el.setWidth(this.width);
48336 * @class Roo.form.Row
48337 * @extends Roo.form.Layout
48338 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48340 * @param {Object} config Configuration options
48344 Roo.form.Row = function(config){
48345 Roo.form.Row.superclass.constructor.call(this, config);
48348 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48350 * @cfg {Number/String} width
48351 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48354 * @cfg {Number/String} height
48355 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48357 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48361 onRender : function(ct, position){
48362 //console.log('row render');
48364 var t = new Roo.Template(
48365 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48366 '<label for="{0}" style="{2}">{1}{4}</label>',
48367 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48371 t.disableFormats = true;
48373 Roo.form.Layout.prototype.rowTpl = t;
48375 this.fieldTpl = this.rowTpl;
48377 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48378 var labelWidth = 100;
48380 if ((this.labelAlign != 'top')) {
48381 if (typeof this.labelWidth == 'number') {
48382 labelWidth = this.labelWidth
48384 this.padWidth = 20 + labelWidth;
48388 Roo.form.Column.superclass.onRender.call(this, ct, position);
48390 this.el.setWidth(this.width);
48393 this.el.setHeight(this.height);
48398 renderField : function(f){
48399 f.fieldEl = this.fieldTpl.append(this.el, [
48400 f.id, f.fieldLabel,
48401 f.labelStyle||this.labelStyle||'',
48402 this.elementStyle||'',
48403 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48404 f.itemCls||this.itemCls||'',
48405 f.width ? f.width + this.padWidth : 160 + this.padWidth
48412 * @class Roo.form.FieldSet
48413 * @extends Roo.form.Layout
48414 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48416 * @param {Object} config Configuration options
48418 Roo.form.FieldSet = function(config){
48419 Roo.form.FieldSet.superclass.constructor.call(this, config);
48422 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48424 * @cfg {String} legend
48425 * The text to display as the legend for the FieldSet (defaults to '')
48428 * @cfg {String/Object} autoCreate
48429 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48433 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48436 onRender : function(ct, position){
48437 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48439 this.setLegend(this.legend);
48444 setLegend : function(text){
48446 this.el.child('legend').update(text);
48451 * Ext JS Library 1.1.1
48452 * Copyright(c) 2006-2007, Ext JS, LLC.
48454 * Originally Released Under LGPL - original licence link has changed is not relivant.
48457 * <script type="text/javascript">
48460 * @class Roo.form.VTypes
48461 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48464 Roo.form.VTypes = function(){
48465 // closure these in so they are only created once.
48466 var alpha = /^[a-zA-Z_]+$/;
48467 var alphanum = /^[a-zA-Z0-9_]+$/;
48468 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48469 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48471 // All these messages and functions are configurable
48474 * The function used to validate email addresses
48475 * @param {String} value The email address
48477 'email' : function(v){
48478 return email.test(v);
48481 * The error text to display when the email validation function returns false
48484 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48486 * The keystroke filter mask to be applied on email input
48489 'emailMask' : /[a-z0-9_\.\-@]/i,
48492 * The function used to validate URLs
48493 * @param {String} value The URL
48495 'url' : function(v){
48496 return url.test(v);
48499 * The error text to display when the url validation function returns false
48502 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48505 * The function used to validate alpha values
48506 * @param {String} value The value
48508 'alpha' : function(v){
48509 return alpha.test(v);
48512 * The error text to display when the alpha validation function returns false
48515 'alphaText' : 'This field should only contain letters and _',
48517 * The keystroke filter mask to be applied on alpha input
48520 'alphaMask' : /[a-z_]/i,
48523 * The function used to validate alphanumeric values
48524 * @param {String} value The value
48526 'alphanum' : function(v){
48527 return alphanum.test(v);
48530 * The error text to display when the alphanumeric validation function returns false
48533 'alphanumText' : 'This field should only contain letters, numbers and _',
48535 * The keystroke filter mask to be applied on alphanumeric input
48538 'alphanumMask' : /[a-z0-9_]/i
48540 }();//<script type="text/javascript">
48543 * @class Roo.form.FCKeditor
48544 * @extends Roo.form.TextArea
48545 * Wrapper around the FCKEditor http://www.fckeditor.net
48547 * Creates a new FCKeditor
48548 * @param {Object} config Configuration options
48550 Roo.form.FCKeditor = function(config){
48551 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48554 * @event editorinit
48555 * Fired when the editor is initialized - you can add extra handlers here..
48556 * @param {FCKeditor} this
48557 * @param {Object} the FCK object.
48564 Roo.form.FCKeditor.editors = { };
48565 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48567 //defaultAutoCreate : {
48568 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48572 * @cfg {Object} fck options - see fck manual for details.
48577 * @cfg {Object} fck toolbar set (Basic or Default)
48579 toolbarSet : 'Basic',
48581 * @cfg {Object} fck BasePath
48583 basePath : '/fckeditor/',
48591 onRender : function(ct, position)
48594 this.defaultAutoCreate = {
48596 style:"width:300px;height:60px;",
48597 autocomplete: "new-password"
48600 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48603 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48604 if(this.preventScrollbars){
48605 this.el.setStyle("overflow", "hidden");
48607 this.el.setHeight(this.growMin);
48610 //console.log('onrender' + this.getId() );
48611 Roo.form.FCKeditor.editors[this.getId()] = this;
48614 this.replaceTextarea() ;
48618 getEditor : function() {
48619 return this.fckEditor;
48622 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48623 * @param {Mixed} value The value to set
48627 setValue : function(value)
48629 //console.log('setValue: ' + value);
48631 if(typeof(value) == 'undefined') { // not sure why this is happending...
48634 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48636 //if(!this.el || !this.getEditor()) {
48637 // this.value = value;
48638 //this.setValue.defer(100,this,[value]);
48642 if(!this.getEditor()) {
48646 this.getEditor().SetData(value);
48653 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48654 * @return {Mixed} value The field value
48656 getValue : function()
48659 if (this.frame && this.frame.dom.style.display == 'none') {
48660 return Roo.form.FCKeditor.superclass.getValue.call(this);
48663 if(!this.el || !this.getEditor()) {
48665 // this.getValue.defer(100,this);
48670 var value=this.getEditor().GetData();
48671 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48672 return Roo.form.FCKeditor.superclass.getValue.call(this);
48678 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48679 * @return {Mixed} value The field value
48681 getRawValue : function()
48683 if (this.frame && this.frame.dom.style.display == 'none') {
48684 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48687 if(!this.el || !this.getEditor()) {
48688 //this.getRawValue.defer(100,this);
48695 var value=this.getEditor().GetData();
48696 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48697 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48701 setSize : function(w,h) {
48705 //if (this.frame && this.frame.dom.style.display == 'none') {
48706 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48709 //if(!this.el || !this.getEditor()) {
48710 // this.setSize.defer(100,this, [w,h]);
48716 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48718 this.frame.dom.setAttribute('width', w);
48719 this.frame.dom.setAttribute('height', h);
48720 this.frame.setSize(w,h);
48724 toggleSourceEdit : function(value) {
48728 this.el.dom.style.display = value ? '' : 'none';
48729 this.frame.dom.style.display = value ? 'none' : '';
48734 focus: function(tag)
48736 if (this.frame.dom.style.display == 'none') {
48737 return Roo.form.FCKeditor.superclass.focus.call(this);
48739 if(!this.el || !this.getEditor()) {
48740 this.focus.defer(100,this, [tag]);
48747 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48748 this.getEditor().Focus();
48750 if (!this.getEditor().Selection.GetSelection()) {
48751 this.focus.defer(100,this, [tag]);
48756 var r = this.getEditor().EditorDocument.createRange();
48757 r.setStart(tgs[0],0);
48758 r.setEnd(tgs[0],0);
48759 this.getEditor().Selection.GetSelection().removeAllRanges();
48760 this.getEditor().Selection.GetSelection().addRange(r);
48761 this.getEditor().Focus();
48768 replaceTextarea : function()
48770 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48773 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48775 // We must check the elements firstly using the Id and then the name.
48776 var oTextarea = document.getElementById( this.getId() );
48778 var colElementsByName = document.getElementsByName( this.getId() ) ;
48780 oTextarea.style.display = 'none' ;
48782 if ( oTextarea.tabIndex ) {
48783 this.TabIndex = oTextarea.tabIndex ;
48786 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48787 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48788 this.frame = Roo.get(this.getId() + '___Frame')
48791 _getConfigHtml : function()
48795 for ( var o in this.fckconfig ) {
48796 sConfig += sConfig.length > 0 ? '&' : '';
48797 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48800 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48804 _getIFrameHtml : function()
48806 var sFile = 'fckeditor.html' ;
48807 /* no idea what this is about..
48810 if ( (/fcksource=true/i).test( window.top.location.search ) )
48811 sFile = 'fckeditor.original.html' ;
48816 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48817 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48820 var html = '<iframe id="' + this.getId() +
48821 '___Frame" src="' + sLink +
48822 '" width="' + this.width +
48823 '" height="' + this.height + '"' +
48824 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48825 ' frameborder="0" scrolling="no"></iframe>' ;
48830 _insertHtmlBefore : function( html, element )
48832 if ( element.insertAdjacentHTML ) {
48834 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48836 var oRange = document.createRange() ;
48837 oRange.setStartBefore( element ) ;
48838 var oFragment = oRange.createContextualFragment( html );
48839 element.parentNode.insertBefore( oFragment, element ) ;
48852 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48854 function FCKeditor_OnComplete(editorInstance){
48855 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48856 f.fckEditor = editorInstance;
48857 //console.log("loaded");
48858 f.fireEvent('editorinit', f, editorInstance);
48878 //<script type="text/javascript">
48880 * @class Roo.form.GridField
48881 * @extends Roo.form.Field
48882 * Embed a grid (or editable grid into a form)
48885 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48887 * xgrid.store = Roo.data.Store
48888 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48889 * xgrid.store.reader = Roo.data.JsonReader
48893 * Creates a new GridField
48894 * @param {Object} config Configuration options
48896 Roo.form.GridField = function(config){
48897 Roo.form.GridField.superclass.constructor.call(this, config);
48901 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48903 * @cfg {Number} width - used to restrict width of grid..
48907 * @cfg {Number} height - used to restrict height of grid..
48911 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48917 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48918 * {tag: "input", type: "checkbox", autocomplete: "off"})
48920 // defaultAutoCreate : { tag: 'div' },
48921 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48923 * @cfg {String} addTitle Text to include for adding a title.
48927 onResize : function(){
48928 Roo.form.Field.superclass.onResize.apply(this, arguments);
48931 initEvents : function(){
48932 // Roo.form.Checkbox.superclass.initEvents.call(this);
48933 // has no events...
48938 getResizeEl : function(){
48942 getPositionEl : function(){
48947 onRender : function(ct, position){
48949 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48950 var style = this.style;
48953 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48954 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48955 this.viewEl = this.wrap.createChild({ tag: 'div' });
48957 this.viewEl.applyStyles(style);
48960 this.viewEl.setWidth(this.width);
48963 this.viewEl.setHeight(this.height);
48965 //if(this.inputValue !== undefined){
48966 //this.setValue(this.value);
48969 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48972 this.grid.render();
48973 this.grid.getDataSource().on('remove', this.refreshValue, this);
48974 this.grid.getDataSource().on('update', this.refreshValue, this);
48975 this.grid.on('afteredit', this.refreshValue, this);
48981 * Sets the value of the item.
48982 * @param {String} either an object or a string..
48984 setValue : function(v){
48986 v = v || []; // empty set..
48987 // this does not seem smart - it really only affects memoryproxy grids..
48988 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48989 var ds = this.grid.getDataSource();
48990 // assumes a json reader..
48992 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48993 ds.loadData( data);
48995 // clear selection so it does not get stale.
48996 if (this.grid.sm) {
48997 this.grid.sm.clearSelections();
49000 Roo.form.GridField.superclass.setValue.call(this, v);
49001 this.refreshValue();
49002 // should load data in the grid really....
49006 refreshValue: function() {
49008 this.grid.getDataSource().each(function(r) {
49011 this.el.dom.value = Roo.encode(val);
49019 * Ext JS Library 1.1.1
49020 * Copyright(c) 2006-2007, Ext JS, LLC.
49022 * Originally Released Under LGPL - original licence link has changed is not relivant.
49025 * <script type="text/javascript">
49028 * @class Roo.form.DisplayField
49029 * @extends Roo.form.Field
49030 * A generic Field to display non-editable data.
49031 * @cfg {Boolean} closable (true|false) default false
49033 * Creates a new Display Field item.
49034 * @param {Object} config Configuration options
49036 Roo.form.DisplayField = function(config){
49037 Roo.form.DisplayField.superclass.constructor.call(this, config);
49042 * Fires after the click the close btn
49043 * @param {Roo.form.DisplayField} this
49049 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
49050 inputType: 'hidden',
49056 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49058 focusClass : undefined,
49060 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49062 fieldClass: 'x-form-field',
49065 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
49067 valueRenderer: undefined,
49071 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49072 * {tag: "input", type: "checkbox", autocomplete: "off"})
49075 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
49079 onResize : function(){
49080 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
49084 initEvents : function(){
49085 // Roo.form.Checkbox.superclass.initEvents.call(this);
49086 // has no events...
49089 this.closeEl.on('click', this.onClose, this);
49095 getResizeEl : function(){
49099 getPositionEl : function(){
49104 onRender : function(ct, position){
49106 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
49107 //if(this.inputValue !== undefined){
49108 this.wrap = this.el.wrap();
49110 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
49113 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
49116 if (this.bodyStyle) {
49117 this.viewEl.applyStyles(this.bodyStyle);
49119 //this.viewEl.setStyle('padding', '2px');
49121 this.setValue(this.value);
49126 initValue : Roo.emptyFn,
49131 onClick : function(){
49136 * Sets the checked state of the checkbox.
49137 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49139 setValue : function(v){
49141 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49142 // this might be called before we have a dom element..
49143 if (!this.viewEl) {
49146 this.viewEl.dom.innerHTML = html;
49147 Roo.form.DisplayField.superclass.setValue.call(this, v);
49151 onClose : function(e)
49153 e.preventDefault();
49155 this.fireEvent('close', this);
49164 * @class Roo.form.DayPicker
49165 * @extends Roo.form.Field
49166 * A Day picker show [M] [T] [W] ....
49168 * Creates a new Day Picker
49169 * @param {Object} config Configuration options
49171 Roo.form.DayPicker= function(config){
49172 Roo.form.DayPicker.superclass.constructor.call(this, config);
49176 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49178 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49180 focusClass : undefined,
49182 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49184 fieldClass: "x-form-field",
49187 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49188 * {tag: "input", type: "checkbox", autocomplete: "off"})
49190 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49193 actionMode : 'viewEl',
49197 inputType : 'hidden',
49200 inputElement: false, // real input element?
49201 basedOn: false, // ????
49203 isFormField: true, // not sure where this is needed!!!!
49205 onResize : function(){
49206 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49207 if(!this.boxLabel){
49208 this.el.alignTo(this.wrap, 'c-c');
49212 initEvents : function(){
49213 Roo.form.Checkbox.superclass.initEvents.call(this);
49214 this.el.on("click", this.onClick, this);
49215 this.el.on("change", this.onClick, this);
49219 getResizeEl : function(){
49223 getPositionEl : function(){
49229 onRender : function(ct, position){
49230 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49232 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49234 var r1 = '<table><tr>';
49235 var r2 = '<tr class="x-form-daypick-icons">';
49236 for (var i=0; i < 7; i++) {
49237 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49238 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49241 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49242 viewEl.select('img').on('click', this.onClick, this);
49243 this.viewEl = viewEl;
49246 // this will not work on Chrome!!!
49247 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49248 this.el.on('propertychange', this.setFromHidden, this); //ie
49256 initValue : Roo.emptyFn,
49259 * Returns the checked state of the checkbox.
49260 * @return {Boolean} True if checked, else false
49262 getValue : function(){
49263 return this.el.dom.value;
49268 onClick : function(e){
49269 //this.setChecked(!this.checked);
49270 Roo.get(e.target).toggleClass('x-menu-item-checked');
49271 this.refreshValue();
49272 //if(this.el.dom.checked != this.checked){
49273 // this.setValue(this.el.dom.checked);
49278 refreshValue : function()
49281 this.viewEl.select('img',true).each(function(e,i,n) {
49282 val += e.is(".x-menu-item-checked") ? String(n) : '';
49284 this.setValue(val, true);
49288 * Sets the checked state of the checkbox.
49289 * On is always based on a string comparison between inputValue and the param.
49290 * @param {Boolean/String} value - the value to set
49291 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49293 setValue : function(v,suppressEvent){
49294 if (!this.el.dom) {
49297 var old = this.el.dom.value ;
49298 this.el.dom.value = v;
49299 if (suppressEvent) {
49303 // update display..
49304 this.viewEl.select('img',true).each(function(e,i,n) {
49306 var on = e.is(".x-menu-item-checked");
49307 var newv = v.indexOf(String(n)) > -1;
49309 e.toggleClass('x-menu-item-checked');
49315 this.fireEvent('change', this, v, old);
49320 // handle setting of hidden value by some other method!!?!?
49321 setFromHidden: function()
49326 //console.log("SET FROM HIDDEN");
49327 //alert('setFrom hidden');
49328 this.setValue(this.el.dom.value);
49331 onDestroy : function()
49334 Roo.get(this.viewEl).remove();
49337 Roo.form.DayPicker.superclass.onDestroy.call(this);
49341 * RooJS Library 1.1.1
49342 * Copyright(c) 2008-2011 Alan Knowles
49349 * @class Roo.form.ComboCheck
49350 * @extends Roo.form.ComboBox
49351 * A combobox for multiple select items.
49353 * FIXME - could do with a reset button..
49356 * Create a new ComboCheck
49357 * @param {Object} config Configuration options
49359 Roo.form.ComboCheck = function(config){
49360 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49361 // should verify some data...
49363 // hiddenName = required..
49364 // displayField = required
49365 // valudField == required
49366 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49368 Roo.each(req, function(e) {
49369 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49370 throw "Roo.form.ComboCheck : missing value for: " + e;
49377 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49382 selectedClass: 'x-menu-item-checked',
49385 onRender : function(ct, position){
49391 var cls = 'x-combo-list';
49394 this.tpl = new Roo.Template({
49395 html : '<div class="'+cls+'-item x-menu-check-item">' +
49396 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49397 '<span>{' + this.displayField + '}</span>' +
49404 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49405 this.view.singleSelect = false;
49406 this.view.multiSelect = true;
49407 this.view.toggleSelect = true;
49408 this.pageTb.add(new Roo.Toolbar.Fill(), {
49411 handler: function()
49418 onViewOver : function(e, t){
49424 onViewClick : function(doFocus,index){
49428 select: function () {
49429 //Roo.log("SELECT CALLED");
49432 selectByValue : function(xv, scrollIntoView){
49433 var ar = this.getValueArray();
49436 Roo.each(ar, function(v) {
49437 if(v === undefined || v === null){
49440 var r = this.findRecord(this.valueField, v);
49442 sels.push(this.store.indexOf(r))
49446 this.view.select(sels);
49452 onSelect : function(record, index){
49453 // Roo.log("onselect Called");
49454 // this is only called by the clear button now..
49455 this.view.clearSelections();
49456 this.setValue('[]');
49457 if (this.value != this.valueBefore) {
49458 this.fireEvent('change', this, this.value, this.valueBefore);
49459 this.valueBefore = this.value;
49462 getValueArray : function()
49467 //Roo.log(this.value);
49468 if (typeof(this.value) == 'undefined') {
49471 var ar = Roo.decode(this.value);
49472 return ar instanceof Array ? ar : []; //?? valid?
49475 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49480 expand : function ()
49483 Roo.form.ComboCheck.superclass.expand.call(this);
49484 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49485 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49490 collapse : function(){
49491 Roo.form.ComboCheck.superclass.collapse.call(this);
49492 var sl = this.view.getSelectedIndexes();
49493 var st = this.store;
49497 Roo.each(sl, function(i) {
49499 nv.push(r.get(this.valueField));
49501 this.setValue(Roo.encode(nv));
49502 if (this.value != this.valueBefore) {
49504 this.fireEvent('change', this, this.value, this.valueBefore);
49505 this.valueBefore = this.value;
49510 setValue : function(v){
49514 var vals = this.getValueArray();
49516 Roo.each(vals, function(k) {
49517 var r = this.findRecord(this.valueField, k);
49519 tv.push(r.data[this.displayField]);
49520 }else if(this.valueNotFoundText !== undefined){
49521 tv.push( this.valueNotFoundText );
49526 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49527 this.hiddenField.value = v;
49533 * Ext JS Library 1.1.1
49534 * Copyright(c) 2006-2007, Ext JS, LLC.
49536 * Originally Released Under LGPL - original licence link has changed is not relivant.
49539 * <script type="text/javascript">
49543 * @class Roo.form.Signature
49544 * @extends Roo.form.Field
49548 * @param {Object} config Configuration options
49551 Roo.form.Signature = function(config){
49552 Roo.form.Signature.superclass.constructor.call(this, config);
49554 this.addEvents({// not in used??
49557 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49558 * @param {Roo.form.Signature} combo This combo box
49563 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49564 * @param {Roo.form.ComboBox} combo This combo box
49565 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49571 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49573 * @cfg {Object} labels Label to use when rendering a form.
49577 * confirm : "Confirm"
49582 confirm : "Confirm"
49585 * @cfg {Number} width The signature panel width (defaults to 300)
49589 * @cfg {Number} height The signature panel height (defaults to 100)
49593 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49595 allowBlank : false,
49598 // {Object} signPanel The signature SVG panel element (defaults to {})
49600 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49601 isMouseDown : false,
49602 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49603 isConfirmed : false,
49604 // {String} signatureTmp SVG mapping string (defaults to empty string)
49608 defaultAutoCreate : { // modified by initCompnoent..
49614 onRender : function(ct, position){
49616 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49618 this.wrap = this.el.wrap({
49619 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49622 this.createToolbar(this);
49623 this.signPanel = this.wrap.createChild({
49625 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49629 this.svgID = Roo.id();
49630 this.svgEl = this.signPanel.createChild({
49631 xmlns : 'http://www.w3.org/2000/svg',
49633 id : this.svgID + "-svg",
49635 height: this.height,
49636 viewBox: '0 0 '+this.width+' '+this.height,
49640 id: this.svgID + "-svg-r",
49642 height: this.height,
49647 id: this.svgID + "-svg-l",
49649 y1: (this.height*0.8), // start set the line in 80% of height
49650 x2: this.width, // end
49651 y2: (this.height*0.8), // end set the line in 80% of height
49653 'stroke-width': "1",
49654 'stroke-dasharray': "3",
49655 'shape-rendering': "crispEdges",
49656 'pointer-events': "none"
49660 id: this.svgID + "-svg-p",
49662 'stroke-width': "3",
49664 'pointer-events': 'none'
49669 this.svgBox = this.svgEl.dom.getScreenCTM();
49671 createSVG : function(){
49672 var svg = this.signPanel;
49673 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49676 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49677 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49678 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49679 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49680 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49681 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49682 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49685 isTouchEvent : function(e){
49686 return e.type.match(/^touch/);
49688 getCoords : function (e) {
49689 var pt = this.svgEl.dom.createSVGPoint();
49692 if (this.isTouchEvent(e)) {
49693 pt.x = e.targetTouches[0].clientX;
49694 pt.y = e.targetTouches[0].clientY;
49696 var a = this.svgEl.dom.getScreenCTM();
49697 var b = a.inverse();
49698 var mx = pt.matrixTransform(b);
49699 return mx.x + ',' + mx.y;
49701 //mouse event headler
49702 down : function (e) {
49703 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49704 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49706 this.isMouseDown = true;
49708 e.preventDefault();
49710 move : function (e) {
49711 if (this.isMouseDown) {
49712 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49713 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49716 e.preventDefault();
49718 up : function (e) {
49719 this.isMouseDown = false;
49720 var sp = this.signatureTmp.split(' ');
49723 if(!sp[sp.length-2].match(/^L/)){
49727 this.signatureTmp = sp.join(" ");
49730 if(this.getValue() != this.signatureTmp){
49731 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49732 this.isConfirmed = false;
49734 e.preventDefault();
49738 * Protected method that will not generally be called directly. It
49739 * is called when the editor creates its toolbar. Override this method if you need to
49740 * add custom toolbar buttons.
49741 * @param {HtmlEditor} editor
49743 createToolbar : function(editor){
49744 function btn(id, toggle, handler){
49745 var xid = fid + '-'+ id ;
49749 cls : 'x-btn-icon x-edit-'+id,
49750 enableToggle:toggle !== false,
49751 scope: editor, // was editor...
49752 handler:handler||editor.relayBtnCmd,
49753 clickEvent:'mousedown',
49754 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49760 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49764 cls : ' x-signature-btn x-signature-'+id,
49765 scope: editor, // was editor...
49766 handler: this.reset,
49767 clickEvent:'mousedown',
49768 text: this.labels.clear
49775 cls : ' x-signature-btn x-signature-'+id,
49776 scope: editor, // was editor...
49777 handler: this.confirmHandler,
49778 clickEvent:'mousedown',
49779 text: this.labels.confirm
49786 * when user is clicked confirm then show this image.....
49788 * @return {String} Image Data URI
49790 getImageDataURI : function(){
49791 var svg = this.svgEl.dom.parentNode.innerHTML;
49792 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49797 * @return {Boolean} this.isConfirmed
49799 getConfirmed : function(){
49800 return this.isConfirmed;
49804 * @return {Number} this.width
49806 getWidth : function(){
49811 * @return {Number} this.height
49813 getHeight : function(){
49814 return this.height;
49817 getSignature : function(){
49818 return this.signatureTmp;
49821 reset : function(){
49822 this.signatureTmp = '';
49823 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49824 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49825 this.isConfirmed = false;
49826 Roo.form.Signature.superclass.reset.call(this);
49828 setSignature : function(s){
49829 this.signatureTmp = s;
49830 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49831 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49833 this.isConfirmed = false;
49834 Roo.form.Signature.superclass.reset.call(this);
49837 // Roo.log(this.signPanel.dom.contentWindow.up())
49840 setConfirmed : function(){
49844 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49847 confirmHandler : function(){
49848 if(!this.getSignature()){
49852 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49853 this.setValue(this.getSignature());
49854 this.isConfirmed = true;
49856 this.fireEvent('confirm', this);
49859 // Subclasses should provide the validation implementation by overriding this
49860 validateValue : function(value){
49861 if(this.allowBlank){
49865 if(this.isConfirmed){
49872 * Ext JS Library 1.1.1
49873 * Copyright(c) 2006-2007, Ext JS, LLC.
49875 * Originally Released Under LGPL - original licence link has changed is not relivant.
49878 * <script type="text/javascript">
49883 * @class Roo.form.ComboBox
49884 * @extends Roo.form.TriggerField
49885 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49887 * Create a new ComboBox.
49888 * @param {Object} config Configuration options
49890 Roo.form.Select = function(config){
49891 Roo.form.Select.superclass.constructor.call(this, config);
49895 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49897 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49900 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49901 * rendering into an Roo.Editor, defaults to false)
49904 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49905 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49908 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49911 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49912 * the dropdown list (defaults to undefined, with no header element)
49916 * @cfg {String/Roo.Template} tpl The template to use to render the output
49920 defaultAutoCreate : {tag: "select" },
49922 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49924 listWidth: undefined,
49926 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49927 * mode = 'remote' or 'text' if mode = 'local')
49929 displayField: undefined,
49931 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49932 * mode = 'remote' or 'value' if mode = 'local').
49933 * Note: use of a valueField requires the user make a selection
49934 * in order for a value to be mapped.
49936 valueField: undefined,
49940 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49941 * field's data value (defaults to the underlying DOM element's name)
49943 hiddenName: undefined,
49945 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49949 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49951 selectedClass: 'x-combo-selected',
49953 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49954 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49955 * which displays a downward arrow icon).
49957 triggerClass : 'x-form-arrow-trigger',
49959 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49963 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49964 * anchor positions (defaults to 'tl-bl')
49966 listAlign: 'tl-bl?',
49968 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49972 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49973 * query specified by the allQuery config option (defaults to 'query')
49975 triggerAction: 'query',
49977 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49978 * (defaults to 4, does not apply if editable = false)
49982 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49983 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49987 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49988 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49992 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49993 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49997 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49998 * when editable = true (defaults to false)
50000 selectOnFocus:false,
50002 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50004 queryParam: 'query',
50006 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50007 * when mode = 'remote' (defaults to 'Loading...')
50009 loadingText: 'Loading...',
50011 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50015 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
50019 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
50020 * traditional select (defaults to true)
50024 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
50028 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
50032 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
50033 * listWidth has a higher value)
50037 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
50038 * allow the user to set arbitrary text into the field (defaults to false)
50040 forceSelection:false,
50042 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
50043 * if typeAhead = true (defaults to 250)
50045 typeAheadDelay : 250,
50047 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
50048 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
50050 valueNotFoundText : undefined,
50053 * @cfg {String} defaultValue The value displayed after loading the store.
50058 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
50060 blockFocus : false,
50063 * @cfg {Boolean} disableClear Disable showing of clear button.
50065 disableClear : false,
50067 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
50069 alwaysQuery : false,
50075 // element that contains real text value.. (when hidden is used..)
50078 onRender : function(ct, position){
50079 Roo.form.Field.prototype.onRender.call(this, ct, position);
50082 this.store.on('beforeload', this.onBeforeLoad, this);
50083 this.store.on('load', this.onLoad, this);
50084 this.store.on('loadexception', this.onLoadException, this);
50085 this.store.load({});
50093 initEvents : function(){
50094 //Roo.form.ComboBox.superclass.initEvents.call(this);
50098 onDestroy : function(){
50101 this.store.un('beforeload', this.onBeforeLoad, this);
50102 this.store.un('load', this.onLoad, this);
50103 this.store.un('loadexception', this.onLoadException, this);
50105 //Roo.form.ComboBox.superclass.onDestroy.call(this);
50109 fireKey : function(e){
50110 if(e.isNavKeyPress() && !this.list.isVisible()){
50111 this.fireEvent("specialkey", this, e);
50116 onResize: function(w, h){
50124 * Allow or prevent the user from directly editing the field text. If false is passed,
50125 * the user will only be able to select from the items defined in the dropdown list. This method
50126 * is the runtime equivalent of setting the 'editable' config option at config time.
50127 * @param {Boolean} value True to allow the user to directly edit the field text
50129 setEditable : function(value){
50134 onBeforeLoad : function(){
50136 Roo.log("Select before load");
50139 this.innerList.update(this.loadingText ?
50140 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50141 //this.restrictHeight();
50142 this.selectedIndex = -1;
50146 onLoad : function(){
50149 var dom = this.el.dom;
50150 dom.innerHTML = '';
50151 var od = dom.ownerDocument;
50153 if (this.emptyText) {
50154 var op = od.createElement('option');
50155 op.setAttribute('value', '');
50156 op.innerHTML = String.format('{0}', this.emptyText);
50157 dom.appendChild(op);
50159 if(this.store.getCount() > 0){
50161 var vf = this.valueField;
50162 var df = this.displayField;
50163 this.store.data.each(function(r) {
50164 // which colmsn to use... testing - cdoe / title..
50165 var op = od.createElement('option');
50166 op.setAttribute('value', r.data[vf]);
50167 op.innerHTML = String.format('{0}', r.data[df]);
50168 dom.appendChild(op);
50170 if (typeof(this.defaultValue != 'undefined')) {
50171 this.setValue(this.defaultValue);
50176 //this.onEmptyResults();
50181 onLoadException : function()
50183 dom.innerHTML = '';
50185 Roo.log("Select on load exception");
50189 Roo.log(this.store.reader.jsonData);
50190 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50191 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50197 onTypeAhead : function(){
50202 onSelect : function(record, index){
50203 Roo.log('on select?');
50205 if(this.fireEvent('beforeselect', this, record, index) !== false){
50206 this.setFromData(index > -1 ? record.data : false);
50208 this.fireEvent('select', this, record, index);
50213 * Returns the currently selected field value or empty string if no value is set.
50214 * @return {String} value The selected value
50216 getValue : function(){
50217 var dom = this.el.dom;
50218 this.value = dom.options[dom.selectedIndex].value;
50224 * Clears any text/value currently set in the field
50226 clearValue : function(){
50228 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50233 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50234 * will be displayed in the field. If the value does not match the data value of an existing item,
50235 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50236 * Otherwise the field will be blank (although the value will still be set).
50237 * @param {String} value The value to match
50239 setValue : function(v){
50240 var d = this.el.dom;
50241 for (var i =0; i < d.options.length;i++) {
50242 if (v == d.options[i].value) {
50243 d.selectedIndex = i;
50251 * @property {Object} the last set data for the element
50256 * Sets the value of the field based on a object which is related to the record format for the store.
50257 * @param {Object} value the value to set as. or false on reset?
50259 setFromData : function(o){
50260 Roo.log('setfrom data?');
50266 reset : function(){
50270 findRecord : function(prop, value){
50275 if(this.store.getCount() > 0){
50276 this.store.each(function(r){
50277 if(r.data[prop] == value){
50287 getName: function()
50289 // returns hidden if it's set..
50290 if (!this.rendered) {return ''};
50291 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50299 onEmptyResults : function(){
50300 Roo.log('empty results');
50305 * Returns true if the dropdown list is expanded, else false.
50307 isExpanded : function(){
50312 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50313 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50314 * @param {String} value The data value of the item to select
50315 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50316 * selected item if it is not currently in view (defaults to true)
50317 * @return {Boolean} True if the value matched an item in the list, else false
50319 selectByValue : function(v, scrollIntoView){
50320 Roo.log('select By Value');
50323 if(v !== undefined && v !== null){
50324 var r = this.findRecord(this.valueField || this.displayField, v);
50326 this.select(this.store.indexOf(r), scrollIntoView);
50334 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50335 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50336 * @param {Number} index The zero-based index of the list item to select
50337 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50338 * selected item if it is not currently in view (defaults to true)
50340 select : function(index, scrollIntoView){
50341 Roo.log('select ');
50344 this.selectedIndex = index;
50345 this.view.select(index);
50346 if(scrollIntoView !== false){
50347 var el = this.view.getNode(index);
50349 this.innerList.scrollChildIntoView(el, false);
50357 validateBlur : function(){
50364 initQuery : function(){
50365 this.doQuery(this.getRawValue());
50369 doForce : function(){
50370 if(this.el.dom.value.length > 0){
50371 this.el.dom.value =
50372 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50378 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50379 * query allowing the query action to be canceled if needed.
50380 * @param {String} query The SQL query to execute
50381 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50382 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50383 * saved in the current store (defaults to false)
50385 doQuery : function(q, forceAll){
50387 Roo.log('doQuery?');
50388 if(q === undefined || q === null){
50393 forceAll: forceAll,
50397 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50401 forceAll = qe.forceAll;
50402 if(forceAll === true || (q.length >= this.minChars)){
50403 if(this.lastQuery != q || this.alwaysQuery){
50404 this.lastQuery = q;
50405 if(this.mode == 'local'){
50406 this.selectedIndex = -1;
50408 this.store.clearFilter();
50410 this.store.filter(this.displayField, q);
50414 this.store.baseParams[this.queryParam] = q;
50416 params: this.getParams(q)
50421 this.selectedIndex = -1;
50428 getParams : function(q){
50430 //p[this.queryParam] = q;
50433 p.limit = this.pageSize;
50439 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50441 collapse : function(){
50446 collapseIf : function(e){
50451 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50453 expand : function(){
50461 * @cfg {Boolean} grow
50465 * @cfg {Number} growMin
50469 * @cfg {Number} growMax
50477 setWidth : function()
50481 getResizeEl : function(){
50484 });//<script type="text/javasscript">
50488 * @class Roo.DDView
50489 * A DnD enabled version of Roo.View.
50490 * @param {Element/String} container The Element in which to create the View.
50491 * @param {String} tpl The template string used to create the markup for each element of the View
50492 * @param {Object} config The configuration properties. These include all the config options of
50493 * {@link Roo.View} plus some specific to this class.<br>
50495 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50496 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50498 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50499 .x-view-drag-insert-above {
50500 border-top:1px dotted #3366cc;
50502 .x-view-drag-insert-below {
50503 border-bottom:1px dotted #3366cc;
50509 Roo.DDView = function(container, tpl, config) {
50510 Roo.DDView.superclass.constructor.apply(this, arguments);
50511 this.getEl().setStyle("outline", "0px none");
50512 this.getEl().unselectable();
50513 if (this.dragGroup) {
50514 this.setDraggable(this.dragGroup.split(","));
50516 if (this.dropGroup) {
50517 this.setDroppable(this.dropGroup.split(","));
50519 if (this.deletable) {
50520 this.setDeletable();
50522 this.isDirtyFlag = false;
50528 Roo.extend(Roo.DDView, Roo.View, {
50529 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50530 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50531 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50532 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50536 reset: Roo.emptyFn,
50538 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50540 validate: function() {
50544 destroy: function() {
50545 this.purgeListeners();
50546 this.getEl.removeAllListeners();
50547 this.getEl().remove();
50548 if (this.dragZone) {
50549 if (this.dragZone.destroy) {
50550 this.dragZone.destroy();
50553 if (this.dropZone) {
50554 if (this.dropZone.destroy) {
50555 this.dropZone.destroy();
50560 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50561 getName: function() {
50565 /** Loads the View from a JSON string representing the Records to put into the Store. */
50566 setValue: function(v) {
50568 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50571 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50572 this.store.proxy = new Roo.data.MemoryProxy(data);
50576 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50577 getValue: function() {
50579 this.store.each(function(rec) {
50580 result += rec.id + ',';
50582 return result.substr(0, result.length - 1) + ')';
50585 getIds: function() {
50586 var i = 0, result = new Array(this.store.getCount());
50587 this.store.each(function(rec) {
50588 result[i++] = rec.id;
50593 isDirty: function() {
50594 return this.isDirtyFlag;
50598 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50599 * whole Element becomes the target, and this causes the drop gesture to append.
50601 getTargetFromEvent : function(e) {
50602 var target = e.getTarget();
50603 while ((target !== null) && (target.parentNode != this.el.dom)) {
50604 target = target.parentNode;
50607 target = this.el.dom.lastChild || this.el.dom;
50613 * Create the drag data which consists of an object which has the property "ddel" as
50614 * the drag proxy element.
50616 getDragData : function(e) {
50617 var target = this.findItemFromChild(e.getTarget());
50619 this.handleSelection(e);
50620 var selNodes = this.getSelectedNodes();
50623 copy: this.copy || (this.allowCopy && e.ctrlKey),
50627 var selectedIndices = this.getSelectedIndexes();
50628 for (var i = 0; i < selectedIndices.length; i++) {
50629 dragData.records.push(this.store.getAt(selectedIndices[i]));
50631 if (selNodes.length == 1) {
50632 dragData.ddel = target.cloneNode(true); // the div element
50634 var div = document.createElement('div'); // create the multi element drag "ghost"
50635 div.className = 'multi-proxy';
50636 for (var i = 0, len = selNodes.length; i < len; i++) {
50637 div.appendChild(selNodes[i].cloneNode(true));
50639 dragData.ddel = div;
50641 //console.log(dragData)
50642 //console.log(dragData.ddel.innerHTML)
50645 //console.log('nodragData')
50649 /** Specify to which ddGroup items in this DDView may be dragged. */
50650 setDraggable: function(ddGroup) {
50651 if (ddGroup instanceof Array) {
50652 Roo.each(ddGroup, this.setDraggable, this);
50655 if (this.dragZone) {
50656 this.dragZone.addToGroup(ddGroup);
50658 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50659 containerScroll: true,
50663 // Draggability implies selection. DragZone's mousedown selects the element.
50664 if (!this.multiSelect) { this.singleSelect = true; }
50666 // Wire the DragZone's handlers up to methods in *this*
50667 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50671 /** Specify from which ddGroup this DDView accepts drops. */
50672 setDroppable: function(ddGroup) {
50673 if (ddGroup instanceof Array) {
50674 Roo.each(ddGroup, this.setDroppable, this);
50677 if (this.dropZone) {
50678 this.dropZone.addToGroup(ddGroup);
50680 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50681 containerScroll: true,
50685 // Wire the DropZone's handlers up to methods in *this*
50686 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50687 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50688 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50689 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50690 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50694 /** Decide whether to drop above or below a View node. */
50695 getDropPoint : function(e, n, dd){
50696 if (n == this.el.dom) { return "above"; }
50697 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50698 var c = t + (b - t) / 2;
50699 var y = Roo.lib.Event.getPageY(e);
50707 onNodeEnter : function(n, dd, e, data){
50711 onNodeOver : function(n, dd, e, data){
50712 var pt = this.getDropPoint(e, n, dd);
50713 // set the insert point style on the target node
50714 var dragElClass = this.dropNotAllowed;
50717 if (pt == "above"){
50718 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50719 targetElClass = "x-view-drag-insert-above";
50721 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50722 targetElClass = "x-view-drag-insert-below";
50724 if (this.lastInsertClass != targetElClass){
50725 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50726 this.lastInsertClass = targetElClass;
50729 return dragElClass;
50732 onNodeOut : function(n, dd, e, data){
50733 this.removeDropIndicators(n);
50736 onNodeDrop : function(n, dd, e, data){
50737 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50740 var pt = this.getDropPoint(e, n, dd);
50741 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50742 if (pt == "below") { insertAt++; }
50743 for (var i = 0; i < data.records.length; i++) {
50744 var r = data.records[i];
50745 var dup = this.store.getById(r.id);
50746 if (dup && (dd != this.dragZone)) {
50747 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50750 this.store.insert(insertAt++, r.copy());
50752 data.source.isDirtyFlag = true;
50754 this.store.insert(insertAt++, r);
50756 this.isDirtyFlag = true;
50759 this.dragZone.cachedTarget = null;
50763 removeDropIndicators : function(n){
50765 Roo.fly(n).removeClass([
50766 "x-view-drag-insert-above",
50767 "x-view-drag-insert-below"]);
50768 this.lastInsertClass = "_noclass";
50773 * Utility method. Add a delete option to the DDView's context menu.
50774 * @param {String} imageUrl The URL of the "delete" icon image.
50776 setDeletable: function(imageUrl) {
50777 if (!this.singleSelect && !this.multiSelect) {
50778 this.singleSelect = true;
50780 var c = this.getContextMenu();
50781 this.contextMenu.on("itemclick", function(item) {
50784 this.remove(this.getSelectedIndexes());
50788 this.contextMenu.add({
50795 /** Return the context menu for this DDView. */
50796 getContextMenu: function() {
50797 if (!this.contextMenu) {
50798 // Create the View's context menu
50799 this.contextMenu = new Roo.menu.Menu({
50800 id: this.id + "-contextmenu"
50802 this.el.on("contextmenu", this.showContextMenu, this);
50804 return this.contextMenu;
50807 disableContextMenu: function() {
50808 if (this.contextMenu) {
50809 this.el.un("contextmenu", this.showContextMenu, this);
50813 showContextMenu: function(e, item) {
50814 item = this.findItemFromChild(e.getTarget());
50817 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50818 this.contextMenu.showAt(e.getXY());
50823 * Remove {@link Roo.data.Record}s at the specified indices.
50824 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50826 remove: function(selectedIndices) {
50827 selectedIndices = [].concat(selectedIndices);
50828 for (var i = 0; i < selectedIndices.length; i++) {
50829 var rec = this.store.getAt(selectedIndices[i]);
50830 this.store.remove(rec);
50835 * Double click fires the event, but also, if this is draggable, and there is only one other
50836 * related DropZone, it transfers the selected node.
50838 onDblClick : function(e){
50839 var item = this.findItemFromChild(e.getTarget());
50841 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50844 if (this.dragGroup) {
50845 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50846 while (targets.indexOf(this.dropZone) > -1) {
50847 targets.remove(this.dropZone);
50849 if (targets.length == 1) {
50850 this.dragZone.cachedTarget = null;
50851 var el = Roo.get(targets[0].getEl());
50852 var box = el.getBox(true);
50853 targets[0].onNodeDrop(el.dom, {
50855 xy: [box.x, box.y + box.height - 1]
50856 }, null, this.getDragData(e));
50862 handleSelection: function(e) {
50863 this.dragZone.cachedTarget = null;
50864 var item = this.findItemFromChild(e.getTarget());
50866 this.clearSelections(true);
50869 if (item && (this.multiSelect || this.singleSelect)){
50870 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50871 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50872 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50873 this.unselect(item);
50875 this.select(item, this.multiSelect && e.ctrlKey);
50876 this.lastSelection = item;
50881 onItemClick : function(item, index, e){
50882 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50888 unselect : function(nodeInfo, suppressEvent){
50889 var node = this.getNode(nodeInfo);
50890 if(node && this.isSelected(node)){
50891 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50892 Roo.fly(node).removeClass(this.selectedClass);
50893 this.selections.remove(node);
50894 if(!suppressEvent){
50895 this.fireEvent("selectionchange", this, this.selections);
50903 * Ext JS Library 1.1.1
50904 * Copyright(c) 2006-2007, Ext JS, LLC.
50906 * Originally Released Under LGPL - original licence link has changed is not relivant.
50909 * <script type="text/javascript">
50913 * @class Roo.LayoutManager
50914 * @extends Roo.util.Observable
50915 * Base class for layout managers.
50917 Roo.LayoutManager = function(container, config){
50918 Roo.LayoutManager.superclass.constructor.call(this);
50919 this.el = Roo.get(container);
50920 // ie scrollbar fix
50921 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50922 document.body.scroll = "no";
50923 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50924 this.el.position('relative');
50926 this.id = this.el.id;
50927 this.el.addClass("x-layout-container");
50928 /** false to disable window resize monitoring @type Boolean */
50929 this.monitorWindowResize = true;
50934 * Fires when a layout is performed.
50935 * @param {Roo.LayoutManager} this
50939 * @event regionresized
50940 * Fires when the user resizes a region.
50941 * @param {Roo.LayoutRegion} region The resized region
50942 * @param {Number} newSize The new size (width for east/west, height for north/south)
50944 "regionresized" : true,
50946 * @event regioncollapsed
50947 * Fires when a region is collapsed.
50948 * @param {Roo.LayoutRegion} region The collapsed region
50950 "regioncollapsed" : true,
50952 * @event regionexpanded
50953 * Fires when a region is expanded.
50954 * @param {Roo.LayoutRegion} region The expanded region
50956 "regionexpanded" : true
50958 this.updating = false;
50959 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50962 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50964 * Returns true if this layout is currently being updated
50965 * @return {Boolean}
50967 isUpdating : function(){
50968 return this.updating;
50972 * Suspend the LayoutManager from doing auto-layouts while
50973 * making multiple add or remove calls
50975 beginUpdate : function(){
50976 this.updating = true;
50980 * Restore auto-layouts and optionally disable the manager from performing a layout
50981 * @param {Boolean} noLayout true to disable a layout update
50983 endUpdate : function(noLayout){
50984 this.updating = false;
50990 layout: function(){
50994 onRegionResized : function(region, newSize){
50995 this.fireEvent("regionresized", region, newSize);
50999 onRegionCollapsed : function(region){
51000 this.fireEvent("regioncollapsed", region);
51003 onRegionExpanded : function(region){
51004 this.fireEvent("regionexpanded", region);
51008 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51009 * performs box-model adjustments.
51010 * @return {Object} The size as an object {width: (the width), height: (the height)}
51012 getViewSize : function(){
51014 if(this.el.dom != document.body){
51015 size = this.el.getSize();
51017 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
51019 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
51020 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
51025 * Returns the Element this layout is bound to.
51026 * @return {Roo.Element}
51028 getEl : function(){
51033 * Returns the specified region.
51034 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
51035 * @return {Roo.LayoutRegion}
51037 getRegion : function(target){
51038 return this.regions[target.toLowerCase()];
51041 onWindowResize : function(){
51042 if(this.monitorWindowResize){
51048 * Ext JS Library 1.1.1
51049 * Copyright(c) 2006-2007, Ext JS, LLC.
51051 * Originally Released Under LGPL - original licence link has changed is not relivant.
51054 * <script type="text/javascript">
51057 * @class Roo.BorderLayout
51058 * @extends Roo.LayoutManager
51059 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
51060 * please see: <br><br>
51061 * <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>
51062 * <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>
51065 var layout = new Roo.BorderLayout(document.body, {
51099 preferredTabWidth: 150
51104 var CP = Roo.ContentPanel;
51106 layout.beginUpdate();
51107 layout.add("north", new CP("north", "North"));
51108 layout.add("south", new CP("south", {title: "South", closable: true}));
51109 layout.add("west", new CP("west", {title: "West"}));
51110 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
51111 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
51112 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
51113 layout.getRegion("center").showPanel("center1");
51114 layout.endUpdate();
51117 <b>The container the layout is rendered into can be either the body element or any other element.
51118 If it is not the body element, the container needs to either be an absolute positioned element,
51119 or you will need to add "position:relative" to the css of the container. You will also need to specify
51120 the container size if it is not the body element.</b>
51123 * Create a new BorderLayout
51124 * @param {String/HTMLElement/Element} container The container this layout is bound to
51125 * @param {Object} config Configuration options
51127 Roo.BorderLayout = function(container, config){
51128 config = config || {};
51129 Roo.BorderLayout.superclass.constructor.call(this, container, config);
51130 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
51131 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
51132 var target = this.factory.validRegions[i];
51133 if(config[target]){
51134 this.addRegion(target, config[target]);
51139 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51141 * Creates and adds a new region if it doesn't already exist.
51142 * @param {String} target The target region key (north, south, east, west or center).
51143 * @param {Object} config The regions config object
51144 * @return {BorderLayoutRegion} The new region
51146 addRegion : function(target, config){
51147 if(!this.regions[target]){
51148 var r = this.factory.create(target, this, config);
51149 this.bindRegion(target, r);
51151 return this.regions[target];
51155 bindRegion : function(name, r){
51156 this.regions[name] = r;
51157 r.on("visibilitychange", this.layout, this);
51158 r.on("paneladded", this.layout, this);
51159 r.on("panelremoved", this.layout, this);
51160 r.on("invalidated", this.layout, this);
51161 r.on("resized", this.onRegionResized, this);
51162 r.on("collapsed", this.onRegionCollapsed, this);
51163 r.on("expanded", this.onRegionExpanded, this);
51167 * Performs a layout update.
51169 layout : function(){
51170 if(this.updating) {
51173 var size = this.getViewSize();
51174 var w = size.width;
51175 var h = size.height;
51180 //var x = 0, y = 0;
51182 var rs = this.regions;
51183 var north = rs["north"];
51184 var south = rs["south"];
51185 var west = rs["west"];
51186 var east = rs["east"];
51187 var center = rs["center"];
51188 //if(this.hideOnLayout){ // not supported anymore
51189 //c.el.setStyle("display", "none");
51191 if(north && north.isVisible()){
51192 var b = north.getBox();
51193 var m = north.getMargins();
51194 b.width = w - (m.left+m.right);
51197 centerY = b.height + b.y + m.bottom;
51198 centerH -= centerY;
51199 north.updateBox(this.safeBox(b));
51201 if(south && south.isVisible()){
51202 var b = south.getBox();
51203 var m = south.getMargins();
51204 b.width = w - (m.left+m.right);
51206 var totalHeight = (b.height + m.top + m.bottom);
51207 b.y = h - totalHeight + m.top;
51208 centerH -= totalHeight;
51209 south.updateBox(this.safeBox(b));
51211 if(west && west.isVisible()){
51212 var b = west.getBox();
51213 var m = west.getMargins();
51214 b.height = centerH - (m.top+m.bottom);
51216 b.y = centerY + m.top;
51217 var totalWidth = (b.width + m.left + m.right);
51218 centerX += totalWidth;
51219 centerW -= totalWidth;
51220 west.updateBox(this.safeBox(b));
51222 if(east && east.isVisible()){
51223 var b = east.getBox();
51224 var m = east.getMargins();
51225 b.height = centerH - (m.top+m.bottom);
51226 var totalWidth = (b.width + m.left + m.right);
51227 b.x = w - totalWidth + m.left;
51228 b.y = centerY + m.top;
51229 centerW -= totalWidth;
51230 east.updateBox(this.safeBox(b));
51233 var m = center.getMargins();
51235 x: centerX + m.left,
51236 y: centerY + m.top,
51237 width: centerW - (m.left+m.right),
51238 height: centerH - (m.top+m.bottom)
51240 //if(this.hideOnLayout){
51241 //center.el.setStyle("display", "block");
51243 center.updateBox(this.safeBox(centerBox));
51246 this.fireEvent("layout", this);
51250 safeBox : function(box){
51251 box.width = Math.max(0, box.width);
51252 box.height = Math.max(0, box.height);
51257 * Adds a ContentPanel (or subclass) to this layout.
51258 * @param {String} target The target region key (north, south, east, west or center).
51259 * @param {Roo.ContentPanel} panel The panel to add
51260 * @return {Roo.ContentPanel} The added panel
51262 add : function(target, panel){
51264 target = target.toLowerCase();
51265 return this.regions[target].add(panel);
51269 * Remove a ContentPanel (or subclass) to this layout.
51270 * @param {String} target The target region key (north, south, east, west or center).
51271 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51272 * @return {Roo.ContentPanel} The removed panel
51274 remove : function(target, panel){
51275 target = target.toLowerCase();
51276 return this.regions[target].remove(panel);
51280 * Searches all regions for a panel with the specified id
51281 * @param {String} panelId
51282 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51284 findPanel : function(panelId){
51285 var rs = this.regions;
51286 for(var target in rs){
51287 if(typeof rs[target] != "function"){
51288 var p = rs[target].getPanel(panelId);
51298 * Searches all regions for a panel with the specified id and activates (shows) it.
51299 * @param {String/ContentPanel} panelId The panels id or the panel itself
51300 * @return {Roo.ContentPanel} The shown panel or null
51302 showPanel : function(panelId) {
51303 var rs = this.regions;
51304 for(var target in rs){
51305 var r = rs[target];
51306 if(typeof r != "function"){
51307 if(r.hasPanel(panelId)){
51308 return r.showPanel(panelId);
51316 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51317 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51319 restoreState : function(provider){
51321 provider = Roo.state.Manager;
51323 var sm = new Roo.LayoutStateManager();
51324 sm.init(this, provider);
51328 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51329 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51330 * a valid ContentPanel config object. Example:
51332 // Create the main layout
51333 var layout = new Roo.BorderLayout('main-ct', {
51344 // Create and add multiple ContentPanels at once via configs
51347 id: 'source-files',
51349 title:'Ext Source Files',
51362 * @param {Object} regions An object containing ContentPanel configs by region name
51364 batchAdd : function(regions){
51365 this.beginUpdate();
51366 for(var rname in regions){
51367 var lr = this.regions[rname];
51369 this.addTypedPanels(lr, regions[rname]);
51376 addTypedPanels : function(lr, ps){
51377 if(typeof ps == 'string'){
51378 lr.add(new Roo.ContentPanel(ps));
51380 else if(ps instanceof Array){
51381 for(var i =0, len = ps.length; i < len; i++){
51382 this.addTypedPanels(lr, ps[i]);
51385 else if(!ps.events){ // raw config?
51387 delete ps.el; // prevent conflict
51388 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51390 else { // panel object assumed!
51395 * Adds a xtype elements to the layout.
51399 xtype : 'ContentPanel',
51406 xtype : 'NestedLayoutPanel',
51412 items : [ ... list of content panels or nested layout panels.. ]
51416 * @param {Object} cfg Xtype definition of item to add.
51418 addxtype : function(cfg)
51420 // basically accepts a pannel...
51421 // can accept a layout region..!?!?
51422 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51424 if (!cfg.xtype.match(/Panel$/)) {
51429 if (typeof(cfg.region) == 'undefined') {
51430 Roo.log("Failed to add Panel, region was not set");
51434 var region = cfg.region;
51440 xitems = cfg.items;
51447 case 'ContentPanel': // ContentPanel (el, cfg)
51448 case 'ScrollPanel': // ContentPanel (el, cfg)
51450 if(cfg.autoCreate) {
51451 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51453 var el = this.el.createChild();
51454 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51457 this.add(region, ret);
51461 case 'TreePanel': // our new panel!
51462 cfg.el = this.el.createChild();
51463 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51464 this.add(region, ret);
51467 case 'NestedLayoutPanel':
51468 // create a new Layout (which is a Border Layout...
51469 var el = this.el.createChild();
51470 var clayout = cfg.layout;
51472 clayout.items = clayout.items || [];
51473 // replace this exitems with the clayout ones..
51474 xitems = clayout.items;
51477 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51478 cfg.background = false;
51480 var layout = new Roo.BorderLayout(el, clayout);
51482 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51483 //console.log('adding nested layout panel ' + cfg.toSource());
51484 this.add(region, ret);
51485 nb = {}; /// find first...
51490 // needs grid and region
51492 //var el = this.getRegion(region).el.createChild();
51493 var el = this.el.createChild();
51494 // create the grid first...
51496 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51498 if (region == 'center' && this.active ) {
51499 cfg.background = false;
51501 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51503 this.add(region, ret);
51504 if (cfg.background) {
51505 ret.on('activate', function(gp) {
51506 if (!gp.grid.rendered) {
51521 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51523 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51524 this.add(region, ret);
51527 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51531 // GridPanel (grid, cfg)
51534 this.beginUpdate();
51538 Roo.each(xitems, function(i) {
51539 region = nb && i.region ? i.region : false;
51541 var add = ret.addxtype(i);
51544 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51545 if (!i.background) {
51546 abn[region] = nb[region] ;
51553 // make the last non-background panel active..
51554 //if (nb) { Roo.log(abn); }
51557 for(var r in abn) {
51558 region = this.getRegion(r);
51560 // tried using nb[r], but it does not work..
51562 region.showPanel(abn[r]);
51573 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51574 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51575 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51576 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51579 var CP = Roo.ContentPanel;
51581 var layout = Roo.BorderLayout.create({
51585 panels: [new CP("north", "North")]
51594 panels: [new CP("west", {title: "West"})]
51603 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51612 panels: [new CP("south", {title: "South", closable: true})]
51619 preferredTabWidth: 150,
51621 new CP("center1", {title: "Close Me", closable: true}),
51622 new CP("center2", {title: "Center Panel", closable: false})
51627 layout.getRegion("center").showPanel("center1");
51632 Roo.BorderLayout.create = function(config, targetEl){
51633 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51634 layout.beginUpdate();
51635 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51636 for(var j = 0, jlen = regions.length; j < jlen; j++){
51637 var lr = regions[j];
51638 if(layout.regions[lr] && config[lr].panels){
51639 var r = layout.regions[lr];
51640 var ps = config[lr].panels;
51641 layout.addTypedPanels(r, ps);
51644 layout.endUpdate();
51649 Roo.BorderLayout.RegionFactory = {
51651 validRegions : ["north","south","east","west","center"],
51654 create : function(target, mgr, config){
51655 target = target.toLowerCase();
51656 if(config.lightweight || config.basic){
51657 return new Roo.BasicLayoutRegion(mgr, config, target);
51661 return new Roo.NorthLayoutRegion(mgr, config);
51663 return new Roo.SouthLayoutRegion(mgr, config);
51665 return new Roo.EastLayoutRegion(mgr, config);
51667 return new Roo.WestLayoutRegion(mgr, config);
51669 return new Roo.CenterLayoutRegion(mgr, config);
51671 throw 'Layout region "'+target+'" not supported.';
51675 * Ext JS Library 1.1.1
51676 * Copyright(c) 2006-2007, Ext JS, LLC.
51678 * Originally Released Under LGPL - original licence link has changed is not relivant.
51681 * <script type="text/javascript">
51685 * @class Roo.BasicLayoutRegion
51686 * @extends Roo.util.Observable
51687 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51688 * and does not have a titlebar, tabs or any other features. All it does is size and position
51689 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51691 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51693 this.position = pos;
51696 * @scope Roo.BasicLayoutRegion
51700 * @event beforeremove
51701 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51702 * @param {Roo.LayoutRegion} this
51703 * @param {Roo.ContentPanel} panel The panel
51704 * @param {Object} e The cancel event object
51706 "beforeremove" : true,
51708 * @event invalidated
51709 * Fires when the layout for this region is changed.
51710 * @param {Roo.LayoutRegion} this
51712 "invalidated" : true,
51714 * @event visibilitychange
51715 * Fires when this region is shown or hidden
51716 * @param {Roo.LayoutRegion} this
51717 * @param {Boolean} visibility true or false
51719 "visibilitychange" : true,
51721 * @event paneladded
51722 * Fires when a panel is added.
51723 * @param {Roo.LayoutRegion} this
51724 * @param {Roo.ContentPanel} panel The panel
51726 "paneladded" : true,
51728 * @event panelremoved
51729 * Fires when a panel is removed.
51730 * @param {Roo.LayoutRegion} this
51731 * @param {Roo.ContentPanel} panel The panel
51733 "panelremoved" : true,
51735 * @event beforecollapse
51736 * Fires when this region before collapse.
51737 * @param {Roo.LayoutRegion} this
51739 "beforecollapse" : true,
51742 * Fires when this region is collapsed.
51743 * @param {Roo.LayoutRegion} this
51745 "collapsed" : true,
51748 * Fires when this region is expanded.
51749 * @param {Roo.LayoutRegion} this
51754 * Fires when this region is slid into view.
51755 * @param {Roo.LayoutRegion} this
51757 "slideshow" : true,
51760 * Fires when this region slides out of view.
51761 * @param {Roo.LayoutRegion} this
51763 "slidehide" : true,
51765 * @event panelactivated
51766 * Fires when a panel is activated.
51767 * @param {Roo.LayoutRegion} this
51768 * @param {Roo.ContentPanel} panel The activated panel
51770 "panelactivated" : true,
51773 * Fires when the user resizes this region.
51774 * @param {Roo.LayoutRegion} this
51775 * @param {Number} newSize The new size (width for east/west, height for north/south)
51779 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51780 this.panels = new Roo.util.MixedCollection();
51781 this.panels.getKey = this.getPanelId.createDelegate(this);
51783 this.activePanel = null;
51784 // ensure listeners are added...
51786 if (config.listeners || config.events) {
51787 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51788 listeners : config.listeners || {},
51789 events : config.events || {}
51793 if(skipConfig !== true){
51794 this.applyConfig(config);
51798 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51799 getPanelId : function(p){
51803 applyConfig : function(config){
51804 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51805 this.config = config;
51810 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51811 * the width, for horizontal (north, south) the height.
51812 * @param {Number} newSize The new width or height
51814 resizeTo : function(newSize){
51815 var el = this.el ? this.el :
51816 (this.activePanel ? this.activePanel.getEl() : null);
51818 switch(this.position){
51821 el.setWidth(newSize);
51822 this.fireEvent("resized", this, newSize);
51826 el.setHeight(newSize);
51827 this.fireEvent("resized", this, newSize);
51833 getBox : function(){
51834 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51837 getMargins : function(){
51838 return this.margins;
51841 updateBox : function(box){
51843 var el = this.activePanel.getEl();
51844 el.dom.style.left = box.x + "px";
51845 el.dom.style.top = box.y + "px";
51846 this.activePanel.setSize(box.width, box.height);
51850 * Returns the container element for this region.
51851 * @return {Roo.Element}
51853 getEl : function(){
51854 return this.activePanel;
51858 * Returns true if this region is currently visible.
51859 * @return {Boolean}
51861 isVisible : function(){
51862 return this.activePanel ? true : false;
51865 setActivePanel : function(panel){
51866 panel = this.getPanel(panel);
51867 if(this.activePanel && this.activePanel != panel){
51868 this.activePanel.setActiveState(false);
51869 this.activePanel.getEl().setLeftTop(-10000,-10000);
51871 this.activePanel = panel;
51872 panel.setActiveState(true);
51874 panel.setSize(this.box.width, this.box.height);
51876 this.fireEvent("panelactivated", this, panel);
51877 this.fireEvent("invalidated");
51881 * Show the specified panel.
51882 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51883 * @return {Roo.ContentPanel} The shown panel or null
51885 showPanel : function(panel){
51886 if(panel = this.getPanel(panel)){
51887 this.setActivePanel(panel);
51893 * Get the active panel for this region.
51894 * @return {Roo.ContentPanel} The active panel or null
51896 getActivePanel : function(){
51897 return this.activePanel;
51901 * Add the passed ContentPanel(s)
51902 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51903 * @return {Roo.ContentPanel} The panel added (if only one was added)
51905 add : function(panel){
51906 if(arguments.length > 1){
51907 for(var i = 0, len = arguments.length; i < len; i++) {
51908 this.add(arguments[i]);
51912 if(this.hasPanel(panel)){
51913 this.showPanel(panel);
51916 var el = panel.getEl();
51917 if(el.dom.parentNode != this.mgr.el.dom){
51918 this.mgr.el.dom.appendChild(el.dom);
51920 if(panel.setRegion){
51921 panel.setRegion(this);
51923 this.panels.add(panel);
51924 el.setStyle("position", "absolute");
51925 if(!panel.background){
51926 this.setActivePanel(panel);
51927 if(this.config.initialSize && this.panels.getCount()==1){
51928 this.resizeTo(this.config.initialSize);
51931 this.fireEvent("paneladded", this, panel);
51936 * Returns true if the panel is in this region.
51937 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51938 * @return {Boolean}
51940 hasPanel : function(panel){
51941 if(typeof panel == "object"){ // must be panel obj
51942 panel = panel.getId();
51944 return this.getPanel(panel) ? true : false;
51948 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51949 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51950 * @param {Boolean} preservePanel Overrides the config preservePanel option
51951 * @return {Roo.ContentPanel} The panel that was removed
51953 remove : function(panel, preservePanel){
51954 panel = this.getPanel(panel);
51959 this.fireEvent("beforeremove", this, panel, e);
51960 if(e.cancel === true){
51963 var panelId = panel.getId();
51964 this.panels.removeKey(panelId);
51969 * Returns the panel specified or null if it's not in this region.
51970 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51971 * @return {Roo.ContentPanel}
51973 getPanel : function(id){
51974 if(typeof id == "object"){ // must be panel obj
51977 return this.panels.get(id);
51981 * Returns this regions position (north/south/east/west/center).
51984 getPosition: function(){
51985 return this.position;
51989 * Ext JS Library 1.1.1
51990 * Copyright(c) 2006-2007, Ext JS, LLC.
51992 * Originally Released Under LGPL - original licence link has changed is not relivant.
51995 * <script type="text/javascript">
51999 * @class Roo.LayoutRegion
52000 * @extends Roo.BasicLayoutRegion
52001 * This class represents a region in a layout manager.
52002 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52003 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52004 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52005 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52006 * @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})
52007 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52008 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52009 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52010 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52011 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52012 * @cfg {String} title The title for the region (overrides panel titles)
52013 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52014 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52015 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52016 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
52017 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
52018 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
52019 * the space available, similar to FireFox 1.5 tabs (defaults to false)
52020 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
52021 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
52022 * @cfg {Boolean} showPin True to show a pin button
52023 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
52024 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
52025 * @cfg {Boolean} disableTabTips True to disable tab tooltips
52026 * @cfg {Number} width For East/West panels
52027 * @cfg {Number} height For North/South panels
52028 * @cfg {Boolean} split To show the splitter
52029 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
52031 Roo.LayoutRegion = function(mgr, config, pos){
52032 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
52033 var dh = Roo.DomHelper;
52034 /** This region's container element
52035 * @type Roo.Element */
52036 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
52037 /** This region's title element
52038 * @type Roo.Element */
52040 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
52041 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
52042 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
52044 this.titleEl.enableDisplayMode();
52045 /** This region's title text element
52046 * @type HTMLElement */
52047 this.titleTextEl = this.titleEl.dom.firstChild;
52048 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
52049 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
52050 this.closeBtn.enableDisplayMode();
52051 this.closeBtn.on("click", this.closeClicked, this);
52052 this.closeBtn.hide();
52054 this.createBody(config);
52055 this.visible = true;
52056 this.collapsed = false;
52058 if(config.hideWhenEmpty){
52060 this.on("paneladded", this.validateVisibility, this);
52061 this.on("panelremoved", this.validateVisibility, this);
52063 this.applyConfig(config);
52066 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
52068 createBody : function(){
52069 /** This region's body element
52070 * @type Roo.Element */
52071 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
52074 applyConfig : function(c){
52075 if(c.collapsible && this.position != "center" && !this.collapsedEl){
52076 var dh = Roo.DomHelper;
52077 if(c.titlebar !== false){
52078 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
52079 this.collapseBtn.on("click", this.collapse, this);
52080 this.collapseBtn.enableDisplayMode();
52082 if(c.showPin === true || this.showPin){
52083 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
52084 this.stickBtn.enableDisplayMode();
52085 this.stickBtn.on("click", this.expand, this);
52086 this.stickBtn.hide();
52089 /** This region's collapsed element
52090 * @type Roo.Element */
52091 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
52092 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
52094 if(c.floatable !== false){
52095 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
52096 this.collapsedEl.on("click", this.collapseClick, this);
52099 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
52100 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
52101 id: "message", unselectable: "on", style:{"float":"left"}});
52102 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
52104 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
52105 this.expandBtn.on("click", this.expand, this);
52107 if(this.collapseBtn){
52108 this.collapseBtn.setVisible(c.collapsible == true);
52110 this.cmargins = c.cmargins || this.cmargins ||
52111 (this.position == "west" || this.position == "east" ?
52112 {top: 0, left: 2, right:2, bottom: 0} :
52113 {top: 2, left: 0, right:0, bottom: 2});
52114 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52115 this.bottomTabs = c.tabPosition != "top";
52116 this.autoScroll = c.autoScroll || false;
52117 if(this.autoScroll){
52118 this.bodyEl.setStyle("overflow", "auto");
52120 this.bodyEl.setStyle("overflow", "hidden");
52122 //if(c.titlebar !== false){
52123 if((!c.titlebar && !c.title) || c.titlebar === false){
52124 this.titleEl.hide();
52126 this.titleEl.show();
52128 this.titleTextEl.innerHTML = c.title;
52132 this.duration = c.duration || .30;
52133 this.slideDuration = c.slideDuration || .45;
52136 this.collapse(true);
52143 * Returns true if this region is currently visible.
52144 * @return {Boolean}
52146 isVisible : function(){
52147 return this.visible;
52151 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52152 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52154 setCollapsedTitle : function(title){
52155 title = title || " ";
52156 if(this.collapsedTitleTextEl){
52157 this.collapsedTitleTextEl.innerHTML = title;
52161 getBox : function(){
52163 if(!this.collapsed){
52164 b = this.el.getBox(false, true);
52166 b = this.collapsedEl.getBox(false, true);
52171 getMargins : function(){
52172 return this.collapsed ? this.cmargins : this.margins;
52175 highlight : function(){
52176 this.el.addClass("x-layout-panel-dragover");
52179 unhighlight : function(){
52180 this.el.removeClass("x-layout-panel-dragover");
52183 updateBox : function(box){
52185 if(!this.collapsed){
52186 this.el.dom.style.left = box.x + "px";
52187 this.el.dom.style.top = box.y + "px";
52188 this.updateBody(box.width, box.height);
52190 this.collapsedEl.dom.style.left = box.x + "px";
52191 this.collapsedEl.dom.style.top = box.y + "px";
52192 this.collapsedEl.setSize(box.width, box.height);
52195 this.tabs.autoSizeTabs();
52199 updateBody : function(w, h){
52201 this.el.setWidth(w);
52202 w -= this.el.getBorderWidth("rl");
52203 if(this.config.adjustments){
52204 w += this.config.adjustments[0];
52208 this.el.setHeight(h);
52209 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52210 h -= this.el.getBorderWidth("tb");
52211 if(this.config.adjustments){
52212 h += this.config.adjustments[1];
52214 this.bodyEl.setHeight(h);
52216 h = this.tabs.syncHeight(h);
52219 if(this.panelSize){
52220 w = w !== null ? w : this.panelSize.width;
52221 h = h !== null ? h : this.panelSize.height;
52223 if(this.activePanel){
52224 var el = this.activePanel.getEl();
52225 w = w !== null ? w : el.getWidth();
52226 h = h !== null ? h : el.getHeight();
52227 this.panelSize = {width: w, height: h};
52228 this.activePanel.setSize(w, h);
52230 if(Roo.isIE && this.tabs){
52231 this.tabs.el.repaint();
52236 * Returns the container element for this region.
52237 * @return {Roo.Element}
52239 getEl : function(){
52244 * Hides this region.
52247 if(!this.collapsed){
52248 this.el.dom.style.left = "-2000px";
52251 this.collapsedEl.dom.style.left = "-2000px";
52252 this.collapsedEl.hide();
52254 this.visible = false;
52255 this.fireEvent("visibilitychange", this, false);
52259 * Shows this region if it was previously hidden.
52262 if(!this.collapsed){
52265 this.collapsedEl.show();
52267 this.visible = true;
52268 this.fireEvent("visibilitychange", this, true);
52271 closeClicked : function(){
52272 if(this.activePanel){
52273 this.remove(this.activePanel);
52277 collapseClick : function(e){
52279 e.stopPropagation();
52282 e.stopPropagation();
52288 * Collapses this region.
52289 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52291 collapse : function(skipAnim, skipCheck = false){
52292 if(this.collapsed) {
52296 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52298 this.collapsed = true;
52300 this.split.el.hide();
52302 if(this.config.animate && skipAnim !== true){
52303 this.fireEvent("invalidated", this);
52304 this.animateCollapse();
52306 this.el.setLocation(-20000,-20000);
52308 this.collapsedEl.show();
52309 this.fireEvent("collapsed", this);
52310 this.fireEvent("invalidated", this);
52316 animateCollapse : function(){
52321 * Expands this region if it was previously collapsed.
52322 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52323 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52325 expand : function(e, skipAnim){
52327 e.stopPropagation();
52329 if(!this.collapsed || this.el.hasActiveFx()) {
52333 this.afterSlideIn();
52336 this.collapsed = false;
52337 if(this.config.animate && skipAnim !== true){
52338 this.animateExpand();
52342 this.split.el.show();
52344 this.collapsedEl.setLocation(-2000,-2000);
52345 this.collapsedEl.hide();
52346 this.fireEvent("invalidated", this);
52347 this.fireEvent("expanded", this);
52351 animateExpand : function(){
52355 initTabs : function()
52357 this.bodyEl.setStyle("overflow", "hidden");
52358 var ts = new Roo.TabPanel(
52361 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52362 disableTooltips: this.config.disableTabTips,
52363 toolbar : this.config.toolbar
52366 if(this.config.hideTabs){
52367 ts.stripWrap.setDisplayed(false);
52370 ts.resizeTabs = this.config.resizeTabs === true;
52371 ts.minTabWidth = this.config.minTabWidth || 40;
52372 ts.maxTabWidth = this.config.maxTabWidth || 250;
52373 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52374 ts.monitorResize = false;
52375 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52376 ts.bodyEl.addClass('x-layout-tabs-body');
52377 this.panels.each(this.initPanelAsTab, this);
52380 initPanelAsTab : function(panel){
52381 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52382 this.config.closeOnTab && panel.isClosable());
52383 if(panel.tabTip !== undefined){
52384 ti.setTooltip(panel.tabTip);
52386 ti.on("activate", function(){
52387 this.setActivePanel(panel);
52389 if(this.config.closeOnTab){
52390 ti.on("beforeclose", function(t, e){
52392 this.remove(panel);
52398 updatePanelTitle : function(panel, title){
52399 if(this.activePanel == panel){
52400 this.updateTitle(title);
52403 var ti = this.tabs.getTab(panel.getEl().id);
52405 if(panel.tabTip !== undefined){
52406 ti.setTooltip(panel.tabTip);
52411 updateTitle : function(title){
52412 if(this.titleTextEl && !this.config.title){
52413 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52417 setActivePanel : function(panel){
52418 panel = this.getPanel(panel);
52419 if(this.activePanel && this.activePanel != panel){
52420 this.activePanel.setActiveState(false);
52422 this.activePanel = panel;
52423 panel.setActiveState(true);
52424 if(this.panelSize){
52425 panel.setSize(this.panelSize.width, this.panelSize.height);
52428 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52430 this.updateTitle(panel.getTitle());
52432 this.fireEvent("invalidated", this);
52434 this.fireEvent("panelactivated", this, panel);
52438 * Shows the specified panel.
52439 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52440 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52442 showPanel : function(panel)
52444 panel = this.getPanel(panel);
52447 var tab = this.tabs.getTab(panel.getEl().id);
52448 if(tab.isHidden()){
52449 this.tabs.unhideTab(tab.id);
52453 this.setActivePanel(panel);
52460 * Get the active panel for this region.
52461 * @return {Roo.ContentPanel} The active panel or null
52463 getActivePanel : function(){
52464 return this.activePanel;
52467 validateVisibility : function(){
52468 if(this.panels.getCount() < 1){
52469 this.updateTitle(" ");
52470 this.closeBtn.hide();
52473 if(!this.isVisible()){
52480 * Adds the passed ContentPanel(s) to this region.
52481 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52482 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52484 add : function(panel){
52485 if(arguments.length > 1){
52486 for(var i = 0, len = arguments.length; i < len; i++) {
52487 this.add(arguments[i]);
52491 if(this.hasPanel(panel)){
52492 this.showPanel(panel);
52495 panel.setRegion(this);
52496 this.panels.add(panel);
52497 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52498 this.bodyEl.dom.appendChild(panel.getEl().dom);
52499 if(panel.background !== true){
52500 this.setActivePanel(panel);
52502 this.fireEvent("paneladded", this, panel);
52508 this.initPanelAsTab(panel);
52510 if(panel.background !== true){
52511 this.tabs.activate(panel.getEl().id);
52513 this.fireEvent("paneladded", this, panel);
52518 * Hides the tab for the specified panel.
52519 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52521 hidePanel : function(panel){
52522 if(this.tabs && (panel = this.getPanel(panel))){
52523 this.tabs.hideTab(panel.getEl().id);
52528 * Unhides the tab for a previously hidden panel.
52529 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52531 unhidePanel : function(panel){
52532 if(this.tabs && (panel = this.getPanel(panel))){
52533 this.tabs.unhideTab(panel.getEl().id);
52537 clearPanels : function(){
52538 while(this.panels.getCount() > 0){
52539 this.remove(this.panels.first());
52544 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52545 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52546 * @param {Boolean} preservePanel Overrides the config preservePanel option
52547 * @return {Roo.ContentPanel} The panel that was removed
52549 remove : function(panel, preservePanel){
52550 panel = this.getPanel(panel);
52555 this.fireEvent("beforeremove", this, panel, e);
52556 if(e.cancel === true){
52559 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52560 var panelId = panel.getId();
52561 this.panels.removeKey(panelId);
52563 document.body.appendChild(panel.getEl().dom);
52566 this.tabs.removeTab(panel.getEl().id);
52567 }else if (!preservePanel){
52568 this.bodyEl.dom.removeChild(panel.getEl().dom);
52570 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52571 var p = this.panels.first();
52572 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52573 tempEl.appendChild(p.getEl().dom);
52574 this.bodyEl.update("");
52575 this.bodyEl.dom.appendChild(p.getEl().dom);
52577 this.updateTitle(p.getTitle());
52579 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52580 this.setActivePanel(p);
52582 panel.setRegion(null);
52583 if(this.activePanel == panel){
52584 this.activePanel = null;
52586 if(this.config.autoDestroy !== false && preservePanel !== true){
52587 try{panel.destroy();}catch(e){}
52589 this.fireEvent("panelremoved", this, panel);
52594 * Returns the TabPanel component used by this region
52595 * @return {Roo.TabPanel}
52597 getTabs : function(){
52601 createTool : function(parentEl, className){
52602 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52603 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52604 btn.addClassOnOver("x-layout-tools-button-over");
52609 * Ext JS Library 1.1.1
52610 * Copyright(c) 2006-2007, Ext JS, LLC.
52612 * Originally Released Under LGPL - original licence link has changed is not relivant.
52615 * <script type="text/javascript">
52621 * @class Roo.SplitLayoutRegion
52622 * @extends Roo.LayoutRegion
52623 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52625 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52626 this.cursor = cursor;
52627 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52630 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52631 splitTip : "Drag to resize.",
52632 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52633 useSplitTips : false,
52635 applyConfig : function(config){
52636 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52639 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52640 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52641 /** The SplitBar for this region
52642 * @type Roo.SplitBar */
52643 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52644 this.split.on("moved", this.onSplitMove, this);
52645 this.split.useShim = config.useShim === true;
52646 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52647 if(this.useSplitTips){
52648 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52650 if(config.collapsible){
52651 this.split.el.on("dblclick", this.collapse, this);
52654 if(typeof config.minSize != "undefined"){
52655 this.split.minSize = config.minSize;
52657 if(typeof config.maxSize != "undefined"){
52658 this.split.maxSize = config.maxSize;
52660 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52661 this.hideSplitter();
52666 getHMaxSize : function(){
52667 var cmax = this.config.maxSize || 10000;
52668 var center = this.mgr.getRegion("center");
52669 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52672 getVMaxSize : function(){
52673 var cmax = this.config.maxSize || 10000;
52674 var center = this.mgr.getRegion("center");
52675 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52678 onSplitMove : function(split, newSize){
52679 this.fireEvent("resized", this, newSize);
52683 * Returns the {@link Roo.SplitBar} for this region.
52684 * @return {Roo.SplitBar}
52686 getSplitBar : function(){
52691 this.hideSplitter();
52692 Roo.SplitLayoutRegion.superclass.hide.call(this);
52695 hideSplitter : function(){
52697 this.split.el.setLocation(-2000,-2000);
52698 this.split.el.hide();
52704 this.split.el.show();
52706 Roo.SplitLayoutRegion.superclass.show.call(this);
52709 beforeSlide: function(){
52710 if(Roo.isGecko){// firefox overflow auto bug workaround
52711 this.bodyEl.clip();
52713 this.tabs.bodyEl.clip();
52715 if(this.activePanel){
52716 this.activePanel.getEl().clip();
52718 if(this.activePanel.beforeSlide){
52719 this.activePanel.beforeSlide();
52725 afterSlide : function(){
52726 if(Roo.isGecko){// firefox overflow auto bug workaround
52727 this.bodyEl.unclip();
52729 this.tabs.bodyEl.unclip();
52731 if(this.activePanel){
52732 this.activePanel.getEl().unclip();
52733 if(this.activePanel.afterSlide){
52734 this.activePanel.afterSlide();
52740 initAutoHide : function(){
52741 if(this.autoHide !== false){
52742 if(!this.autoHideHd){
52743 var st = new Roo.util.DelayedTask(this.slideIn, this);
52744 this.autoHideHd = {
52745 "mouseout": function(e){
52746 if(!e.within(this.el, true)){
52750 "mouseover" : function(e){
52756 this.el.on(this.autoHideHd);
52760 clearAutoHide : function(){
52761 if(this.autoHide !== false){
52762 this.el.un("mouseout", this.autoHideHd.mouseout);
52763 this.el.un("mouseover", this.autoHideHd.mouseover);
52767 clearMonitor : function(){
52768 Roo.get(document).un("click", this.slideInIf, this);
52771 // these names are backwards but not changed for compat
52772 slideOut : function(){
52773 if(this.isSlid || this.el.hasActiveFx()){
52776 this.isSlid = true;
52777 if(this.collapseBtn){
52778 this.collapseBtn.hide();
52780 this.closeBtnState = this.closeBtn.getStyle('display');
52781 this.closeBtn.hide();
52783 this.stickBtn.show();
52786 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52787 this.beforeSlide();
52788 this.el.setStyle("z-index", 10001);
52789 this.el.slideIn(this.getSlideAnchor(), {
52790 callback: function(){
52792 this.initAutoHide();
52793 Roo.get(document).on("click", this.slideInIf, this);
52794 this.fireEvent("slideshow", this);
52801 afterSlideIn : function(){
52802 this.clearAutoHide();
52803 this.isSlid = false;
52804 this.clearMonitor();
52805 this.el.setStyle("z-index", "");
52806 if(this.collapseBtn){
52807 this.collapseBtn.show();
52809 this.closeBtn.setStyle('display', this.closeBtnState);
52811 this.stickBtn.hide();
52813 this.fireEvent("slidehide", this);
52816 slideIn : function(cb){
52817 if(!this.isSlid || this.el.hasActiveFx()){
52821 this.isSlid = false;
52822 this.beforeSlide();
52823 this.el.slideOut(this.getSlideAnchor(), {
52824 callback: function(){
52825 this.el.setLeftTop(-10000, -10000);
52827 this.afterSlideIn();
52835 slideInIf : function(e){
52836 if(!e.within(this.el)){
52841 animateCollapse : function(){
52842 this.beforeSlide();
52843 this.el.setStyle("z-index", 20000);
52844 var anchor = this.getSlideAnchor();
52845 this.el.slideOut(anchor, {
52846 callback : function(){
52847 this.el.setStyle("z-index", "");
52848 this.collapsedEl.slideIn(anchor, {duration:.3});
52850 this.el.setLocation(-10000,-10000);
52852 this.fireEvent("collapsed", this);
52859 animateExpand : function(){
52860 this.beforeSlide();
52861 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52862 this.el.setStyle("z-index", 20000);
52863 this.collapsedEl.hide({
52866 this.el.slideIn(this.getSlideAnchor(), {
52867 callback : function(){
52868 this.el.setStyle("z-index", "");
52871 this.split.el.show();
52873 this.fireEvent("invalidated", this);
52874 this.fireEvent("expanded", this);
52902 getAnchor : function(){
52903 return this.anchors[this.position];
52906 getCollapseAnchor : function(){
52907 return this.canchors[this.position];
52910 getSlideAnchor : function(){
52911 return this.sanchors[this.position];
52914 getAlignAdj : function(){
52915 var cm = this.cmargins;
52916 switch(this.position){
52932 getExpandAdj : function(){
52933 var c = this.collapsedEl, cm = this.cmargins;
52934 switch(this.position){
52936 return [-(cm.right+c.getWidth()+cm.left), 0];
52939 return [cm.right+c.getWidth()+cm.left, 0];
52942 return [0, -(cm.top+cm.bottom+c.getHeight())];
52945 return [0, cm.top+cm.bottom+c.getHeight()];
52951 * Ext JS Library 1.1.1
52952 * Copyright(c) 2006-2007, Ext JS, LLC.
52954 * Originally Released Under LGPL - original licence link has changed is not relivant.
52957 * <script type="text/javascript">
52960 * These classes are private internal classes
52962 Roo.CenterLayoutRegion = function(mgr, config){
52963 Roo.LayoutRegion.call(this, mgr, config, "center");
52964 this.visible = true;
52965 this.minWidth = config.minWidth || 20;
52966 this.minHeight = config.minHeight || 20;
52969 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52971 // center panel can't be hidden
52975 // center panel can't be hidden
52978 getMinWidth: function(){
52979 return this.minWidth;
52982 getMinHeight: function(){
52983 return this.minHeight;
52988 Roo.NorthLayoutRegion = function(mgr, config){
52989 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52991 this.split.placement = Roo.SplitBar.TOP;
52992 this.split.orientation = Roo.SplitBar.VERTICAL;
52993 this.split.el.addClass("x-layout-split-v");
52995 var size = config.initialSize || config.height;
52996 if(typeof size != "undefined"){
52997 this.el.setHeight(size);
53000 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53001 orientation: Roo.SplitBar.VERTICAL,
53002 getBox : function(){
53003 if(this.collapsed){
53004 return this.collapsedEl.getBox();
53006 var box = this.el.getBox();
53008 box.height += this.split.el.getHeight();
53013 updateBox : function(box){
53014 if(this.split && !this.collapsed){
53015 box.height -= this.split.el.getHeight();
53016 this.split.el.setLeft(box.x);
53017 this.split.el.setTop(box.y+box.height);
53018 this.split.el.setWidth(box.width);
53020 if(this.collapsed){
53021 this.updateBody(box.width, null);
53023 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53027 Roo.SouthLayoutRegion = function(mgr, config){
53028 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
53030 this.split.placement = Roo.SplitBar.BOTTOM;
53031 this.split.orientation = Roo.SplitBar.VERTICAL;
53032 this.split.el.addClass("x-layout-split-v");
53034 var size = config.initialSize || config.height;
53035 if(typeof size != "undefined"){
53036 this.el.setHeight(size);
53039 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
53040 orientation: Roo.SplitBar.VERTICAL,
53041 getBox : function(){
53042 if(this.collapsed){
53043 return this.collapsedEl.getBox();
53045 var box = this.el.getBox();
53047 var sh = this.split.el.getHeight();
53054 updateBox : function(box){
53055 if(this.split && !this.collapsed){
53056 var sh = this.split.el.getHeight();
53059 this.split.el.setLeft(box.x);
53060 this.split.el.setTop(box.y-sh);
53061 this.split.el.setWidth(box.width);
53063 if(this.collapsed){
53064 this.updateBody(box.width, null);
53066 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53070 Roo.EastLayoutRegion = function(mgr, config){
53071 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
53073 this.split.placement = Roo.SplitBar.RIGHT;
53074 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53075 this.split.el.addClass("x-layout-split-h");
53077 var size = config.initialSize || config.width;
53078 if(typeof size != "undefined"){
53079 this.el.setWidth(size);
53082 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
53083 orientation: Roo.SplitBar.HORIZONTAL,
53084 getBox : function(){
53085 if(this.collapsed){
53086 return this.collapsedEl.getBox();
53088 var box = this.el.getBox();
53090 var sw = this.split.el.getWidth();
53097 updateBox : function(box){
53098 if(this.split && !this.collapsed){
53099 var sw = this.split.el.getWidth();
53101 this.split.el.setLeft(box.x);
53102 this.split.el.setTop(box.y);
53103 this.split.el.setHeight(box.height);
53106 if(this.collapsed){
53107 this.updateBody(null, box.height);
53109 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53113 Roo.WestLayoutRegion = function(mgr, config){
53114 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
53116 this.split.placement = Roo.SplitBar.LEFT;
53117 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53118 this.split.el.addClass("x-layout-split-h");
53120 var size = config.initialSize || config.width;
53121 if(typeof size != "undefined"){
53122 this.el.setWidth(size);
53125 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
53126 orientation: Roo.SplitBar.HORIZONTAL,
53127 getBox : function(){
53128 if(this.collapsed){
53129 return this.collapsedEl.getBox();
53131 var box = this.el.getBox();
53133 box.width += this.split.el.getWidth();
53138 updateBox : function(box){
53139 if(this.split && !this.collapsed){
53140 var sw = this.split.el.getWidth();
53142 this.split.el.setLeft(box.x+box.width);
53143 this.split.el.setTop(box.y);
53144 this.split.el.setHeight(box.height);
53146 if(this.collapsed){
53147 this.updateBody(null, box.height);
53149 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53154 * Ext JS Library 1.1.1
53155 * Copyright(c) 2006-2007, Ext JS, LLC.
53157 * Originally Released Under LGPL - original licence link has changed is not relivant.
53160 * <script type="text/javascript">
53165 * Private internal class for reading and applying state
53167 Roo.LayoutStateManager = function(layout){
53168 // default empty state
53177 Roo.LayoutStateManager.prototype = {
53178 init : function(layout, provider){
53179 this.provider = provider;
53180 var state = provider.get(layout.id+"-layout-state");
53182 var wasUpdating = layout.isUpdating();
53184 layout.beginUpdate();
53186 for(var key in state){
53187 if(typeof state[key] != "function"){
53188 var rstate = state[key];
53189 var r = layout.getRegion(key);
53192 r.resizeTo(rstate.size);
53194 if(rstate.collapsed == true){
53197 r.expand(null, true);
53203 layout.endUpdate();
53205 this.state = state;
53207 this.layout = layout;
53208 layout.on("regionresized", this.onRegionResized, this);
53209 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53210 layout.on("regionexpanded", this.onRegionExpanded, this);
53213 storeState : function(){
53214 this.provider.set(this.layout.id+"-layout-state", this.state);
53217 onRegionResized : function(region, newSize){
53218 this.state[region.getPosition()].size = newSize;
53222 onRegionCollapsed : function(region){
53223 this.state[region.getPosition()].collapsed = true;
53227 onRegionExpanded : function(region){
53228 this.state[region.getPosition()].collapsed = false;
53233 * Ext JS Library 1.1.1
53234 * Copyright(c) 2006-2007, Ext JS, LLC.
53236 * Originally Released Under LGPL - original licence link has changed is not relivant.
53239 * <script type="text/javascript">
53242 * @class Roo.ContentPanel
53243 * @extends Roo.util.Observable
53244 * A basic ContentPanel element.
53245 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53246 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53247 * @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
53248 * @cfg {Boolean} closable True if the panel can be closed/removed
53249 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53250 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53251 * @cfg {Toolbar} toolbar A toolbar for this panel
53252 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53253 * @cfg {String} title The title for this panel
53254 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53255 * @cfg {String} url Calls {@link #setUrl} with this value
53256 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53257 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53258 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53259 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53262 * Create a new ContentPanel.
53263 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53264 * @param {String/Object} config A string to set only the title or a config object
53265 * @param {String} content (optional) Set the HTML content for this panel
53266 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53268 Roo.ContentPanel = function(el, config, content){
53272 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53276 if (config && config.parentLayout) {
53277 el = config.parentLayout.el.createChild();
53280 if(el.autoCreate){ // xtype is available if this is called from factory
53284 this.el = Roo.get(el);
53285 if(!this.el && config && config.autoCreate){
53286 if(typeof config.autoCreate == "object"){
53287 if(!config.autoCreate.id){
53288 config.autoCreate.id = config.id||el;
53290 this.el = Roo.DomHelper.append(document.body,
53291 config.autoCreate, true);
53293 this.el = Roo.DomHelper.append(document.body,
53294 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53297 this.closable = false;
53298 this.loaded = false;
53299 this.active = false;
53300 if(typeof config == "string"){
53301 this.title = config;
53303 Roo.apply(this, config);
53306 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53307 this.wrapEl = this.el.wrap();
53308 this.toolbar.container = this.el.insertSibling(false, 'before');
53309 this.toolbar = new Roo.Toolbar(this.toolbar);
53312 // xtype created footer. - not sure if will work as we normally have to render first..
53313 if (this.footer && !this.footer.el && this.footer.xtype) {
53314 if (!this.wrapEl) {
53315 this.wrapEl = this.el.wrap();
53318 this.footer.container = this.wrapEl.createChild();
53320 this.footer = Roo.factory(this.footer, Roo);
53325 this.resizeEl = Roo.get(this.resizeEl, true);
53327 this.resizeEl = this.el;
53329 // handle view.xtype
53337 * Fires when this panel is activated.
53338 * @param {Roo.ContentPanel} this
53342 * @event deactivate
53343 * Fires when this panel is activated.
53344 * @param {Roo.ContentPanel} this
53346 "deactivate" : true,
53350 * Fires when this panel is resized if fitToFrame is true.
53351 * @param {Roo.ContentPanel} this
53352 * @param {Number} width The width after any component adjustments
53353 * @param {Number} height The height after any component adjustments
53359 * Fires when this tab is created
53360 * @param {Roo.ContentPanel} this
53371 if(this.autoScroll){
53372 this.resizeEl.setStyle("overflow", "auto");
53374 // fix randome scrolling
53375 this.el.on('scroll', function() {
53376 Roo.log('fix random scolling');
53377 this.scrollTo('top',0);
53380 content = content || this.content;
53382 this.setContent(content);
53384 if(config && config.url){
53385 this.setUrl(this.url, this.params, this.loadOnce);
53390 Roo.ContentPanel.superclass.constructor.call(this);
53392 if (this.view && typeof(this.view.xtype) != 'undefined') {
53393 this.view.el = this.el.appendChild(document.createElement("div"));
53394 this.view = Roo.factory(this.view);
53395 this.view.render && this.view.render(false, '');
53399 this.fireEvent('render', this);
53402 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53404 setRegion : function(region){
53405 this.region = region;
53407 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53409 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53414 * Returns the toolbar for this Panel if one was configured.
53415 * @return {Roo.Toolbar}
53417 getToolbar : function(){
53418 return this.toolbar;
53421 setActiveState : function(active){
53422 this.active = active;
53424 this.fireEvent("deactivate", this);
53426 this.fireEvent("activate", this);
53430 * Updates this panel's element
53431 * @param {String} content The new content
53432 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53434 setContent : function(content, loadScripts){
53435 this.el.update(content, loadScripts);
53438 ignoreResize : function(w, h){
53439 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53442 this.lastSize = {width: w, height: h};
53447 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53448 * @return {Roo.UpdateManager} The UpdateManager
53450 getUpdateManager : function(){
53451 return this.el.getUpdateManager();
53454 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53455 * @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:
53458 url: "your-url.php",
53459 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53460 callback: yourFunction,
53461 scope: yourObject, //(optional scope)
53464 text: "Loading...",
53469 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53470 * 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.
53471 * @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}
53472 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53473 * @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.
53474 * @return {Roo.ContentPanel} this
53477 var um = this.el.getUpdateManager();
53478 um.update.apply(um, arguments);
53484 * 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.
53485 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53486 * @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)
53487 * @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)
53488 * @return {Roo.UpdateManager} The UpdateManager
53490 setUrl : function(url, params, loadOnce){
53491 if(this.refreshDelegate){
53492 this.removeListener("activate", this.refreshDelegate);
53494 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53495 this.on("activate", this.refreshDelegate);
53496 return this.el.getUpdateManager();
53499 _handleRefresh : function(url, params, loadOnce){
53500 if(!loadOnce || !this.loaded){
53501 var updater = this.el.getUpdateManager();
53502 updater.update(url, params, this._setLoaded.createDelegate(this));
53506 _setLoaded : function(){
53507 this.loaded = true;
53511 * Returns this panel's id
53514 getId : function(){
53519 * Returns this panel's element - used by regiosn to add.
53520 * @return {Roo.Element}
53522 getEl : function(){
53523 return this.wrapEl || this.el;
53526 adjustForComponents : function(width, height)
53528 //Roo.log('adjustForComponents ');
53529 if(this.resizeEl != this.el){
53530 width -= this.el.getFrameWidth('lr');
53531 height -= this.el.getFrameWidth('tb');
53534 var te = this.toolbar.getEl();
53535 height -= te.getHeight();
53536 te.setWidth(width);
53539 var te = this.footer.getEl();
53540 Roo.log("footer:" + te.getHeight());
53542 height -= te.getHeight();
53543 te.setWidth(width);
53547 if(this.adjustments){
53548 width += this.adjustments[0];
53549 height += this.adjustments[1];
53551 return {"width": width, "height": height};
53554 setSize : function(width, height){
53555 if(this.fitToFrame && !this.ignoreResize(width, height)){
53556 if(this.fitContainer && this.resizeEl != this.el){
53557 this.el.setSize(width, height);
53559 var size = this.adjustForComponents(width, height);
53560 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53561 this.fireEvent('resize', this, size.width, size.height);
53566 * Returns this panel's title
53569 getTitle : function(){
53574 * Set this panel's title
53575 * @param {String} title
53577 setTitle : function(title){
53578 this.title = title;
53580 this.region.updatePanelTitle(this, title);
53585 * Returns true is this panel was configured to be closable
53586 * @return {Boolean}
53588 isClosable : function(){
53589 return this.closable;
53592 beforeSlide : function(){
53594 this.resizeEl.clip();
53597 afterSlide : function(){
53599 this.resizeEl.unclip();
53603 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53604 * Will fail silently if the {@link #setUrl} method has not been called.
53605 * This does not activate the panel, just updates its content.
53607 refresh : function(){
53608 if(this.refreshDelegate){
53609 this.loaded = false;
53610 this.refreshDelegate();
53615 * Destroys this panel
53617 destroy : function(){
53618 this.el.removeAllListeners();
53619 var tempEl = document.createElement("span");
53620 tempEl.appendChild(this.el.dom);
53621 tempEl.innerHTML = "";
53627 * form - if the content panel contains a form - this is a reference to it.
53628 * @type {Roo.form.Form}
53632 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53633 * This contains a reference to it.
53639 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53649 * @param {Object} cfg Xtype definition of item to add.
53652 addxtype : function(cfg) {
53654 if (cfg.xtype.match(/^Form$/)) {
53657 //if (this.footer) {
53658 // el = this.footer.container.insertSibling(false, 'before');
53660 el = this.el.createChild();
53663 this.form = new Roo.form.Form(cfg);
53666 if ( this.form.allItems.length) {
53667 this.form.render(el.dom);
53671 // should only have one of theses..
53672 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53673 // views.. should not be just added - used named prop 'view''
53675 cfg.el = this.el.appendChild(document.createElement("div"));
53678 var ret = new Roo.factory(cfg);
53680 ret.render && ret.render(false, ''); // render blank..
53689 * @class Roo.GridPanel
53690 * @extends Roo.ContentPanel
53692 * Create a new GridPanel.
53693 * @param {Roo.grid.Grid} grid The grid for this panel
53694 * @param {String/Object} config A string to set only the panel's title, or a config object
53696 Roo.GridPanel = function(grid, config){
53699 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53700 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53702 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53704 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53707 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53709 // xtype created footer. - not sure if will work as we normally have to render first..
53710 if (this.footer && !this.footer.el && this.footer.xtype) {
53712 this.footer.container = this.grid.getView().getFooterPanel(true);
53713 this.footer.dataSource = this.grid.dataSource;
53714 this.footer = Roo.factory(this.footer, Roo);
53718 grid.monitorWindowResize = false; // turn off autosizing
53719 grid.autoHeight = false;
53720 grid.autoWidth = false;
53722 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53725 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53726 getId : function(){
53727 return this.grid.id;
53731 * Returns the grid for this panel
53732 * @return {Roo.grid.Grid}
53734 getGrid : function(){
53738 setSize : function(width, height){
53739 if(!this.ignoreResize(width, height)){
53740 var grid = this.grid;
53741 var size = this.adjustForComponents(width, height);
53742 grid.getGridEl().setSize(size.width, size.height);
53747 beforeSlide : function(){
53748 this.grid.getView().scroller.clip();
53751 afterSlide : function(){
53752 this.grid.getView().scroller.unclip();
53755 destroy : function(){
53756 this.grid.destroy();
53758 Roo.GridPanel.superclass.destroy.call(this);
53764 * @class Roo.NestedLayoutPanel
53765 * @extends Roo.ContentPanel
53767 * Create a new NestedLayoutPanel.
53770 * @param {Roo.BorderLayout} layout The layout for this panel
53771 * @param {String/Object} config A string to set only the title or a config object
53773 Roo.NestedLayoutPanel = function(layout, config)
53775 // construct with only one argument..
53776 /* FIXME - implement nicer consturctors
53777 if (layout.layout) {
53779 layout = config.layout;
53780 delete config.layout;
53782 if (layout.xtype && !layout.getEl) {
53783 // then layout needs constructing..
53784 layout = Roo.factory(layout, Roo);
53789 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53791 layout.monitorWindowResize = false; // turn off autosizing
53792 this.layout = layout;
53793 this.layout.getEl().addClass("x-layout-nested-layout");
53800 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53802 setSize : function(width, height){
53803 if(!this.ignoreResize(width, height)){
53804 var size = this.adjustForComponents(width, height);
53805 var el = this.layout.getEl();
53806 el.setSize(size.width, size.height);
53807 var touch = el.dom.offsetWidth;
53808 this.layout.layout();
53809 // ie requires a double layout on the first pass
53810 if(Roo.isIE && !this.initialized){
53811 this.initialized = true;
53812 this.layout.layout();
53817 // activate all subpanels if not currently active..
53819 setActiveState : function(active){
53820 this.active = active;
53822 this.fireEvent("deactivate", this);
53826 this.fireEvent("activate", this);
53827 // not sure if this should happen before or after..
53828 if (!this.layout) {
53829 return; // should not happen..
53832 for (var r in this.layout.regions) {
53833 reg = this.layout.getRegion(r);
53834 if (reg.getActivePanel()) {
53835 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53836 reg.setActivePanel(reg.getActivePanel());
53839 if (!reg.panels.length) {
53842 reg.showPanel(reg.getPanel(0));
53851 * Returns the nested BorderLayout for this panel
53852 * @return {Roo.BorderLayout}
53854 getLayout : function(){
53855 return this.layout;
53859 * Adds a xtype elements to the layout of the nested panel
53863 xtype : 'ContentPanel',
53870 xtype : 'NestedLayoutPanel',
53876 items : [ ... list of content panels or nested layout panels.. ]
53880 * @param {Object} cfg Xtype definition of item to add.
53882 addxtype : function(cfg) {
53883 return this.layout.addxtype(cfg);
53888 Roo.ScrollPanel = function(el, config, content){
53889 config = config || {};
53890 config.fitToFrame = true;
53891 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53893 this.el.dom.style.overflow = "hidden";
53894 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53895 this.el.removeClass("x-layout-inactive-content");
53896 this.el.on("mousewheel", this.onWheel, this);
53898 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53899 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53900 up.unselectable(); down.unselectable();
53901 up.on("click", this.scrollUp, this);
53902 down.on("click", this.scrollDown, this);
53903 up.addClassOnOver("x-scroller-btn-over");
53904 down.addClassOnOver("x-scroller-btn-over");
53905 up.addClassOnClick("x-scroller-btn-click");
53906 down.addClassOnClick("x-scroller-btn-click");
53907 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53909 this.resizeEl = this.el;
53910 this.el = wrap; this.up = up; this.down = down;
53913 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53915 wheelIncrement : 5,
53916 scrollUp : function(){
53917 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53920 scrollDown : function(){
53921 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53924 afterScroll : function(){
53925 var el = this.resizeEl;
53926 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53927 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53928 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53931 setSize : function(){
53932 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53933 this.afterScroll();
53936 onWheel : function(e){
53937 var d = e.getWheelDelta();
53938 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53939 this.afterScroll();
53943 setContent : function(content, loadScripts){
53944 this.resizeEl.update(content, loadScripts);
53958 * @class Roo.TreePanel
53959 * @extends Roo.ContentPanel
53961 * Create a new TreePanel. - defaults to fit/scoll contents.
53962 * @param {String/Object} config A string to set only the panel's title, or a config object
53963 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53965 Roo.TreePanel = function(config){
53966 var el = config.el;
53967 var tree = config.tree;
53968 delete config.tree;
53969 delete config.el; // hopefull!
53971 // wrapper for IE7 strict & safari scroll issue
53973 var treeEl = el.createChild();
53974 config.resizeEl = treeEl;
53978 Roo.TreePanel.superclass.constructor.call(this, el, config);
53981 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53982 //console.log(tree);
53983 this.on('activate', function()
53985 if (this.tree.rendered) {
53988 //console.log('render tree');
53989 this.tree.render();
53991 // this should not be needed.. - it's actually the 'el' that resizes?
53992 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53994 //this.on('resize', function (cp, w, h) {
53995 // this.tree.innerCt.setWidth(w);
53996 // this.tree.innerCt.setHeight(h);
53997 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54004 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
54021 * Ext JS Library 1.1.1
54022 * Copyright(c) 2006-2007, Ext JS, LLC.
54024 * Originally Released Under LGPL - original licence link has changed is not relivant.
54027 * <script type="text/javascript">
54032 * @class Roo.ReaderLayout
54033 * @extends Roo.BorderLayout
54034 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
54035 * center region containing two nested regions (a top one for a list view and one for item preview below),
54036 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
54037 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
54038 * expedites the setup of the overall layout and regions for this common application style.
54041 var reader = new Roo.ReaderLayout();
54042 var CP = Roo.ContentPanel; // shortcut for adding
54044 reader.beginUpdate();
54045 reader.add("north", new CP("north", "North"));
54046 reader.add("west", new CP("west", {title: "West"}));
54047 reader.add("east", new CP("east", {title: "East"}));
54049 reader.regions.listView.add(new CP("listView", "List"));
54050 reader.regions.preview.add(new CP("preview", "Preview"));
54051 reader.endUpdate();
54054 * Create a new ReaderLayout
54055 * @param {Object} config Configuration options
54056 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
54057 * document.body if omitted)
54059 Roo.ReaderLayout = function(config, renderTo){
54060 var c = config || {size:{}};
54061 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
54062 north: c.north !== false ? Roo.apply({
54066 }, c.north) : false,
54067 west: c.west !== false ? Roo.apply({
54075 margins:{left:5,right:0,bottom:5,top:5},
54076 cmargins:{left:5,right:5,bottom:5,top:5}
54077 }, c.west) : false,
54078 east: c.east !== false ? Roo.apply({
54086 margins:{left:0,right:5,bottom:5,top:5},
54087 cmargins:{left:5,right:5,bottom:5,top:5}
54088 }, c.east) : false,
54089 center: Roo.apply({
54090 tabPosition: 'top',
54094 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
54098 this.el.addClass('x-reader');
54100 this.beginUpdate();
54102 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
54103 south: c.preview !== false ? Roo.apply({
54110 cmargins:{top:5,left:0, right:0, bottom:0}
54111 }, c.preview) : false,
54112 center: Roo.apply({
54118 this.add('center', new Roo.NestedLayoutPanel(inner,
54119 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
54123 this.regions.preview = inner.getRegion('south');
54124 this.regions.listView = inner.getRegion('center');
54127 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
54129 * Ext JS Library 1.1.1
54130 * Copyright(c) 2006-2007, Ext JS, LLC.
54132 * Originally Released Under LGPL - original licence link has changed is not relivant.
54135 * <script type="text/javascript">
54139 * @class Roo.grid.Grid
54140 * @extends Roo.util.Observable
54141 * This class represents the primary interface of a component based grid control.
54142 * <br><br>Usage:<pre><code>
54143 var grid = new Roo.grid.Grid("my-container-id", {
54146 selModel: mySelectionModel,
54147 autoSizeColumns: true,
54148 monitorWindowResize: false,
54149 trackMouseOver: true
54154 * <b>Common Problems:</b><br/>
54155 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54156 * element will correct this<br/>
54157 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54158 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54159 * are unpredictable.<br/>
54160 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54161 * grid to calculate dimensions/offsets.<br/>
54163 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54164 * The container MUST have some type of size defined for the grid to fill. The container will be
54165 * automatically set to position relative if it isn't already.
54166 * @param {Object} config A config object that sets properties on this grid.
54168 Roo.grid.Grid = function(container, config){
54169 // initialize the container
54170 this.container = Roo.get(container);
54171 this.container.update("");
54172 this.container.setStyle("overflow", "hidden");
54173 this.container.addClass('x-grid-container');
54175 this.id = this.container.id;
54177 Roo.apply(this, config);
54178 // check and correct shorthanded configs
54180 this.dataSource = this.ds;
54184 this.colModel = this.cm;
54188 this.selModel = this.sm;
54192 if (this.selModel) {
54193 this.selModel = Roo.factory(this.selModel, Roo.grid);
54194 this.sm = this.selModel;
54195 this.sm.xmodule = this.xmodule || false;
54197 if (typeof(this.colModel.config) == 'undefined') {
54198 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54199 this.cm = this.colModel;
54200 this.cm.xmodule = this.xmodule || false;
54202 if (this.dataSource) {
54203 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54204 this.ds = this.dataSource;
54205 this.ds.xmodule = this.xmodule || false;
54212 this.container.setWidth(this.width);
54216 this.container.setHeight(this.height);
54223 * The raw click event for the entire grid.
54224 * @param {Roo.EventObject} e
54229 * The raw dblclick event for the entire grid.
54230 * @param {Roo.EventObject} e
54234 * @event contextmenu
54235 * The raw contextmenu event for the entire grid.
54236 * @param {Roo.EventObject} e
54238 "contextmenu" : true,
54241 * The raw mousedown event for the entire grid.
54242 * @param {Roo.EventObject} e
54244 "mousedown" : true,
54247 * The raw mouseup event for the entire grid.
54248 * @param {Roo.EventObject} e
54253 * The raw mouseover event for the entire grid.
54254 * @param {Roo.EventObject} e
54256 "mouseover" : true,
54259 * The raw mouseout event for the entire grid.
54260 * @param {Roo.EventObject} e
54265 * The raw keypress event for the entire grid.
54266 * @param {Roo.EventObject} e
54271 * The raw keydown event for the entire grid.
54272 * @param {Roo.EventObject} e
54280 * Fires when a cell is clicked
54281 * @param {Grid} this
54282 * @param {Number} rowIndex
54283 * @param {Number} columnIndex
54284 * @param {Roo.EventObject} e
54286 "cellclick" : true,
54288 * @event celldblclick
54289 * Fires when a cell is double clicked
54290 * @param {Grid} this
54291 * @param {Number} rowIndex
54292 * @param {Number} columnIndex
54293 * @param {Roo.EventObject} e
54295 "celldblclick" : true,
54298 * Fires when a row is clicked
54299 * @param {Grid} this
54300 * @param {Number} rowIndex
54301 * @param {Roo.EventObject} e
54305 * @event rowdblclick
54306 * Fires when a row is double clicked
54307 * @param {Grid} this
54308 * @param {Number} rowIndex
54309 * @param {Roo.EventObject} e
54311 "rowdblclick" : true,
54313 * @event headerclick
54314 * Fires when a header is clicked
54315 * @param {Grid} this
54316 * @param {Number} columnIndex
54317 * @param {Roo.EventObject} e
54319 "headerclick" : true,
54321 * @event headerdblclick
54322 * Fires when a header cell is double clicked
54323 * @param {Grid} this
54324 * @param {Number} columnIndex
54325 * @param {Roo.EventObject} e
54327 "headerdblclick" : true,
54329 * @event rowcontextmenu
54330 * Fires when a row is right clicked
54331 * @param {Grid} this
54332 * @param {Number} rowIndex
54333 * @param {Roo.EventObject} e
54335 "rowcontextmenu" : true,
54337 * @event cellcontextmenu
54338 * Fires when a cell is right clicked
54339 * @param {Grid} this
54340 * @param {Number} rowIndex
54341 * @param {Number} cellIndex
54342 * @param {Roo.EventObject} e
54344 "cellcontextmenu" : true,
54346 * @event headercontextmenu
54347 * Fires when a header is right clicked
54348 * @param {Grid} this
54349 * @param {Number} columnIndex
54350 * @param {Roo.EventObject} e
54352 "headercontextmenu" : true,
54354 * @event bodyscroll
54355 * Fires when the body element is scrolled
54356 * @param {Number} scrollLeft
54357 * @param {Number} scrollTop
54359 "bodyscroll" : true,
54361 * @event columnresize
54362 * Fires when the user resizes a column
54363 * @param {Number} columnIndex
54364 * @param {Number} newSize
54366 "columnresize" : true,
54368 * @event columnmove
54369 * Fires when the user moves a column
54370 * @param {Number} oldIndex
54371 * @param {Number} newIndex
54373 "columnmove" : true,
54376 * Fires when row(s) start being dragged
54377 * @param {Grid} this
54378 * @param {Roo.GridDD} dd The drag drop object
54379 * @param {event} e The raw browser event
54381 "startdrag" : true,
54384 * Fires when a drag operation is complete
54385 * @param {Grid} this
54386 * @param {Roo.GridDD} dd The drag drop object
54387 * @param {event} e The raw browser event
54392 * Fires when dragged row(s) are dropped on a valid DD target
54393 * @param {Grid} this
54394 * @param {Roo.GridDD} dd The drag drop object
54395 * @param {String} targetId The target drag drop object
54396 * @param {event} e The raw browser event
54401 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54402 * @param {Grid} this
54403 * @param {Roo.GridDD} dd The drag drop object
54404 * @param {String} targetId The target drag drop object
54405 * @param {event} e The raw browser event
54410 * Fires when the dragged row(s) first cross another DD target while being dragged
54411 * @param {Grid} this
54412 * @param {Roo.GridDD} dd The drag drop object
54413 * @param {String} targetId The target drag drop object
54414 * @param {event} e The raw browser event
54416 "dragenter" : true,
54419 * Fires when the dragged row(s) leave another DD target while being dragged
54420 * @param {Grid} this
54421 * @param {Roo.GridDD} dd The drag drop object
54422 * @param {String} targetId The target drag drop object
54423 * @param {event} e The raw browser event
54428 * Fires when a row is rendered, so you can change add a style to it.
54429 * @param {GridView} gridview The grid view
54430 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54436 * Fires when the grid is rendered
54437 * @param {Grid} grid
54442 Roo.grid.Grid.superclass.constructor.call(this);
54444 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54447 * @cfg {String} ddGroup - drag drop group.
54451 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54453 minColumnWidth : 25,
54456 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54457 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54458 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54460 autoSizeColumns : false,
54463 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54465 autoSizeHeaders : true,
54468 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54470 monitorWindowResize : true,
54473 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54474 * rows measured to get a columns size. Default is 0 (all rows).
54476 maxRowsToMeasure : 0,
54479 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54481 trackMouseOver : true,
54484 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54488 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54490 enableDragDrop : false,
54493 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54495 enableColumnMove : true,
54498 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54500 enableColumnHide : true,
54503 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54505 enableRowHeightSync : false,
54508 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54513 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54515 autoHeight : false,
54518 * @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.
54520 autoExpandColumn : false,
54523 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54526 autoExpandMin : 50,
54529 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54531 autoExpandMax : 1000,
54534 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54539 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54543 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54553 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54554 * of a fixed width. Default is false.
54557 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54560 * Called once after all setup has been completed and the grid is ready to be rendered.
54561 * @return {Roo.grid.Grid} this
54563 render : function()
54565 var c = this.container;
54566 // try to detect autoHeight/width mode
54567 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54568 this.autoHeight = true;
54570 var view = this.getView();
54573 c.on("click", this.onClick, this);
54574 c.on("dblclick", this.onDblClick, this);
54575 c.on("contextmenu", this.onContextMenu, this);
54576 c.on("keydown", this.onKeyDown, this);
54578 c.on("touchstart", this.onTouchStart, this);
54581 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54583 this.getSelectionModel().init(this);
54588 this.loadMask = new Roo.LoadMask(this.container,
54589 Roo.apply({store:this.dataSource}, this.loadMask));
54593 if (this.toolbar && this.toolbar.xtype) {
54594 this.toolbar.container = this.getView().getHeaderPanel(true);
54595 this.toolbar = new Roo.Toolbar(this.toolbar);
54597 if (this.footer && this.footer.xtype) {
54598 this.footer.dataSource = this.getDataSource();
54599 this.footer.container = this.getView().getFooterPanel(true);
54600 this.footer = Roo.factory(this.footer, Roo);
54602 if (this.dropTarget && this.dropTarget.xtype) {
54603 delete this.dropTarget.xtype;
54604 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54608 this.rendered = true;
54609 this.fireEvent('render', this);
54614 * Reconfigures the grid to use a different Store and Column Model.
54615 * The View will be bound to the new objects and refreshed.
54616 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54617 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54619 reconfigure : function(dataSource, colModel){
54621 this.loadMask.destroy();
54622 this.loadMask = new Roo.LoadMask(this.container,
54623 Roo.apply({store:dataSource}, this.loadMask));
54625 this.view.bind(dataSource, colModel);
54626 this.dataSource = dataSource;
54627 this.colModel = colModel;
54628 this.view.refresh(true);
54632 onKeyDown : function(e){
54633 this.fireEvent("keydown", e);
54637 * Destroy this grid.
54638 * @param {Boolean} removeEl True to remove the element
54640 destroy : function(removeEl, keepListeners){
54642 this.loadMask.destroy();
54644 var c = this.container;
54645 c.removeAllListeners();
54646 this.view.destroy();
54647 this.colModel.purgeListeners();
54648 if(!keepListeners){
54649 this.purgeListeners();
54652 if(removeEl === true){
54658 processEvent : function(name, e){
54659 // does this fire select???
54660 //Roo.log('grid:processEvent ' + name);
54662 if (name != 'touchstart' ) {
54663 this.fireEvent(name, e);
54666 var t = e.getTarget();
54668 var header = v.findHeaderIndex(t);
54669 if(header !== false){
54670 var ename = name == 'touchstart' ? 'click' : name;
54672 this.fireEvent("header" + ename, this, header, e);
54674 var row = v.findRowIndex(t);
54675 var cell = v.findCellIndex(t);
54676 if (name == 'touchstart') {
54677 // first touch is always a click.
54678 // hopefull this happens after selection is updated.?
54681 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54682 var cs = this.selModel.getSelectedCell();
54683 if (row == cs[0] && cell == cs[1]){
54687 if (typeof(this.selModel.getSelections) != 'undefined') {
54688 var cs = this.selModel.getSelections();
54689 var ds = this.dataSource;
54690 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54701 this.fireEvent("row" + name, this, row, e);
54702 if(cell !== false){
54703 this.fireEvent("cell" + name, this, row, cell, e);
54710 onClick : function(e){
54711 this.processEvent("click", e);
54714 onTouchStart : function(e){
54715 this.processEvent("touchstart", e);
54719 onContextMenu : function(e, t){
54720 this.processEvent("contextmenu", e);
54724 onDblClick : function(e){
54725 this.processEvent("dblclick", e);
54729 walkCells : function(row, col, step, fn, scope){
54730 var cm = this.colModel, clen = cm.getColumnCount();
54731 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54743 if(fn.call(scope || this, row, col, cm) === true){
54761 if(fn.call(scope || this, row, col, cm) === true){
54773 getSelections : function(){
54774 return this.selModel.getSelections();
54778 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54779 * but if manual update is required this method will initiate it.
54781 autoSize : function(){
54783 this.view.layout();
54784 if(this.view.adjustForScroll){
54785 this.view.adjustForScroll();
54791 * Returns the grid's underlying element.
54792 * @return {Element} The element
54794 getGridEl : function(){
54795 return this.container;
54798 // private for compatibility, overridden by editor grid
54799 stopEditing : function(){},
54802 * Returns the grid's SelectionModel.
54803 * @return {SelectionModel}
54805 getSelectionModel : function(){
54806 if(!this.selModel){
54807 this.selModel = new Roo.grid.RowSelectionModel();
54809 return this.selModel;
54813 * Returns the grid's DataSource.
54814 * @return {DataSource}
54816 getDataSource : function(){
54817 return this.dataSource;
54821 * Returns the grid's ColumnModel.
54822 * @return {ColumnModel}
54824 getColumnModel : function(){
54825 return this.colModel;
54829 * Returns the grid's GridView object.
54830 * @return {GridView}
54832 getView : function(){
54834 this.view = new Roo.grid.GridView(this.viewConfig);
54839 * Called to get grid's drag proxy text, by default returns this.ddText.
54842 getDragDropText : function(){
54843 var count = this.selModel.getCount();
54844 return String.format(this.ddText, count, count == 1 ? '' : 's');
54848 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54849 * %0 is replaced with the number of selected rows.
54852 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54854 * Ext JS Library 1.1.1
54855 * Copyright(c) 2006-2007, Ext JS, LLC.
54857 * Originally Released Under LGPL - original licence link has changed is not relivant.
54860 * <script type="text/javascript">
54863 Roo.grid.AbstractGridView = function(){
54867 "beforerowremoved" : true,
54868 "beforerowsinserted" : true,
54869 "beforerefresh" : true,
54870 "rowremoved" : true,
54871 "rowsinserted" : true,
54872 "rowupdated" : true,
54875 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54878 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54879 rowClass : "x-grid-row",
54880 cellClass : "x-grid-cell",
54881 tdClass : "x-grid-td",
54882 hdClass : "x-grid-hd",
54883 splitClass : "x-grid-hd-split",
54885 init: function(grid){
54887 var cid = this.grid.getGridEl().id;
54888 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54889 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54890 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54891 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54894 getColumnRenderers : function(){
54895 var renderers = [];
54896 var cm = this.grid.colModel;
54897 var colCount = cm.getColumnCount();
54898 for(var i = 0; i < colCount; i++){
54899 renderers[i] = cm.getRenderer(i);
54904 getColumnIds : function(){
54906 var cm = this.grid.colModel;
54907 var colCount = cm.getColumnCount();
54908 for(var i = 0; i < colCount; i++){
54909 ids[i] = cm.getColumnId(i);
54914 getDataIndexes : function(){
54915 if(!this.indexMap){
54916 this.indexMap = this.buildIndexMap();
54918 return this.indexMap.colToData;
54921 getColumnIndexByDataIndex : function(dataIndex){
54922 if(!this.indexMap){
54923 this.indexMap = this.buildIndexMap();
54925 return this.indexMap.dataToCol[dataIndex];
54929 * Set a css style for a column dynamically.
54930 * @param {Number} colIndex The index of the column
54931 * @param {String} name The css property name
54932 * @param {String} value The css value
54934 setCSSStyle : function(colIndex, name, value){
54935 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54936 Roo.util.CSS.updateRule(selector, name, value);
54939 generateRules : function(cm){
54940 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54941 Roo.util.CSS.removeStyleSheet(rulesId);
54942 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54943 var cid = cm.getColumnId(i);
54944 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54945 this.tdSelector, cid, " {\n}\n",
54946 this.hdSelector, cid, " {\n}\n",
54947 this.splitSelector, cid, " {\n}\n");
54949 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54953 * Ext JS Library 1.1.1
54954 * Copyright(c) 2006-2007, Ext JS, LLC.
54956 * Originally Released Under LGPL - original licence link has changed is not relivant.
54959 * <script type="text/javascript">
54963 // This is a support class used internally by the Grid components
54964 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54966 this.view = grid.getView();
54967 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54968 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54970 this.setHandleElId(Roo.id(hd));
54971 this.setOuterHandleElId(Roo.id(hd2));
54973 this.scroll = false;
54975 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54977 getDragData : function(e){
54978 var t = Roo.lib.Event.getTarget(e);
54979 var h = this.view.findHeaderCell(t);
54981 return {ddel: h.firstChild, header:h};
54986 onInitDrag : function(e){
54987 this.view.headersDisabled = true;
54988 var clone = this.dragData.ddel.cloneNode(true);
54989 clone.id = Roo.id();
54990 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54991 this.proxy.update(clone);
54995 afterValidDrop : function(){
54997 setTimeout(function(){
54998 v.headersDisabled = false;
55002 afterInvalidDrop : function(){
55004 setTimeout(function(){
55005 v.headersDisabled = false;
55011 * Ext JS Library 1.1.1
55012 * Copyright(c) 2006-2007, Ext JS, LLC.
55014 * Originally Released Under LGPL - original licence link has changed is not relivant.
55017 * <script type="text/javascript">
55020 // This is a support class used internally by the Grid components
55021 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
55023 this.view = grid.getView();
55024 // split the proxies so they don't interfere with mouse events
55025 this.proxyTop = Roo.DomHelper.append(document.body, {
55026 cls:"col-move-top", html:" "
55028 this.proxyBottom = Roo.DomHelper.append(document.body, {
55029 cls:"col-move-bottom", html:" "
55031 this.proxyTop.hide = this.proxyBottom.hide = function(){
55032 this.setLeftTop(-100,-100);
55033 this.setStyle("visibility", "hidden");
55035 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55036 // temporarily disabled
55037 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
55038 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
55040 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
55041 proxyOffsets : [-4, -9],
55042 fly: Roo.Element.fly,
55044 getTargetFromEvent : function(e){
55045 var t = Roo.lib.Event.getTarget(e);
55046 var cindex = this.view.findCellIndex(t);
55047 if(cindex !== false){
55048 return this.view.getHeaderCell(cindex);
55053 nextVisible : function(h){
55054 var v = this.view, cm = this.grid.colModel;
55057 if(!cm.isHidden(v.getCellIndex(h))){
55065 prevVisible : function(h){
55066 var v = this.view, cm = this.grid.colModel;
55069 if(!cm.isHidden(v.getCellIndex(h))){
55077 positionIndicator : function(h, n, e){
55078 var x = Roo.lib.Event.getPageX(e);
55079 var r = Roo.lib.Dom.getRegion(n.firstChild);
55080 var px, pt, py = r.top + this.proxyOffsets[1];
55081 if((r.right - x) <= (r.right-r.left)/2){
55082 px = r.right+this.view.borderWidth;
55088 var oldIndex = this.view.getCellIndex(h);
55089 var newIndex = this.view.getCellIndex(n);
55091 if(this.grid.colModel.isFixed(newIndex)){
55095 var locked = this.grid.colModel.isLocked(newIndex);
55100 if(oldIndex < newIndex){
55103 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
55106 px += this.proxyOffsets[0];
55107 this.proxyTop.setLeftTop(px, py);
55108 this.proxyTop.show();
55109 if(!this.bottomOffset){
55110 this.bottomOffset = this.view.mainHd.getHeight();
55112 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
55113 this.proxyBottom.show();
55117 onNodeEnter : function(n, dd, e, data){
55118 if(data.header != n){
55119 this.positionIndicator(data.header, n, e);
55123 onNodeOver : function(n, dd, e, data){
55124 var result = false;
55125 if(data.header != n){
55126 result = this.positionIndicator(data.header, n, e);
55129 this.proxyTop.hide();
55130 this.proxyBottom.hide();
55132 return result ? this.dropAllowed : this.dropNotAllowed;
55135 onNodeOut : function(n, dd, e, data){
55136 this.proxyTop.hide();
55137 this.proxyBottom.hide();
55140 onNodeDrop : function(n, dd, e, data){
55141 var h = data.header;
55143 var cm = this.grid.colModel;
55144 var x = Roo.lib.Event.getPageX(e);
55145 var r = Roo.lib.Dom.getRegion(n.firstChild);
55146 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55147 var oldIndex = this.view.getCellIndex(h);
55148 var newIndex = this.view.getCellIndex(n);
55149 var locked = cm.isLocked(newIndex);
55153 if(oldIndex < newIndex){
55156 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55159 cm.setLocked(oldIndex, locked, true);
55160 cm.moveColumn(oldIndex, newIndex);
55161 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55169 * Ext JS Library 1.1.1
55170 * Copyright(c) 2006-2007, Ext JS, LLC.
55172 * Originally Released Under LGPL - original licence link has changed is not relivant.
55175 * <script type="text/javascript">
55179 * @class Roo.grid.GridView
55180 * @extends Roo.util.Observable
55183 * @param {Object} config
55185 Roo.grid.GridView = function(config){
55186 Roo.grid.GridView.superclass.constructor.call(this);
55189 Roo.apply(this, config);
55192 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55194 unselectable : 'unselectable="on"',
55195 unselectableCls : 'x-unselectable',
55198 rowClass : "x-grid-row",
55200 cellClass : "x-grid-col",
55202 tdClass : "x-grid-td",
55204 hdClass : "x-grid-hd",
55206 splitClass : "x-grid-split",
55208 sortClasses : ["sort-asc", "sort-desc"],
55210 enableMoveAnim : false,
55214 dh : Roo.DomHelper,
55216 fly : Roo.Element.fly,
55218 css : Roo.util.CSS,
55224 scrollIncrement : 22,
55226 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55228 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55230 bind : function(ds, cm){
55232 this.ds.un("load", this.onLoad, this);
55233 this.ds.un("datachanged", this.onDataChange, this);
55234 this.ds.un("add", this.onAdd, this);
55235 this.ds.un("remove", this.onRemove, this);
55236 this.ds.un("update", this.onUpdate, this);
55237 this.ds.un("clear", this.onClear, this);
55240 ds.on("load", this.onLoad, this);
55241 ds.on("datachanged", this.onDataChange, this);
55242 ds.on("add", this.onAdd, this);
55243 ds.on("remove", this.onRemove, this);
55244 ds.on("update", this.onUpdate, this);
55245 ds.on("clear", this.onClear, this);
55250 this.cm.un("widthchange", this.onColWidthChange, this);
55251 this.cm.un("headerchange", this.onHeaderChange, this);
55252 this.cm.un("hiddenchange", this.onHiddenChange, this);
55253 this.cm.un("columnmoved", this.onColumnMove, this);
55254 this.cm.un("columnlockchange", this.onColumnLock, this);
55257 this.generateRules(cm);
55258 cm.on("widthchange", this.onColWidthChange, this);
55259 cm.on("headerchange", this.onHeaderChange, this);
55260 cm.on("hiddenchange", this.onHiddenChange, this);
55261 cm.on("columnmoved", this.onColumnMove, this);
55262 cm.on("columnlockchange", this.onColumnLock, this);
55267 init: function(grid){
55268 Roo.grid.GridView.superclass.init.call(this, grid);
55270 this.bind(grid.dataSource, grid.colModel);
55272 grid.on("headerclick", this.handleHeaderClick, this);
55274 if(grid.trackMouseOver){
55275 grid.on("mouseover", this.onRowOver, this);
55276 grid.on("mouseout", this.onRowOut, this);
55278 grid.cancelTextSelection = function(){};
55279 this.gridId = grid.id;
55281 var tpls = this.templates || {};
55284 tpls.master = new Roo.Template(
55285 '<div class="x-grid" hidefocus="true">',
55286 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55287 '<div class="x-grid-topbar"></div>',
55288 '<div class="x-grid-scroller"><div></div></div>',
55289 '<div class="x-grid-locked">',
55290 '<div class="x-grid-header">{lockedHeader}</div>',
55291 '<div class="x-grid-body">{lockedBody}</div>',
55293 '<div class="x-grid-viewport">',
55294 '<div class="x-grid-header">{header}</div>',
55295 '<div class="x-grid-body">{body}</div>',
55297 '<div class="x-grid-bottombar"></div>',
55299 '<div class="x-grid-resize-proxy"> </div>',
55302 tpls.master.disableformats = true;
55306 tpls.header = new Roo.Template(
55307 '<table border="0" cellspacing="0" cellpadding="0">',
55308 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55311 tpls.header.disableformats = true;
55313 tpls.header.compile();
55316 tpls.hcell = new Roo.Template(
55317 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55318 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55321 tpls.hcell.disableFormats = true;
55323 tpls.hcell.compile();
55326 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55327 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55328 tpls.hsplit.disableFormats = true;
55330 tpls.hsplit.compile();
55333 tpls.body = new Roo.Template(
55334 '<table border="0" cellspacing="0" cellpadding="0">',
55335 "<tbody>{rows}</tbody>",
55338 tpls.body.disableFormats = true;
55340 tpls.body.compile();
55343 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55344 tpls.row.disableFormats = true;
55346 tpls.row.compile();
55349 tpls.cell = new Roo.Template(
55350 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55351 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55352 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55355 tpls.cell.disableFormats = true;
55357 tpls.cell.compile();
55359 this.templates = tpls;
55362 // remap these for backwards compat
55363 onColWidthChange : function(){
55364 this.updateColumns.apply(this, arguments);
55366 onHeaderChange : function(){
55367 this.updateHeaders.apply(this, arguments);
55369 onHiddenChange : function(){
55370 this.handleHiddenChange.apply(this, arguments);
55372 onColumnMove : function(){
55373 this.handleColumnMove.apply(this, arguments);
55375 onColumnLock : function(){
55376 this.handleLockChange.apply(this, arguments);
55379 onDataChange : function(){
55381 this.updateHeaderSortState();
55384 onClear : function(){
55388 onUpdate : function(ds, record){
55389 this.refreshRow(record);
55392 refreshRow : function(record){
55393 var ds = this.ds, index;
55394 if(typeof record == 'number'){
55396 record = ds.getAt(index);
55398 index = ds.indexOf(record);
55400 this.insertRows(ds, index, index, true);
55401 this.onRemove(ds, record, index+1, true);
55402 this.syncRowHeights(index, index);
55404 this.fireEvent("rowupdated", this, index, record);
55407 onAdd : function(ds, records, index){
55408 this.insertRows(ds, index, index + (records.length-1));
55411 onRemove : function(ds, record, index, isUpdate){
55412 if(isUpdate !== true){
55413 this.fireEvent("beforerowremoved", this, index, record);
55415 var bt = this.getBodyTable(), lt = this.getLockedTable();
55416 if(bt.rows[index]){
55417 bt.firstChild.removeChild(bt.rows[index]);
55419 if(lt.rows[index]){
55420 lt.firstChild.removeChild(lt.rows[index]);
55422 if(isUpdate !== true){
55423 this.stripeRows(index);
55424 this.syncRowHeights(index, index);
55426 this.fireEvent("rowremoved", this, index, record);
55430 onLoad : function(){
55431 this.scrollToTop();
55435 * Scrolls the grid to the top
55437 scrollToTop : function(){
55439 this.scroller.dom.scrollTop = 0;
55445 * Gets a panel in the header of the grid that can be used for toolbars etc.
55446 * After modifying the contents of this panel a call to grid.autoSize() may be
55447 * required to register any changes in size.
55448 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55449 * @return Roo.Element
55451 getHeaderPanel : function(doShow){
55453 this.headerPanel.show();
55455 return this.headerPanel;
55459 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55460 * After modifying the contents of this panel a call to grid.autoSize() may be
55461 * required to register any changes in size.
55462 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55463 * @return Roo.Element
55465 getFooterPanel : function(doShow){
55467 this.footerPanel.show();
55469 return this.footerPanel;
55472 initElements : function(){
55473 var E = Roo.Element;
55474 var el = this.grid.getGridEl().dom.firstChild;
55475 var cs = el.childNodes;
55477 this.el = new E(el);
55479 this.focusEl = new E(el.firstChild);
55480 this.focusEl.swallowEvent("click", true);
55482 this.headerPanel = new E(cs[1]);
55483 this.headerPanel.enableDisplayMode("block");
55485 this.scroller = new E(cs[2]);
55486 this.scrollSizer = new E(this.scroller.dom.firstChild);
55488 this.lockedWrap = new E(cs[3]);
55489 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55490 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55492 this.mainWrap = new E(cs[4]);
55493 this.mainHd = new E(this.mainWrap.dom.firstChild);
55494 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55496 this.footerPanel = new E(cs[5]);
55497 this.footerPanel.enableDisplayMode("block");
55499 this.resizeProxy = new E(cs[6]);
55501 this.headerSelector = String.format(
55502 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55503 this.lockedHd.id, this.mainHd.id
55506 this.splitterSelector = String.format(
55507 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55508 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55511 idToCssName : function(s)
55513 return s.replace(/[^a-z0-9]+/ig, '-');
55516 getHeaderCell : function(index){
55517 return Roo.DomQuery.select(this.headerSelector)[index];
55520 getHeaderCellMeasure : function(index){
55521 return this.getHeaderCell(index).firstChild;
55524 getHeaderCellText : function(index){
55525 return this.getHeaderCell(index).firstChild.firstChild;
55528 getLockedTable : function(){
55529 return this.lockedBody.dom.firstChild;
55532 getBodyTable : function(){
55533 return this.mainBody.dom.firstChild;
55536 getLockedRow : function(index){
55537 return this.getLockedTable().rows[index];
55540 getRow : function(index){
55541 return this.getBodyTable().rows[index];
55544 getRowComposite : function(index){
55546 this.rowEl = new Roo.CompositeElementLite();
55548 var els = [], lrow, mrow;
55549 if(lrow = this.getLockedRow(index)){
55552 if(mrow = this.getRow(index)){
55555 this.rowEl.elements = els;
55559 * Gets the 'td' of the cell
55561 * @param {Integer} rowIndex row to select
55562 * @param {Integer} colIndex column to select
55566 getCell : function(rowIndex, colIndex){
55567 var locked = this.cm.getLockedCount();
55569 if(colIndex < locked){
55570 source = this.lockedBody.dom.firstChild;
55572 source = this.mainBody.dom.firstChild;
55573 colIndex -= locked;
55575 return source.rows[rowIndex].childNodes[colIndex];
55578 getCellText : function(rowIndex, colIndex){
55579 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55582 getCellBox : function(cell){
55583 var b = this.fly(cell).getBox();
55584 if(Roo.isOpera){ // opera fails to report the Y
55585 b.y = cell.offsetTop + this.mainBody.getY();
55590 getCellIndex : function(cell){
55591 var id = String(cell.className).match(this.cellRE);
55593 return parseInt(id[1], 10);
55598 findHeaderIndex : function(n){
55599 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55600 return r ? this.getCellIndex(r) : false;
55603 findHeaderCell : function(n){
55604 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55605 return r ? r : false;
55608 findRowIndex : function(n){
55612 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55613 return r ? r.rowIndex : false;
55616 findCellIndex : function(node){
55617 var stop = this.el.dom;
55618 while(node && node != stop){
55619 if(this.findRE.test(node.className)){
55620 return this.getCellIndex(node);
55622 node = node.parentNode;
55627 getColumnId : function(index){
55628 return this.cm.getColumnId(index);
55631 getSplitters : function()
55633 if(this.splitterSelector){
55634 return Roo.DomQuery.select(this.splitterSelector);
55640 getSplitter : function(index){
55641 return this.getSplitters()[index];
55644 onRowOver : function(e, t){
55646 if((row = this.findRowIndex(t)) !== false){
55647 this.getRowComposite(row).addClass("x-grid-row-over");
55651 onRowOut : function(e, t){
55653 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55654 this.getRowComposite(row).removeClass("x-grid-row-over");
55658 renderHeaders : function(){
55660 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55661 var cb = [], lb = [], sb = [], lsb = [], p = {};
55662 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55663 p.cellId = "x-grid-hd-0-" + i;
55664 p.splitId = "x-grid-csplit-0-" + i;
55665 p.id = cm.getColumnId(i);
55666 p.value = cm.getColumnHeader(i) || "";
55667 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55668 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55669 if(!cm.isLocked(i)){
55670 cb[cb.length] = ct.apply(p);
55671 sb[sb.length] = st.apply(p);
55673 lb[lb.length] = ct.apply(p);
55674 lsb[lsb.length] = st.apply(p);
55677 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55678 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55681 updateHeaders : function(){
55682 var html = this.renderHeaders();
55683 this.lockedHd.update(html[0]);
55684 this.mainHd.update(html[1]);
55688 * Focuses the specified row.
55689 * @param {Number} row The row index
55691 focusRow : function(row)
55693 //Roo.log('GridView.focusRow');
55694 var x = this.scroller.dom.scrollLeft;
55695 this.focusCell(row, 0, false);
55696 this.scroller.dom.scrollLeft = x;
55700 * Focuses the specified cell.
55701 * @param {Number} row The row index
55702 * @param {Number} col The column index
55703 * @param {Boolean} hscroll false to disable horizontal scrolling
55705 focusCell : function(row, col, hscroll)
55707 //Roo.log('GridView.focusCell');
55708 var el = this.ensureVisible(row, col, hscroll);
55709 this.focusEl.alignTo(el, "tl-tl");
55711 this.focusEl.focus();
55713 this.focusEl.focus.defer(1, this.focusEl);
55718 * Scrolls the specified cell into view
55719 * @param {Number} row The row index
55720 * @param {Number} col The column index
55721 * @param {Boolean} hscroll false to disable horizontal scrolling
55723 ensureVisible : function(row, col, hscroll)
55725 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55726 //return null; //disable for testing.
55727 if(typeof row != "number"){
55728 row = row.rowIndex;
55730 if(row < 0 && row >= this.ds.getCount()){
55733 col = (col !== undefined ? col : 0);
55734 var cm = this.grid.colModel;
55735 while(cm.isHidden(col)){
55739 var el = this.getCell(row, col);
55743 var c = this.scroller.dom;
55745 var ctop = parseInt(el.offsetTop, 10);
55746 var cleft = parseInt(el.offsetLeft, 10);
55747 var cbot = ctop + el.offsetHeight;
55748 var cright = cleft + el.offsetWidth;
55750 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55751 var stop = parseInt(c.scrollTop, 10);
55752 var sleft = parseInt(c.scrollLeft, 10);
55753 var sbot = stop + ch;
55754 var sright = sleft + c.clientWidth;
55756 Roo.log('GridView.ensureVisible:' +
55758 ' c.clientHeight:' + c.clientHeight +
55759 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55767 c.scrollTop = ctop;
55768 //Roo.log("set scrolltop to ctop DISABLE?");
55769 }else if(cbot > sbot){
55770 //Roo.log("set scrolltop to cbot-ch");
55771 c.scrollTop = cbot-ch;
55774 if(hscroll !== false){
55776 c.scrollLeft = cleft;
55777 }else if(cright > sright){
55778 c.scrollLeft = cright-c.clientWidth;
55785 updateColumns : function(){
55786 this.grid.stopEditing();
55787 var cm = this.grid.colModel, colIds = this.getColumnIds();
55788 //var totalWidth = cm.getTotalWidth();
55790 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55791 //if(cm.isHidden(i)) continue;
55792 var w = cm.getColumnWidth(i);
55793 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55794 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55796 this.updateSplitters();
55799 generateRules : function(cm){
55800 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55801 Roo.util.CSS.removeStyleSheet(rulesId);
55802 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55803 var cid = cm.getColumnId(i);
55805 if(cm.config[i].align){
55806 align = 'text-align:'+cm.config[i].align+';';
55809 if(cm.isHidden(i)){
55810 hidden = 'display:none;';
55812 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55814 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55815 this.hdSelector, cid, " {\n", align, width, "}\n",
55816 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55817 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55819 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55822 updateSplitters : function(){
55823 var cm = this.cm, s = this.getSplitters();
55824 if(s){ // splitters not created yet
55825 var pos = 0, locked = true;
55826 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55827 if(cm.isHidden(i)) {
55830 var w = cm.getColumnWidth(i); // make sure it's a number
55831 if(!cm.isLocked(i) && locked){
55836 s[i].style.left = (pos-this.splitOffset) + "px";
55841 handleHiddenChange : function(colModel, colIndex, hidden){
55843 this.hideColumn(colIndex);
55845 this.unhideColumn(colIndex);
55849 hideColumn : function(colIndex){
55850 var cid = this.getColumnId(colIndex);
55851 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55852 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55854 this.updateHeaders();
55856 this.updateSplitters();
55860 unhideColumn : function(colIndex){
55861 var cid = this.getColumnId(colIndex);
55862 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55863 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55866 this.updateHeaders();
55868 this.updateSplitters();
55872 insertRows : function(dm, firstRow, lastRow, isUpdate){
55873 if(firstRow == 0 && lastRow == dm.getCount()-1){
55877 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55879 var s = this.getScrollState();
55880 var markup = this.renderRows(firstRow, lastRow);
55881 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55882 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55883 this.restoreScroll(s);
55885 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55886 this.syncRowHeights(firstRow, lastRow);
55887 this.stripeRows(firstRow);
55893 bufferRows : function(markup, target, index){
55894 var before = null, trows = target.rows, tbody = target.tBodies[0];
55895 if(index < trows.length){
55896 before = trows[index];
55898 var b = document.createElement("div");
55899 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55900 var rows = b.firstChild.rows;
55901 for(var i = 0, len = rows.length; i < len; i++){
55903 tbody.insertBefore(rows[0], before);
55905 tbody.appendChild(rows[0]);
55912 deleteRows : function(dm, firstRow, lastRow){
55913 if(dm.getRowCount()<1){
55914 this.fireEvent("beforerefresh", this);
55915 this.mainBody.update("");
55916 this.lockedBody.update("");
55917 this.fireEvent("refresh", this);
55919 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55920 var bt = this.getBodyTable();
55921 var tbody = bt.firstChild;
55922 var rows = bt.rows;
55923 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55924 tbody.removeChild(rows[firstRow]);
55926 this.stripeRows(firstRow);
55927 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55931 updateRows : function(dataSource, firstRow, lastRow){
55932 var s = this.getScrollState();
55934 this.restoreScroll(s);
55937 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55941 this.updateHeaderSortState();
55944 getScrollState : function(){
55946 var sb = this.scroller.dom;
55947 return {left: sb.scrollLeft, top: sb.scrollTop};
55950 stripeRows : function(startRow){
55951 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55954 startRow = startRow || 0;
55955 var rows = this.getBodyTable().rows;
55956 var lrows = this.getLockedTable().rows;
55957 var cls = ' x-grid-row-alt ';
55958 for(var i = startRow, len = rows.length; i < len; i++){
55959 var row = rows[i], lrow = lrows[i];
55960 var isAlt = ((i+1) % 2 == 0);
55961 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55962 if(isAlt == hasAlt){
55966 row.className += " x-grid-row-alt";
55968 row.className = row.className.replace("x-grid-row-alt", "");
55971 lrow.className = row.className;
55976 restoreScroll : function(state){
55977 //Roo.log('GridView.restoreScroll');
55978 var sb = this.scroller.dom;
55979 sb.scrollLeft = state.left;
55980 sb.scrollTop = state.top;
55984 syncScroll : function(){
55985 //Roo.log('GridView.syncScroll');
55986 var sb = this.scroller.dom;
55987 var sh = this.mainHd.dom;
55988 var bs = this.mainBody.dom;
55989 var lv = this.lockedBody.dom;
55990 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55991 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55994 handleScroll : function(e){
55996 var sb = this.scroller.dom;
55997 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
56001 handleWheel : function(e){
56002 var d = e.getWheelDelta();
56003 this.scroller.dom.scrollTop -= d*22;
56004 // set this here to prevent jumpy scrolling on large tables
56005 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
56009 renderRows : function(startRow, endRow){
56010 // pull in all the crap needed to render rows
56011 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
56012 var colCount = cm.getColumnCount();
56014 if(ds.getCount() < 1){
56018 // build a map for all the columns
56020 for(var i = 0; i < colCount; i++){
56021 var name = cm.getDataIndex(i);
56023 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
56024 renderer : cm.getRenderer(i),
56025 id : cm.getColumnId(i),
56026 locked : cm.isLocked(i),
56027 has_editor : cm.isCellEditable(i)
56031 startRow = startRow || 0;
56032 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
56034 // records to render
56035 var rs = ds.getRange(startRow, endRow);
56037 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
56040 // As much as I hate to duplicate code, this was branched because FireFox really hates
56041 // [].join("") on strings. The performance difference was substantial enough to
56042 // branch this function
56043 doRender : Roo.isGecko ?
56044 function(cs, rs, ds, startRow, colCount, stripe){
56045 var ts = this.templates, ct = ts.cell, rt = ts.row;
56047 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56049 var hasListener = this.grid.hasListener('rowclass');
56051 for(var j = 0, len = rs.length; j < len; j++){
56052 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
56053 for(var i = 0; i < colCount; i++){
56055 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56057 p.css = p.attr = "";
56058 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56059 if(p.value == undefined || p.value === "") {
56060 p.value = " ";
56063 p.css += ' x-grid-editable-cell';
56065 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
56066 p.css += ' x-grid-dirty-cell';
56068 var markup = ct.apply(p);
56076 if(stripe && ((rowIndex+1) % 2 == 0)){
56077 alt.push("x-grid-row-alt")
56080 alt.push( " x-grid-dirty-row");
56083 if(this.getRowClass){
56084 alt.push(this.getRowClass(r, rowIndex));
56090 rowIndex : rowIndex,
56093 this.grid.fireEvent('rowclass', this, rowcfg);
56094 alt.push(rowcfg.rowClass);
56096 rp.alt = alt.join(" ");
56097 lbuf+= rt.apply(rp);
56099 buf+= rt.apply(rp);
56101 return [lbuf, buf];
56103 function(cs, rs, ds, startRow, colCount, stripe){
56104 var ts = this.templates, ct = ts.cell, rt = ts.row;
56106 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56107 var hasListener = this.grid.hasListener('rowclass');
56110 for(var j = 0, len = rs.length; j < len; j++){
56111 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
56112 for(var i = 0; i < colCount; i++){
56114 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56116 p.css = p.attr = "";
56117 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56118 if(p.value == undefined || p.value === "") {
56119 p.value = " ";
56123 p.css += ' x-grid-editable-cell';
56125 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
56126 p.css += ' x-grid-dirty-cell'
56129 var markup = ct.apply(p);
56131 cb[cb.length] = markup;
56133 lcb[lcb.length] = markup;
56137 if(stripe && ((rowIndex+1) % 2 == 0)){
56138 alt.push( "x-grid-row-alt");
56141 alt.push(" x-grid-dirty-row");
56144 if(this.getRowClass){
56145 alt.push( this.getRowClass(r, rowIndex));
56151 rowIndex : rowIndex,
56154 this.grid.fireEvent('rowclass', this, rowcfg);
56155 alt.push(rowcfg.rowClass);
56158 rp.alt = alt.join(" ");
56159 rp.cells = lcb.join("");
56160 lbuf[lbuf.length] = rt.apply(rp);
56161 rp.cells = cb.join("");
56162 buf[buf.length] = rt.apply(rp);
56164 return [lbuf.join(""), buf.join("")];
56167 renderBody : function(){
56168 var markup = this.renderRows();
56169 var bt = this.templates.body;
56170 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56174 * Refreshes the grid
56175 * @param {Boolean} headersToo
56177 refresh : function(headersToo){
56178 this.fireEvent("beforerefresh", this);
56179 this.grid.stopEditing();
56180 var result = this.renderBody();
56181 this.lockedBody.update(result[0]);
56182 this.mainBody.update(result[1]);
56183 if(headersToo === true){
56184 this.updateHeaders();
56185 this.updateColumns();
56186 this.updateSplitters();
56187 this.updateHeaderSortState();
56189 this.syncRowHeights();
56191 this.fireEvent("refresh", this);
56194 handleColumnMove : function(cm, oldIndex, newIndex){
56195 this.indexMap = null;
56196 var s = this.getScrollState();
56197 this.refresh(true);
56198 this.restoreScroll(s);
56199 this.afterMove(newIndex);
56202 afterMove : function(colIndex){
56203 if(this.enableMoveAnim && Roo.enableFx){
56204 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56206 // if multisort - fix sortOrder, and reload..
56207 if (this.grid.dataSource.multiSort) {
56208 // the we can call sort again..
56209 var dm = this.grid.dataSource;
56210 var cm = this.grid.colModel;
56212 for(var i = 0; i < cm.config.length; i++ ) {
56214 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56215 continue; // dont' bother, it's not in sort list or being set.
56218 so.push(cm.config[i].dataIndex);
56221 dm.load(dm.lastOptions);
56228 updateCell : function(dm, rowIndex, dataIndex){
56229 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56230 if(typeof colIndex == "undefined"){ // not present in grid
56233 var cm = this.grid.colModel;
56234 var cell = this.getCell(rowIndex, colIndex);
56235 var cellText = this.getCellText(rowIndex, colIndex);
56238 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56239 id : cm.getColumnId(colIndex),
56240 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56242 var renderer = cm.getRenderer(colIndex);
56243 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56244 if(typeof val == "undefined" || val === "") {
56247 cellText.innerHTML = val;
56248 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56249 this.syncRowHeights(rowIndex, rowIndex);
56252 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56254 if(this.grid.autoSizeHeaders){
56255 var h = this.getHeaderCellMeasure(colIndex);
56256 maxWidth = Math.max(maxWidth, h.scrollWidth);
56259 if(this.cm.isLocked(colIndex)){
56260 tb = this.getLockedTable();
56263 tb = this.getBodyTable();
56264 index = colIndex - this.cm.getLockedCount();
56267 var rows = tb.rows;
56268 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56269 for(var i = 0; i < stopIndex; i++){
56270 var cell = rows[i].childNodes[index].firstChild;
56271 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56274 return maxWidth + /*margin for error in IE*/ 5;
56277 * Autofit a column to its content.
56278 * @param {Number} colIndex
56279 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56281 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56282 if(this.cm.isHidden(colIndex)){
56283 return; // can't calc a hidden column
56286 var cid = this.cm.getColumnId(colIndex);
56287 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56288 if(this.grid.autoSizeHeaders){
56289 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56292 var newWidth = this.calcColumnWidth(colIndex);
56293 this.cm.setColumnWidth(colIndex,
56294 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56295 if(!suppressEvent){
56296 this.grid.fireEvent("columnresize", colIndex, newWidth);
56301 * Autofits all columns to their content and then expands to fit any extra space in the grid
56303 autoSizeColumns : function(){
56304 var cm = this.grid.colModel;
56305 var colCount = cm.getColumnCount();
56306 for(var i = 0; i < colCount; i++){
56307 this.autoSizeColumn(i, true, true);
56309 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56312 this.updateColumns();
56318 * Autofits all columns to the grid's width proportionate with their current size
56319 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56321 fitColumns : function(reserveScrollSpace){
56322 var cm = this.grid.colModel;
56323 var colCount = cm.getColumnCount();
56327 for (i = 0; i < colCount; i++){
56328 if(!cm.isHidden(i) && !cm.isFixed(i)){
56329 w = cm.getColumnWidth(i);
56335 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56336 if(reserveScrollSpace){
56339 var frac = (avail - cm.getTotalWidth())/width;
56340 while (cols.length){
56343 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56345 this.updateColumns();
56349 onRowSelect : function(rowIndex){
56350 var row = this.getRowComposite(rowIndex);
56351 row.addClass("x-grid-row-selected");
56354 onRowDeselect : function(rowIndex){
56355 var row = this.getRowComposite(rowIndex);
56356 row.removeClass("x-grid-row-selected");
56359 onCellSelect : function(row, col){
56360 var cell = this.getCell(row, col);
56362 Roo.fly(cell).addClass("x-grid-cell-selected");
56366 onCellDeselect : function(row, col){
56367 var cell = this.getCell(row, col);
56369 Roo.fly(cell).removeClass("x-grid-cell-selected");
56373 updateHeaderSortState : function(){
56375 // sort state can be single { field: xxx, direction : yyy}
56376 // or { xxx=>ASC , yyy : DESC ..... }
56379 if (!this.ds.multiSort) {
56380 var state = this.ds.getSortState();
56384 mstate[state.field] = state.direction;
56385 // FIXME... - this is not used here.. but might be elsewhere..
56386 this.sortState = state;
56389 mstate = this.ds.sortToggle;
56391 //remove existing sort classes..
56393 var sc = this.sortClasses;
56394 var hds = this.el.select(this.headerSelector).removeClass(sc);
56396 for(var f in mstate) {
56398 var sortColumn = this.cm.findColumnIndex(f);
56400 if(sortColumn != -1){
56401 var sortDir = mstate[f];
56402 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56411 handleHeaderClick : function(g, index,e){
56413 Roo.log("header click");
56416 // touch events on header are handled by context
56417 this.handleHdCtx(g,index,e);
56422 if(this.headersDisabled){
56425 var dm = g.dataSource, cm = g.colModel;
56426 if(!cm.isSortable(index)){
56431 if (dm.multiSort) {
56432 // update the sortOrder
56434 for(var i = 0; i < cm.config.length; i++ ) {
56436 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56437 continue; // dont' bother, it's not in sort list or being set.
56440 so.push(cm.config[i].dataIndex);
56446 dm.sort(cm.getDataIndex(index));
56450 destroy : function(){
56452 this.colMenu.removeAll();
56453 Roo.menu.MenuMgr.unregister(this.colMenu);
56454 this.colMenu.getEl().remove();
56455 delete this.colMenu;
56458 this.hmenu.removeAll();
56459 Roo.menu.MenuMgr.unregister(this.hmenu);
56460 this.hmenu.getEl().remove();
56463 if(this.grid.enableColumnMove){
56464 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56466 for(var dd in dds){
56467 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56468 var elid = dds[dd].dragElId;
56470 Roo.get(elid).remove();
56471 } else if(dds[dd].config.isTarget){
56472 dds[dd].proxyTop.remove();
56473 dds[dd].proxyBottom.remove();
56476 if(Roo.dd.DDM.locationCache[dd]){
56477 delete Roo.dd.DDM.locationCache[dd];
56480 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56483 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56484 this.bind(null, null);
56485 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56488 handleLockChange : function(){
56489 this.refresh(true);
56492 onDenyColumnLock : function(){
56496 onDenyColumnHide : function(){
56500 handleHdMenuClick : function(item){
56501 var index = this.hdCtxIndex;
56502 var cm = this.cm, ds = this.ds;
56505 ds.sort(cm.getDataIndex(index), "ASC");
56508 ds.sort(cm.getDataIndex(index), "DESC");
56511 var lc = cm.getLockedCount();
56512 if(cm.getColumnCount(true) <= lc+1){
56513 this.onDenyColumnLock();
56517 cm.setLocked(index, true, true);
56518 cm.moveColumn(index, lc);
56519 this.grid.fireEvent("columnmove", index, lc);
56521 cm.setLocked(index, true);
56525 var lc = cm.getLockedCount();
56526 if((lc-1) != index){
56527 cm.setLocked(index, false, true);
56528 cm.moveColumn(index, lc-1);
56529 this.grid.fireEvent("columnmove", index, lc-1);
56531 cm.setLocked(index, false);
56534 case 'wider': // used to expand cols on touch..
56536 var cw = cm.getColumnWidth(index);
56537 cw += (item.id == 'wider' ? 1 : -1) * 50;
56538 cw = Math.max(0, cw);
56539 cw = Math.min(cw,4000);
56540 cm.setColumnWidth(index, cw);
56544 index = cm.getIndexById(item.id.substr(4));
56546 if(item.checked && cm.getColumnCount(true) <= 1){
56547 this.onDenyColumnHide();
56550 cm.setHidden(index, item.checked);
56556 beforeColMenuShow : function(){
56557 var cm = this.cm, colCount = cm.getColumnCount();
56558 this.colMenu.removeAll();
56559 for(var i = 0; i < colCount; i++){
56560 this.colMenu.add(new Roo.menu.CheckItem({
56561 id: "col-"+cm.getColumnId(i),
56562 text: cm.getColumnHeader(i),
56563 checked: !cm.isHidden(i),
56569 handleHdCtx : function(g, index, e){
56571 var hd = this.getHeaderCell(index);
56572 this.hdCtxIndex = index;
56573 var ms = this.hmenu.items, cm = this.cm;
56574 ms.get("asc").setDisabled(!cm.isSortable(index));
56575 ms.get("desc").setDisabled(!cm.isSortable(index));
56576 if(this.grid.enableColLock !== false){
56577 ms.get("lock").setDisabled(cm.isLocked(index));
56578 ms.get("unlock").setDisabled(!cm.isLocked(index));
56580 this.hmenu.show(hd, "tl-bl");
56583 handleHdOver : function(e){
56584 var hd = this.findHeaderCell(e.getTarget());
56585 if(hd && !this.headersDisabled){
56586 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56587 this.fly(hd).addClass("x-grid-hd-over");
56592 handleHdOut : function(e){
56593 var hd = this.findHeaderCell(e.getTarget());
56595 this.fly(hd).removeClass("x-grid-hd-over");
56599 handleSplitDblClick : function(e, t){
56600 var i = this.getCellIndex(t);
56601 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56602 this.autoSizeColumn(i, true);
56607 render : function(){
56610 var colCount = cm.getColumnCount();
56612 if(this.grid.monitorWindowResize === true){
56613 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56615 var header = this.renderHeaders();
56616 var body = this.templates.body.apply({rows:""});
56617 var html = this.templates.master.apply({
56620 lockedHeader: header[0],
56624 //this.updateColumns();
56626 this.grid.getGridEl().dom.innerHTML = html;
56628 this.initElements();
56630 // a kludge to fix the random scolling effect in webkit
56631 this.el.on("scroll", function() {
56632 this.el.dom.scrollTop=0; // hopefully not recursive..
56635 this.scroller.on("scroll", this.handleScroll, this);
56636 this.lockedBody.on("mousewheel", this.handleWheel, this);
56637 this.mainBody.on("mousewheel", this.handleWheel, this);
56639 this.mainHd.on("mouseover", this.handleHdOver, this);
56640 this.mainHd.on("mouseout", this.handleHdOut, this);
56641 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56642 {delegate: "."+this.splitClass});
56644 this.lockedHd.on("mouseover", this.handleHdOver, this);
56645 this.lockedHd.on("mouseout", this.handleHdOut, this);
56646 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56647 {delegate: "."+this.splitClass});
56649 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56650 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56653 this.updateSplitters();
56655 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56656 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56657 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56660 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56661 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56663 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56664 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56666 if(this.grid.enableColLock !== false){
56667 this.hmenu.add('-',
56668 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56669 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56673 this.hmenu.add('-',
56674 {id:"wider", text: this.columnsWiderText},
56675 {id:"narrow", text: this.columnsNarrowText }
56681 if(this.grid.enableColumnHide !== false){
56683 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56684 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56685 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56687 this.hmenu.add('-',
56688 {id:"columns", text: this.columnsText, menu: this.colMenu}
56691 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56693 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56696 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56697 this.dd = new Roo.grid.GridDragZone(this.grid, {
56698 ddGroup : this.grid.ddGroup || 'GridDD'
56704 for(var i = 0; i < colCount; i++){
56705 if(cm.isHidden(i)){
56706 this.hideColumn(i);
56708 if(cm.config[i].align){
56709 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56710 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56714 this.updateHeaderSortState();
56716 this.beforeInitialResize();
56719 // two part rendering gives faster view to the user
56720 this.renderPhase2.defer(1, this);
56723 renderPhase2 : function(){
56724 // render the rows now
56726 if(this.grid.autoSizeColumns){
56727 this.autoSizeColumns();
56731 beforeInitialResize : function(){
56735 onColumnSplitterMoved : function(i, w){
56736 this.userResized = true;
56737 var cm = this.grid.colModel;
56738 cm.setColumnWidth(i, w, true);
56739 var cid = cm.getColumnId(i);
56740 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56741 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56742 this.updateSplitters();
56744 this.grid.fireEvent("columnresize", i, w);
56747 syncRowHeights : function(startIndex, endIndex){
56748 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56749 startIndex = startIndex || 0;
56750 var mrows = this.getBodyTable().rows;
56751 var lrows = this.getLockedTable().rows;
56752 var len = mrows.length-1;
56753 endIndex = Math.min(endIndex || len, len);
56754 for(var i = startIndex; i <= endIndex; i++){
56755 var m = mrows[i], l = lrows[i];
56756 var h = Math.max(m.offsetHeight, l.offsetHeight);
56757 m.style.height = l.style.height = h + "px";
56762 layout : function(initialRender, is2ndPass){
56764 var auto = g.autoHeight;
56765 var scrollOffset = 16;
56766 var c = g.getGridEl(), cm = this.cm,
56767 expandCol = g.autoExpandColumn,
56769 //c.beginMeasure();
56771 if(!c.dom.offsetWidth){ // display:none?
56773 this.lockedWrap.show();
56774 this.mainWrap.show();
56779 var hasLock = this.cm.isLocked(0);
56781 var tbh = this.headerPanel.getHeight();
56782 var bbh = this.footerPanel.getHeight();
56785 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56786 var newHeight = ch + c.getBorderWidth("tb");
56788 newHeight = Math.min(g.maxHeight, newHeight);
56790 c.setHeight(newHeight);
56794 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56797 var s = this.scroller;
56799 var csize = c.getSize(true);
56801 this.el.setSize(csize.width, csize.height);
56803 this.headerPanel.setWidth(csize.width);
56804 this.footerPanel.setWidth(csize.width);
56806 var hdHeight = this.mainHd.getHeight();
56807 var vw = csize.width;
56808 var vh = csize.height - (tbh + bbh);
56812 var bt = this.getBodyTable();
56814 if(cm.getLockedCount() == cm.config.length){
56815 bt = this.getLockedTable();
56818 var ltWidth = hasLock ?
56819 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56821 var scrollHeight = bt.offsetHeight;
56822 var scrollWidth = ltWidth + bt.offsetWidth;
56823 var vscroll = false, hscroll = false;
56825 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56827 var lw = this.lockedWrap, mw = this.mainWrap;
56828 var lb = this.lockedBody, mb = this.mainBody;
56830 setTimeout(function(){
56831 var t = s.dom.offsetTop;
56832 var w = s.dom.clientWidth,
56833 h = s.dom.clientHeight;
56836 lw.setSize(ltWidth, h);
56838 mw.setLeftTop(ltWidth, t);
56839 mw.setSize(w-ltWidth, h);
56841 lb.setHeight(h-hdHeight);
56842 mb.setHeight(h-hdHeight);
56844 if(is2ndPass !== true && !gv.userResized && expandCol){
56845 // high speed resize without full column calculation
56847 var ci = cm.getIndexById(expandCol);
56849 ci = cm.findColumnIndex(expandCol);
56851 ci = Math.max(0, ci); // make sure it's got at least the first col.
56852 var expandId = cm.getColumnId(ci);
56853 var tw = cm.getTotalWidth(false);
56854 var currentWidth = cm.getColumnWidth(ci);
56855 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56856 if(currentWidth != cw){
56857 cm.setColumnWidth(ci, cw, true);
56858 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56859 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56860 gv.updateSplitters();
56861 gv.layout(false, true);
56873 onWindowResize : function(){
56874 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56880 appendFooter : function(parentEl){
56884 sortAscText : "Sort Ascending",
56885 sortDescText : "Sort Descending",
56886 lockText : "Lock Column",
56887 unlockText : "Unlock Column",
56888 columnsText : "Columns",
56890 columnsWiderText : "Wider",
56891 columnsNarrowText : "Thinner"
56895 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56896 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56897 this.proxy.el.addClass('x-grid3-col-dd');
56900 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56901 handleMouseDown : function(e){
56905 callHandleMouseDown : function(e){
56906 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56911 * Ext JS Library 1.1.1
56912 * Copyright(c) 2006-2007, Ext JS, LLC.
56914 * Originally Released Under LGPL - original licence link has changed is not relivant.
56917 * <script type="text/javascript">
56921 // This is a support class used internally by the Grid components
56922 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56924 this.view = grid.getView();
56925 this.proxy = this.view.resizeProxy;
56926 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56927 "gridSplitters" + this.grid.getGridEl().id, {
56928 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56930 this.setHandleElId(Roo.id(hd));
56931 this.setOuterHandleElId(Roo.id(hd2));
56932 this.scroll = false;
56934 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56935 fly: Roo.Element.fly,
56937 b4StartDrag : function(x, y){
56938 this.view.headersDisabled = true;
56939 this.proxy.setHeight(this.view.mainWrap.getHeight());
56940 var w = this.cm.getColumnWidth(this.cellIndex);
56941 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56942 this.resetConstraints();
56943 this.setXConstraint(minw, 1000);
56944 this.setYConstraint(0, 0);
56945 this.minX = x - minw;
56946 this.maxX = x + 1000;
56948 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56952 handleMouseDown : function(e){
56953 ev = Roo.EventObject.setEvent(e);
56954 var t = this.fly(ev.getTarget());
56955 if(t.hasClass("x-grid-split")){
56956 this.cellIndex = this.view.getCellIndex(t.dom);
56957 this.split = t.dom;
56958 this.cm = this.grid.colModel;
56959 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56960 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56965 endDrag : function(e){
56966 this.view.headersDisabled = false;
56967 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56968 var diff = endX - this.startPos;
56969 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56972 autoOffset : function(){
56973 this.setDelta(0,0);
56977 * Ext JS Library 1.1.1
56978 * Copyright(c) 2006-2007, Ext JS, LLC.
56980 * Originally Released Under LGPL - original licence link has changed is not relivant.
56983 * <script type="text/javascript">
56987 // This is a support class used internally by the Grid components
56988 Roo.grid.GridDragZone = function(grid, config){
56989 this.view = grid.getView();
56990 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56991 if(this.view.lockedBody){
56992 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56993 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56995 this.scroll = false;
56997 this.ddel = document.createElement('div');
56998 this.ddel.className = 'x-grid-dd-wrap';
57001 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
57002 ddGroup : "GridDD",
57004 getDragData : function(e){
57005 var t = Roo.lib.Event.getTarget(e);
57006 var rowIndex = this.view.findRowIndex(t);
57007 var sm = this.grid.selModel;
57009 //Roo.log(rowIndex);
57011 if (sm.getSelectedCell) {
57012 // cell selection..
57013 if (!sm.getSelectedCell()) {
57016 if (rowIndex != sm.getSelectedCell()[0]) {
57022 if(rowIndex !== false){
57027 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
57029 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
57032 if (e.hasModifier()){
57033 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
57036 Roo.log("getDragData");
57041 rowIndex: rowIndex,
57042 selections:sm.getSelections ? sm.getSelections() : (
57043 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
57050 onInitDrag : function(e){
57051 var data = this.dragData;
57052 this.ddel.innerHTML = this.grid.getDragDropText();
57053 this.proxy.update(this.ddel);
57054 // fire start drag?
57057 afterRepair : function(){
57058 this.dragging = false;
57061 getRepairXY : function(e, data){
57065 onEndDrag : function(data, e){
57069 onValidDrop : function(dd, e, id){
57074 beforeInvalidDrop : function(e, id){
57079 * Ext JS Library 1.1.1
57080 * Copyright(c) 2006-2007, Ext JS, LLC.
57082 * Originally Released Under LGPL - original licence link has changed is not relivant.
57085 * <script type="text/javascript">
57090 * @class Roo.grid.ColumnModel
57091 * @extends Roo.util.Observable
57092 * This is the default implementation of a ColumnModel used by the Grid. It defines
57093 * the columns in the grid.
57096 var colModel = new Roo.grid.ColumnModel([
57097 {header: "Ticker", width: 60, sortable: true, locked: true},
57098 {header: "Company Name", width: 150, sortable: true},
57099 {header: "Market Cap.", width: 100, sortable: true},
57100 {header: "$ Sales", width: 100, sortable: true, renderer: money},
57101 {header: "Employees", width: 100, sortable: true, resizable: false}
57106 * The config options listed for this class are options which may appear in each
57107 * individual column definition.
57108 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
57110 * @param {Object} config An Array of column config objects. See this class's
57111 * config objects for details.
57113 Roo.grid.ColumnModel = function(config){
57115 * The config passed into the constructor
57117 this.config = config;
57120 // if no id, create one
57121 // if the column does not have a dataIndex mapping,
57122 // map it to the order it is in the config
57123 for(var i = 0, len = config.length; i < len; i++){
57125 if(typeof c.dataIndex == "undefined"){
57128 if(typeof c.renderer == "string"){
57129 c.renderer = Roo.util.Format[c.renderer];
57131 if(typeof c.id == "undefined"){
57134 if(c.editor && c.editor.xtype){
57135 c.editor = Roo.factory(c.editor, Roo.grid);
57137 if(c.editor && c.editor.isFormField){
57138 c.editor = new Roo.grid.GridEditor(c.editor);
57140 this.lookup[c.id] = c;
57144 * The width of columns which have no width specified (defaults to 100)
57147 this.defaultWidth = 100;
57150 * Default sortable of columns which have no sortable specified (defaults to false)
57153 this.defaultSortable = false;
57157 * @event widthchange
57158 * Fires when the width of a column changes.
57159 * @param {ColumnModel} this
57160 * @param {Number} columnIndex The column index
57161 * @param {Number} newWidth The new width
57163 "widthchange": true,
57165 * @event headerchange
57166 * Fires when the text of a header changes.
57167 * @param {ColumnModel} this
57168 * @param {Number} columnIndex The column index
57169 * @param {Number} newText The new header text
57171 "headerchange": true,
57173 * @event hiddenchange
57174 * Fires when a column is hidden or "unhidden".
57175 * @param {ColumnModel} this
57176 * @param {Number} columnIndex The column index
57177 * @param {Boolean} hidden true if hidden, false otherwise
57179 "hiddenchange": true,
57181 * @event columnmoved
57182 * Fires when a column is moved.
57183 * @param {ColumnModel} this
57184 * @param {Number} oldIndex
57185 * @param {Number} newIndex
57187 "columnmoved" : true,
57189 * @event columlockchange
57190 * Fires when a column's locked state is changed
57191 * @param {ColumnModel} this
57192 * @param {Number} colIndex
57193 * @param {Boolean} locked true if locked
57195 "columnlockchange" : true
57197 Roo.grid.ColumnModel.superclass.constructor.call(this);
57199 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57201 * @cfg {String} header The header text to display in the Grid view.
57204 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57205 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57206 * specified, the column's index is used as an index into the Record's data Array.
57209 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57210 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57213 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57214 * Defaults to the value of the {@link #defaultSortable} property.
57215 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57218 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57221 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57224 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57227 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57230 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57231 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57232 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57233 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57236 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57239 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57242 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
57245 * @cfg {String} cursor (Optional)
57248 * @cfg {String} tooltip (Optional)
57251 * @cfg {Number} xs (Optional)
57254 * @cfg {Number} sm (Optional)
57257 * @cfg {Number} md (Optional)
57260 * @cfg {Number} lg (Optional)
57263 * Returns the id of the column at the specified index.
57264 * @param {Number} index The column index
57265 * @return {String} the id
57267 getColumnId : function(index){
57268 return this.config[index].id;
57272 * Returns the column for a specified id.
57273 * @param {String} id The column id
57274 * @return {Object} the column
57276 getColumnById : function(id){
57277 return this.lookup[id];
57282 * Returns the column for a specified dataIndex.
57283 * @param {String} dataIndex The column dataIndex
57284 * @return {Object|Boolean} the column or false if not found
57286 getColumnByDataIndex: function(dataIndex){
57287 var index = this.findColumnIndex(dataIndex);
57288 return index > -1 ? this.config[index] : false;
57292 * Returns the index for a specified column id.
57293 * @param {String} id The column id
57294 * @return {Number} the index, or -1 if not found
57296 getIndexById : function(id){
57297 for(var i = 0, len = this.config.length; i < len; i++){
57298 if(this.config[i].id == id){
57306 * Returns the index for a specified column dataIndex.
57307 * @param {String} dataIndex The column dataIndex
57308 * @return {Number} the index, or -1 if not found
57311 findColumnIndex : function(dataIndex){
57312 for(var i = 0, len = this.config.length; i < len; i++){
57313 if(this.config[i].dataIndex == dataIndex){
57321 moveColumn : function(oldIndex, newIndex){
57322 var c = this.config[oldIndex];
57323 this.config.splice(oldIndex, 1);
57324 this.config.splice(newIndex, 0, c);
57325 this.dataMap = null;
57326 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57329 isLocked : function(colIndex){
57330 return this.config[colIndex].locked === true;
57333 setLocked : function(colIndex, value, suppressEvent){
57334 if(this.isLocked(colIndex) == value){
57337 this.config[colIndex].locked = value;
57338 if(!suppressEvent){
57339 this.fireEvent("columnlockchange", this, colIndex, value);
57343 getTotalLockedWidth : function(){
57344 var totalWidth = 0;
57345 for(var i = 0; i < this.config.length; i++){
57346 if(this.isLocked(i) && !this.isHidden(i)){
57347 this.totalWidth += this.getColumnWidth(i);
57353 getLockedCount : function(){
57354 for(var i = 0, len = this.config.length; i < len; i++){
57355 if(!this.isLocked(i)){
57360 return this.config.length;
57364 * Returns the number of columns.
57367 getColumnCount : function(visibleOnly){
57368 if(visibleOnly === true){
57370 for(var i = 0, len = this.config.length; i < len; i++){
57371 if(!this.isHidden(i)){
57377 return this.config.length;
57381 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57382 * @param {Function} fn
57383 * @param {Object} scope (optional)
57384 * @return {Array} result
57386 getColumnsBy : function(fn, scope){
57388 for(var i = 0, len = this.config.length; i < len; i++){
57389 var c = this.config[i];
57390 if(fn.call(scope||this, c, i) === true){
57398 * Returns true if the specified column is sortable.
57399 * @param {Number} col The column index
57400 * @return {Boolean}
57402 isSortable : function(col){
57403 if(typeof this.config[col].sortable == "undefined"){
57404 return this.defaultSortable;
57406 return this.config[col].sortable;
57410 * Returns the rendering (formatting) function defined for the column.
57411 * @param {Number} col The column index.
57412 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57414 getRenderer : function(col){
57415 if(!this.config[col].renderer){
57416 return Roo.grid.ColumnModel.defaultRenderer;
57418 return this.config[col].renderer;
57422 * Sets the rendering (formatting) function for a column.
57423 * @param {Number} col The column index
57424 * @param {Function} fn The function to use to process the cell's raw data
57425 * to return HTML markup for the grid view. The render function is called with
57426 * the following parameters:<ul>
57427 * <li>Data value.</li>
57428 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57429 * <li>css A CSS style string to apply to the table cell.</li>
57430 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57431 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57432 * <li>Row index</li>
57433 * <li>Column index</li>
57434 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57436 setRenderer : function(col, fn){
57437 this.config[col].renderer = fn;
57441 * Returns the width for the specified column.
57442 * @param {Number} col The column index
57445 getColumnWidth : function(col){
57446 return this.config[col].width * 1 || this.defaultWidth;
57450 * Sets the width for a column.
57451 * @param {Number} col The column index
57452 * @param {Number} width The new width
57454 setColumnWidth : function(col, width, suppressEvent){
57455 this.config[col].width = width;
57456 this.totalWidth = null;
57457 if(!suppressEvent){
57458 this.fireEvent("widthchange", this, col, width);
57463 * Returns the total width of all columns.
57464 * @param {Boolean} includeHidden True to include hidden column widths
57467 getTotalWidth : function(includeHidden){
57468 if(!this.totalWidth){
57469 this.totalWidth = 0;
57470 for(var i = 0, len = this.config.length; i < len; i++){
57471 if(includeHidden || !this.isHidden(i)){
57472 this.totalWidth += this.getColumnWidth(i);
57476 return this.totalWidth;
57480 * Returns the header for the specified column.
57481 * @param {Number} col The column index
57484 getColumnHeader : function(col){
57485 return this.config[col].header;
57489 * Sets the header for a column.
57490 * @param {Number} col The column index
57491 * @param {String} header The new header
57493 setColumnHeader : function(col, header){
57494 this.config[col].header = header;
57495 this.fireEvent("headerchange", this, col, header);
57499 * Returns the tooltip for the specified column.
57500 * @param {Number} col The column index
57503 getColumnTooltip : function(col){
57504 return this.config[col].tooltip;
57507 * Sets the tooltip for a column.
57508 * @param {Number} col The column index
57509 * @param {String} tooltip The new tooltip
57511 setColumnTooltip : function(col, tooltip){
57512 this.config[col].tooltip = tooltip;
57516 * Returns the dataIndex for the specified column.
57517 * @param {Number} col The column index
57520 getDataIndex : function(col){
57521 return this.config[col].dataIndex;
57525 * Sets the dataIndex for a column.
57526 * @param {Number} col The column index
57527 * @param {Number} dataIndex The new dataIndex
57529 setDataIndex : function(col, dataIndex){
57530 this.config[col].dataIndex = dataIndex;
57536 * Returns true if the cell is editable.
57537 * @param {Number} colIndex The column index
57538 * @param {Number} rowIndex The row index - this is nto actually used..?
57539 * @return {Boolean}
57541 isCellEditable : function(colIndex, rowIndex){
57542 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57546 * Returns the editor defined for the cell/column.
57547 * return false or null to disable editing.
57548 * @param {Number} colIndex The column index
57549 * @param {Number} rowIndex The row index
57552 getCellEditor : function(colIndex, rowIndex){
57553 return this.config[colIndex].editor;
57557 * Sets if a column is editable.
57558 * @param {Number} col The column index
57559 * @param {Boolean} editable True if the column is editable
57561 setEditable : function(col, editable){
57562 this.config[col].editable = editable;
57567 * Returns true if the column is hidden.
57568 * @param {Number} colIndex The column index
57569 * @return {Boolean}
57571 isHidden : function(colIndex){
57572 return this.config[colIndex].hidden;
57577 * Returns true if the column width cannot be changed
57579 isFixed : function(colIndex){
57580 return this.config[colIndex].fixed;
57584 * Returns true if the column can be resized
57585 * @return {Boolean}
57587 isResizable : function(colIndex){
57588 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57591 * Sets if a column is hidden.
57592 * @param {Number} colIndex The column index
57593 * @param {Boolean} hidden True if the column is hidden
57595 setHidden : function(colIndex, hidden){
57596 this.config[colIndex].hidden = hidden;
57597 this.totalWidth = null;
57598 this.fireEvent("hiddenchange", this, colIndex, hidden);
57602 * Sets the editor for a column.
57603 * @param {Number} col The column index
57604 * @param {Object} editor The editor object
57606 setEditor : function(col, editor){
57607 this.config[col].editor = editor;
57611 Roo.grid.ColumnModel.defaultRenderer = function(value)
57613 if(typeof value == "object") {
57616 if(typeof value == "string" && value.length < 1){
57620 return String.format("{0}", value);
57623 // Alias for backwards compatibility
57624 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57627 * Ext JS Library 1.1.1
57628 * Copyright(c) 2006-2007, Ext JS, LLC.
57630 * Originally Released Under LGPL - original licence link has changed is not relivant.
57633 * <script type="text/javascript">
57637 * @class Roo.grid.AbstractSelectionModel
57638 * @extends Roo.util.Observable
57639 * Abstract base class for grid SelectionModels. It provides the interface that should be
57640 * implemented by descendant classes. This class should not be directly instantiated.
57643 Roo.grid.AbstractSelectionModel = function(){
57644 this.locked = false;
57645 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57648 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57649 /** @ignore Called by the grid automatically. Do not call directly. */
57650 init : function(grid){
57656 * Locks the selections.
57659 this.locked = true;
57663 * Unlocks the selections.
57665 unlock : function(){
57666 this.locked = false;
57670 * Returns true if the selections are locked.
57671 * @return {Boolean}
57673 isLocked : function(){
57674 return this.locked;
57678 * Ext JS Library 1.1.1
57679 * Copyright(c) 2006-2007, Ext JS, LLC.
57681 * Originally Released Under LGPL - original licence link has changed is not relivant.
57684 * <script type="text/javascript">
57687 * @extends Roo.grid.AbstractSelectionModel
57688 * @class Roo.grid.RowSelectionModel
57689 * The default SelectionModel used by {@link Roo.grid.Grid}.
57690 * It supports multiple selections and keyboard selection/navigation.
57692 * @param {Object} config
57694 Roo.grid.RowSelectionModel = function(config){
57695 Roo.apply(this, config);
57696 this.selections = new Roo.util.MixedCollection(false, function(o){
57701 this.lastActive = false;
57705 * @event selectionchange
57706 * Fires when the selection changes
57707 * @param {SelectionModel} this
57709 "selectionchange" : true,
57711 * @event afterselectionchange
57712 * Fires after the selection changes (eg. by key press or clicking)
57713 * @param {SelectionModel} this
57715 "afterselectionchange" : true,
57717 * @event beforerowselect
57718 * Fires when a row is selected being selected, return false to cancel.
57719 * @param {SelectionModel} this
57720 * @param {Number} rowIndex The selected index
57721 * @param {Boolean} keepExisting False if other selections will be cleared
57723 "beforerowselect" : true,
57726 * Fires when a row is selected.
57727 * @param {SelectionModel} this
57728 * @param {Number} rowIndex The selected index
57729 * @param {Roo.data.Record} r The record
57731 "rowselect" : true,
57733 * @event rowdeselect
57734 * Fires when a row is deselected.
57735 * @param {SelectionModel} this
57736 * @param {Number} rowIndex The selected index
57738 "rowdeselect" : true
57740 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57741 this.locked = false;
57744 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57746 * @cfg {Boolean} singleSelect
57747 * True to allow selection of only one row at a time (defaults to false)
57749 singleSelect : false,
57752 initEvents : function(){
57754 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57755 this.grid.on("mousedown", this.handleMouseDown, this);
57756 }else{ // allow click to work like normal
57757 this.grid.on("rowclick", this.handleDragableRowClick, this);
57760 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57761 "up" : function(e){
57763 this.selectPrevious(e.shiftKey);
57764 }else if(this.last !== false && this.lastActive !== false){
57765 var last = this.last;
57766 this.selectRange(this.last, this.lastActive-1);
57767 this.grid.getView().focusRow(this.lastActive);
57768 if(last !== false){
57772 this.selectFirstRow();
57774 this.fireEvent("afterselectionchange", this);
57776 "down" : function(e){
57778 this.selectNext(e.shiftKey);
57779 }else if(this.last !== false && this.lastActive !== false){
57780 var last = this.last;
57781 this.selectRange(this.last, this.lastActive+1);
57782 this.grid.getView().focusRow(this.lastActive);
57783 if(last !== false){
57787 this.selectFirstRow();
57789 this.fireEvent("afterselectionchange", this);
57794 var view = this.grid.view;
57795 view.on("refresh", this.onRefresh, this);
57796 view.on("rowupdated", this.onRowUpdated, this);
57797 view.on("rowremoved", this.onRemove, this);
57801 onRefresh : function(){
57802 var ds = this.grid.dataSource, i, v = this.grid.view;
57803 var s = this.selections;
57804 s.each(function(r){
57805 if((i = ds.indexOfId(r.id)) != -1){
57807 s.add(ds.getAt(i)); // updating the selection relate data
57815 onRemove : function(v, index, r){
57816 this.selections.remove(r);
57820 onRowUpdated : function(v, index, r){
57821 if(this.isSelected(r)){
57822 v.onRowSelect(index);
57828 * @param {Array} records The records to select
57829 * @param {Boolean} keepExisting (optional) True to keep existing selections
57831 selectRecords : function(records, keepExisting){
57833 this.clearSelections();
57835 var ds = this.grid.dataSource;
57836 for(var i = 0, len = records.length; i < len; i++){
57837 this.selectRow(ds.indexOf(records[i]), true);
57842 * Gets the number of selected rows.
57845 getCount : function(){
57846 return this.selections.length;
57850 * Selects the first row in the grid.
57852 selectFirstRow : function(){
57857 * Select the last row.
57858 * @param {Boolean} keepExisting (optional) True to keep existing selections
57860 selectLastRow : function(keepExisting){
57861 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57865 * Selects the row immediately following the last selected row.
57866 * @param {Boolean} keepExisting (optional) True to keep existing selections
57868 selectNext : function(keepExisting){
57869 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57870 this.selectRow(this.last+1, keepExisting);
57871 this.grid.getView().focusRow(this.last);
57876 * Selects the row that precedes the last selected row.
57877 * @param {Boolean} keepExisting (optional) True to keep existing selections
57879 selectPrevious : function(keepExisting){
57881 this.selectRow(this.last-1, keepExisting);
57882 this.grid.getView().focusRow(this.last);
57887 * Returns the selected records
57888 * @return {Array} Array of selected records
57890 getSelections : function(){
57891 return [].concat(this.selections.items);
57895 * Returns the first selected record.
57898 getSelected : function(){
57899 return this.selections.itemAt(0);
57904 * Clears all selections.
57906 clearSelections : function(fast){
57911 var ds = this.grid.dataSource;
57912 var s = this.selections;
57913 s.each(function(r){
57914 this.deselectRow(ds.indexOfId(r.id));
57918 this.selections.clear();
57925 * Selects all rows.
57927 selectAll : function(){
57931 this.selections.clear();
57932 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57933 this.selectRow(i, true);
57938 * Returns True if there is a selection.
57939 * @return {Boolean}
57941 hasSelection : function(){
57942 return this.selections.length > 0;
57946 * Returns True if the specified row is selected.
57947 * @param {Number/Record} record The record or index of the record to check
57948 * @return {Boolean}
57950 isSelected : function(index){
57951 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57952 return (r && this.selections.key(r.id) ? true : false);
57956 * Returns True if the specified record id is selected.
57957 * @param {String} id The id of record to check
57958 * @return {Boolean}
57960 isIdSelected : function(id){
57961 return (this.selections.key(id) ? true : false);
57965 handleMouseDown : function(e, t){
57966 var view = this.grid.getView(), rowIndex;
57967 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57970 if(e.shiftKey && this.last !== false){
57971 var last = this.last;
57972 this.selectRange(last, rowIndex, e.ctrlKey);
57973 this.last = last; // reset the last
57974 view.focusRow(rowIndex);
57976 var isSelected = this.isSelected(rowIndex);
57977 if(e.button !== 0 && isSelected){
57978 view.focusRow(rowIndex);
57979 }else if(e.ctrlKey && isSelected){
57980 this.deselectRow(rowIndex);
57981 }else if(!isSelected){
57982 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57983 view.focusRow(rowIndex);
57986 this.fireEvent("afterselectionchange", this);
57989 handleDragableRowClick : function(grid, rowIndex, e)
57991 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57992 this.selectRow(rowIndex, false);
57993 grid.view.focusRow(rowIndex);
57994 this.fireEvent("afterselectionchange", this);
57999 * Selects multiple rows.
58000 * @param {Array} rows Array of the indexes of the row to select
58001 * @param {Boolean} keepExisting (optional) True to keep existing selections
58003 selectRows : function(rows, keepExisting){
58005 this.clearSelections();
58007 for(var i = 0, len = rows.length; i < len; i++){
58008 this.selectRow(rows[i], true);
58013 * Selects a range of rows. All rows in between startRow and endRow are also selected.
58014 * @param {Number} startRow The index of the first row in the range
58015 * @param {Number} endRow The index of the last row in the range
58016 * @param {Boolean} keepExisting (optional) True to retain existing selections
58018 selectRange : function(startRow, endRow, keepExisting){
58023 this.clearSelections();
58025 if(startRow <= endRow){
58026 for(var i = startRow; i <= endRow; i++){
58027 this.selectRow(i, true);
58030 for(var i = startRow; i >= endRow; i--){
58031 this.selectRow(i, true);
58037 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
58038 * @param {Number} startRow The index of the first row in the range
58039 * @param {Number} endRow The index of the last row in the range
58041 deselectRange : function(startRow, endRow, preventViewNotify){
58045 for(var i = startRow; i <= endRow; i++){
58046 this.deselectRow(i, preventViewNotify);
58052 * @param {Number} row The index of the row to select
58053 * @param {Boolean} keepExisting (optional) True to keep existing selections
58055 selectRow : function(index, keepExisting, preventViewNotify){
58056 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
58059 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
58060 if(!keepExisting || this.singleSelect){
58061 this.clearSelections();
58063 var r = this.grid.dataSource.getAt(index);
58064 this.selections.add(r);
58065 this.last = this.lastActive = index;
58066 if(!preventViewNotify){
58067 this.grid.getView().onRowSelect(index);
58069 this.fireEvent("rowselect", this, index, r);
58070 this.fireEvent("selectionchange", this);
58076 * @param {Number} row The index of the row to deselect
58078 deselectRow : function(index, preventViewNotify){
58082 if(this.last == index){
58085 if(this.lastActive == index){
58086 this.lastActive = false;
58088 var r = this.grid.dataSource.getAt(index);
58089 this.selections.remove(r);
58090 if(!preventViewNotify){
58091 this.grid.getView().onRowDeselect(index);
58093 this.fireEvent("rowdeselect", this, index);
58094 this.fireEvent("selectionchange", this);
58098 restoreLast : function(){
58100 this.last = this._last;
58105 acceptsNav : function(row, col, cm){
58106 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58110 onEditorKey : function(field, e){
58111 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
58116 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58118 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58120 }else if(k == e.ENTER && !e.ctrlKey){
58124 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
58126 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
58128 }else if(k == e.ESC){
58132 g.startEditing(newCell[0], newCell[1]);
58137 * Ext JS Library 1.1.1
58138 * Copyright(c) 2006-2007, Ext JS, LLC.
58140 * Originally Released Under LGPL - original licence link has changed is not relivant.
58143 * <script type="text/javascript">
58146 * @class Roo.grid.CellSelectionModel
58147 * @extends Roo.grid.AbstractSelectionModel
58148 * This class provides the basic implementation for cell selection in a grid.
58150 * @param {Object} config The object containing the configuration of this model.
58151 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58153 Roo.grid.CellSelectionModel = function(config){
58154 Roo.apply(this, config);
58156 this.selection = null;
58160 * @event beforerowselect
58161 * Fires before a cell is selected.
58162 * @param {SelectionModel} this
58163 * @param {Number} rowIndex The selected row index
58164 * @param {Number} colIndex The selected cell index
58166 "beforecellselect" : true,
58168 * @event cellselect
58169 * Fires when a cell is selected.
58170 * @param {SelectionModel} this
58171 * @param {Number} rowIndex The selected row index
58172 * @param {Number} colIndex The selected cell index
58174 "cellselect" : true,
58176 * @event selectionchange
58177 * Fires when the active selection changes.
58178 * @param {SelectionModel} this
58179 * @param {Object} selection null for no selection or an object (o) with two properties
58181 <li>o.record: the record object for the row the selection is in</li>
58182 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58185 "selectionchange" : true,
58188 * Fires when the tab (or enter) was pressed on the last editable cell
58189 * You can use this to trigger add new row.
58190 * @param {SelectionModel} this
58194 * @event beforeeditnext
58195 * Fires before the next editable sell is made active
58196 * You can use this to skip to another cell or fire the tabend
58197 * if you set cell to false
58198 * @param {Object} eventdata object : { cell : [ row, col ] }
58200 "beforeeditnext" : true
58202 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58205 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58207 enter_is_tab: false,
58210 initEvents : function(){
58211 this.grid.on("mousedown", this.handleMouseDown, this);
58212 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58213 var view = this.grid.view;
58214 view.on("refresh", this.onViewChange, this);
58215 view.on("rowupdated", this.onRowUpdated, this);
58216 view.on("beforerowremoved", this.clearSelections, this);
58217 view.on("beforerowsinserted", this.clearSelections, this);
58218 if(this.grid.isEditor){
58219 this.grid.on("beforeedit", this.beforeEdit, this);
58224 beforeEdit : function(e){
58225 this.select(e.row, e.column, false, true, e.record);
58229 onRowUpdated : function(v, index, r){
58230 if(this.selection && this.selection.record == r){
58231 v.onCellSelect(index, this.selection.cell[1]);
58236 onViewChange : function(){
58237 this.clearSelections(true);
58241 * Returns the currently selected cell,.
58242 * @return {Array} The selected cell (row, column) or null if none selected.
58244 getSelectedCell : function(){
58245 return this.selection ? this.selection.cell : null;
58249 * Clears all selections.
58250 * @param {Boolean} true to prevent the gridview from being notified about the change.
58252 clearSelections : function(preventNotify){
58253 var s = this.selection;
58255 if(preventNotify !== true){
58256 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58258 this.selection = null;
58259 this.fireEvent("selectionchange", this, null);
58264 * Returns true if there is a selection.
58265 * @return {Boolean}
58267 hasSelection : function(){
58268 return this.selection ? true : false;
58272 handleMouseDown : function(e, t){
58273 var v = this.grid.getView();
58274 if(this.isLocked()){
58277 var row = v.findRowIndex(t);
58278 var cell = v.findCellIndex(t);
58279 if(row !== false && cell !== false){
58280 this.select(row, cell);
58286 * @param {Number} rowIndex
58287 * @param {Number} collIndex
58289 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58290 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58291 this.clearSelections();
58292 r = r || this.grid.dataSource.getAt(rowIndex);
58295 cell : [rowIndex, colIndex]
58297 if(!preventViewNotify){
58298 var v = this.grid.getView();
58299 v.onCellSelect(rowIndex, colIndex);
58300 if(preventFocus !== true){
58301 v.focusCell(rowIndex, colIndex);
58304 this.fireEvent("cellselect", this, rowIndex, colIndex);
58305 this.fireEvent("selectionchange", this, this.selection);
58310 isSelectable : function(rowIndex, colIndex, cm){
58311 return !cm.isHidden(colIndex);
58315 handleKeyDown : function(e){
58316 //Roo.log('Cell Sel Model handleKeyDown');
58317 if(!e.isNavKeyPress()){
58320 var g = this.grid, s = this.selection;
58323 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58325 this.select(cell[0], cell[1]);
58330 var walk = function(row, col, step){
58331 return g.walkCells(row, col, step, sm.isSelectable, sm);
58333 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58340 // handled by onEditorKey
58341 if (g.isEditor && g.editing) {
58345 newCell = walk(r, c-1, -1);
58347 newCell = walk(r, c+1, 1);
58352 newCell = walk(r+1, c, 1);
58356 newCell = walk(r-1, c, -1);
58360 newCell = walk(r, c+1, 1);
58364 newCell = walk(r, c-1, -1);
58369 if(g.isEditor && !g.editing){
58370 g.startEditing(r, c);
58379 this.select(newCell[0], newCell[1]);
58385 acceptsNav : function(row, col, cm){
58386 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58390 * @param {Number} field (not used) - as it's normally used as a listener
58391 * @param {Number} e - event - fake it by using
58393 * var e = Roo.EventObjectImpl.prototype;
58394 * e.keyCode = e.TAB
58398 onEditorKey : function(field, e){
58400 var k = e.getKey(),
58403 ed = g.activeEditor,
58405 ///Roo.log('onEditorKey' + k);
58408 if (this.enter_is_tab && k == e.ENTER) {
58414 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58416 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58422 } else if(k == e.ENTER && !e.ctrlKey){
58425 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58427 } else if(k == e.ESC){
58432 var ecall = { cell : newCell, forward : forward };
58433 this.fireEvent('beforeeditnext', ecall );
58434 newCell = ecall.cell;
58435 forward = ecall.forward;
58439 //Roo.log('next cell after edit');
58440 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58441 } else if (forward) {
58442 // tabbed past last
58443 this.fireEvent.defer(100, this, ['tabend',this]);
58448 * Ext JS Library 1.1.1
58449 * Copyright(c) 2006-2007, Ext JS, LLC.
58451 * Originally Released Under LGPL - original licence link has changed is not relivant.
58454 * <script type="text/javascript">
58458 * @class Roo.grid.EditorGrid
58459 * @extends Roo.grid.Grid
58460 * Class for creating and editable grid.
58461 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58462 * The container MUST have some type of size defined for the grid to fill. The container will be
58463 * automatically set to position relative if it isn't already.
58464 * @param {Object} dataSource The data model to bind to
58465 * @param {Object} colModel The column model with info about this grid's columns
58467 Roo.grid.EditorGrid = function(container, config){
58468 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58469 this.getGridEl().addClass("xedit-grid");
58471 if(!this.selModel){
58472 this.selModel = new Roo.grid.CellSelectionModel();
58475 this.activeEditor = null;
58479 * @event beforeedit
58480 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58481 * <ul style="padding:5px;padding-left:16px;">
58482 * <li>grid - This grid</li>
58483 * <li>record - The record being edited</li>
58484 * <li>field - The field name being edited</li>
58485 * <li>value - The value for the field being edited.</li>
58486 * <li>row - The grid row index</li>
58487 * <li>column - The grid column index</li>
58488 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58490 * @param {Object} e An edit event (see above for description)
58492 "beforeedit" : true,
58495 * Fires after a cell is edited. <br />
58496 * <ul style="padding:5px;padding-left:16px;">
58497 * <li>grid - This grid</li>
58498 * <li>record - The record being edited</li>
58499 * <li>field - The field name being edited</li>
58500 * <li>value - The value being set</li>
58501 * <li>originalValue - The original value for the field, before the edit.</li>
58502 * <li>row - The grid row index</li>
58503 * <li>column - The grid column index</li>
58505 * @param {Object} e An edit event (see above for description)
58507 "afteredit" : true,
58509 * @event validateedit
58510 * Fires after a cell is edited, but before the value is set in the record.
58511 * You can use this to modify the value being set in the field, Return false
58512 * to cancel the change. The edit event object has the following properties <br />
58513 * <ul style="padding:5px;padding-left:16px;">
58514 * <li>editor - This editor</li>
58515 * <li>grid - This grid</li>
58516 * <li>record - The record being edited</li>
58517 * <li>field - The field name being edited</li>
58518 * <li>value - The value being set</li>
58519 * <li>originalValue - The original value for the field, before the edit.</li>
58520 * <li>row - The grid row index</li>
58521 * <li>column - The grid column index</li>
58522 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58524 * @param {Object} e An edit event (see above for description)
58526 "validateedit" : true
58528 this.on("bodyscroll", this.stopEditing, this);
58529 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58532 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58534 * @cfg {Number} clicksToEdit
58535 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58542 trackMouseOver: false, // causes very odd FF errors
58544 onCellDblClick : function(g, row, col){
58545 this.startEditing(row, col);
58548 onEditComplete : function(ed, value, startValue){
58549 this.editing = false;
58550 this.activeEditor = null;
58551 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58553 var field = this.colModel.getDataIndex(ed.col);
58558 originalValue: startValue,
58565 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58568 if(String(value) !== String(startValue)){
58570 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58571 r.set(field, e.value);
58572 // if we are dealing with a combo box..
58573 // then we also set the 'name' colum to be the displayField
58574 if (ed.field.displayField && ed.field.name) {
58575 r.set(ed.field.name, ed.field.el.dom.value);
58578 delete e.cancel; //?? why!!!
58579 this.fireEvent("afteredit", e);
58582 this.fireEvent("afteredit", e); // always fire it!
58584 this.view.focusCell(ed.row, ed.col);
58588 * Starts editing the specified for the specified row/column
58589 * @param {Number} rowIndex
58590 * @param {Number} colIndex
58592 startEditing : function(row, col){
58593 this.stopEditing();
58594 if(this.colModel.isCellEditable(col, row)){
58595 this.view.ensureVisible(row, col, true);
58597 var r = this.dataSource.getAt(row);
58598 var field = this.colModel.getDataIndex(col);
58599 var cell = Roo.get(this.view.getCell(row,col));
58604 value: r.data[field],
58609 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58610 this.editing = true;
58611 var ed = this.colModel.getCellEditor(col, row);
58617 ed.render(ed.parentEl || document.body);
58623 (function(){ // complex but required for focus issues in safari, ie and opera
58627 ed.on("complete", this.onEditComplete, this, {single: true});
58628 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58629 this.activeEditor = ed;
58630 var v = r.data[field];
58631 ed.startEdit(this.view.getCell(row, col), v);
58632 // combo's with 'displayField and name set
58633 if (ed.field.displayField && ed.field.name) {
58634 ed.field.el.dom.value = r.data[ed.field.name];
58638 }).defer(50, this);
58644 * Stops any active editing
58646 stopEditing : function(){
58647 if(this.activeEditor){
58648 this.activeEditor.completeEdit();
58650 this.activeEditor = null;
58654 * Called to get grid's drag proxy text, by default returns this.ddText.
58657 getDragDropText : function(){
58658 var count = this.selModel.getSelectedCell() ? 1 : 0;
58659 return String.format(this.ddText, count, count == 1 ? '' : 's');
58664 * Ext JS Library 1.1.1
58665 * Copyright(c) 2006-2007, Ext JS, LLC.
58667 * Originally Released Under LGPL - original licence link has changed is not relivant.
58670 * <script type="text/javascript">
58673 // private - not really -- you end up using it !
58674 // This is a support class used internally by the Grid components
58677 * @class Roo.grid.GridEditor
58678 * @extends Roo.Editor
58679 * Class for creating and editable grid elements.
58680 * @param {Object} config any settings (must include field)
58682 Roo.grid.GridEditor = function(field, config){
58683 if (!config && field.field) {
58685 field = Roo.factory(config.field, Roo.form);
58687 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58688 field.monitorTab = false;
58691 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58694 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58697 alignment: "tl-tl",
58700 cls: "x-small-editor x-grid-editor",
58705 * Ext JS Library 1.1.1
58706 * Copyright(c) 2006-2007, Ext JS, LLC.
58708 * Originally Released Under LGPL - original licence link has changed is not relivant.
58711 * <script type="text/javascript">
58716 Roo.grid.PropertyRecord = Roo.data.Record.create([
58717 {name:'name',type:'string'}, 'value'
58721 Roo.grid.PropertyStore = function(grid, source){
58723 this.store = new Roo.data.Store({
58724 recordType : Roo.grid.PropertyRecord
58726 this.store.on('update', this.onUpdate, this);
58728 this.setSource(source);
58730 Roo.grid.PropertyStore.superclass.constructor.call(this);
58735 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58736 setSource : function(o){
58738 this.store.removeAll();
58741 if(this.isEditableValue(o[k])){
58742 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58745 this.store.loadRecords({records: data}, {}, true);
58748 onUpdate : function(ds, record, type){
58749 if(type == Roo.data.Record.EDIT){
58750 var v = record.data['value'];
58751 var oldValue = record.modified['value'];
58752 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58753 this.source[record.id] = v;
58755 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58762 getProperty : function(row){
58763 return this.store.getAt(row);
58766 isEditableValue: function(val){
58767 if(val && val instanceof Date){
58769 }else if(typeof val == 'object' || typeof val == 'function'){
58775 setValue : function(prop, value){
58776 this.source[prop] = value;
58777 this.store.getById(prop).set('value', value);
58780 getSource : function(){
58781 return this.source;
58785 Roo.grid.PropertyColumnModel = function(grid, store){
58788 g.PropertyColumnModel.superclass.constructor.call(this, [
58789 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58790 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58792 this.store = store;
58793 this.bselect = Roo.DomHelper.append(document.body, {
58794 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58795 {tag: 'option', value: 'true', html: 'true'},
58796 {tag: 'option', value: 'false', html: 'false'}
58799 Roo.id(this.bselect);
58802 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58803 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58804 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58805 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58806 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58808 this.renderCellDelegate = this.renderCell.createDelegate(this);
58809 this.renderPropDelegate = this.renderProp.createDelegate(this);
58812 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58816 valueText : 'Value',
58818 dateFormat : 'm/j/Y',
58821 renderDate : function(dateVal){
58822 return dateVal.dateFormat(this.dateFormat);
58825 renderBool : function(bVal){
58826 return bVal ? 'true' : 'false';
58829 isCellEditable : function(colIndex, rowIndex){
58830 return colIndex == 1;
58833 getRenderer : function(col){
58835 this.renderCellDelegate : this.renderPropDelegate;
58838 renderProp : function(v){
58839 return this.getPropertyName(v);
58842 renderCell : function(val){
58844 if(val instanceof Date){
58845 rv = this.renderDate(val);
58846 }else if(typeof val == 'boolean'){
58847 rv = this.renderBool(val);
58849 return Roo.util.Format.htmlEncode(rv);
58852 getPropertyName : function(name){
58853 var pn = this.grid.propertyNames;
58854 return pn && pn[name] ? pn[name] : name;
58857 getCellEditor : function(colIndex, rowIndex){
58858 var p = this.store.getProperty(rowIndex);
58859 var n = p.data['name'], val = p.data['value'];
58861 if(typeof(this.grid.customEditors[n]) == 'string'){
58862 return this.editors[this.grid.customEditors[n]];
58864 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58865 return this.grid.customEditors[n];
58867 if(val instanceof Date){
58868 return this.editors['date'];
58869 }else if(typeof val == 'number'){
58870 return this.editors['number'];
58871 }else if(typeof val == 'boolean'){
58872 return this.editors['boolean'];
58874 return this.editors['string'];
58880 * @class Roo.grid.PropertyGrid
58881 * @extends Roo.grid.EditorGrid
58882 * This class represents the interface of a component based property grid control.
58883 * <br><br>Usage:<pre><code>
58884 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58892 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58893 * The container MUST have some type of size defined for the grid to fill. The container will be
58894 * automatically set to position relative if it isn't already.
58895 * @param {Object} config A config object that sets properties on this grid.
58897 Roo.grid.PropertyGrid = function(container, config){
58898 config = config || {};
58899 var store = new Roo.grid.PropertyStore(this);
58900 this.store = store;
58901 var cm = new Roo.grid.PropertyColumnModel(this, store);
58902 store.store.sort('name', 'ASC');
58903 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58906 enableColLock:false,
58907 enableColumnMove:false,
58909 trackMouseOver: false,
58912 this.getGridEl().addClass('x-props-grid');
58913 this.lastEditRow = null;
58914 this.on('columnresize', this.onColumnResize, this);
58917 * @event beforepropertychange
58918 * Fires before a property changes (return false to stop?)
58919 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58920 * @param {String} id Record Id
58921 * @param {String} newval New Value
58922 * @param {String} oldval Old Value
58924 "beforepropertychange": true,
58926 * @event propertychange
58927 * Fires after a property changes
58928 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58929 * @param {String} id Record Id
58930 * @param {String} newval New Value
58931 * @param {String} oldval Old Value
58933 "propertychange": true
58935 this.customEditors = this.customEditors || {};
58937 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58940 * @cfg {Object} customEditors map of colnames=> custom editors.
58941 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58942 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58943 * false disables editing of the field.
58947 * @cfg {Object} propertyNames map of property Names to their displayed value
58950 render : function(){
58951 Roo.grid.PropertyGrid.superclass.render.call(this);
58952 this.autoSize.defer(100, this);
58955 autoSize : function(){
58956 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58958 this.view.fitColumns();
58962 onColumnResize : function(){
58963 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58967 * Sets the data for the Grid
58968 * accepts a Key => Value object of all the elements avaiable.
58969 * @param {Object} data to appear in grid.
58971 setSource : function(source){
58972 this.store.setSource(source);
58976 * Gets all the data from the grid.
58977 * @return {Object} data data stored in grid
58979 getSource : function(){
58980 return this.store.getSource();
58989 * @class Roo.grid.Calendar
58990 * @extends Roo.util.Grid
58991 * This class extends the Grid to provide a calendar widget
58992 * <br><br>Usage:<pre><code>
58993 var grid = new Roo.grid.Calendar("my-container-id", {
58996 selModel: mySelectionModel,
58997 autoSizeColumns: true,
58998 monitorWindowResize: false,
58999 trackMouseOver: true
59000 eventstore : real data store..
59006 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59007 * The container MUST have some type of size defined for the grid to fill. The container will be
59008 * automatically set to position relative if it isn't already.
59009 * @param {Object} config A config object that sets properties on this grid.
59011 Roo.grid.Calendar = function(container, config){
59012 // initialize the container
59013 this.container = Roo.get(container);
59014 this.container.update("");
59015 this.container.setStyle("overflow", "hidden");
59016 this.container.addClass('x-grid-container');
59018 this.id = this.container.id;
59020 Roo.apply(this, config);
59021 // check and correct shorthanded configs
59025 for (var r = 0;r < 6;r++) {
59028 for (var c =0;c < 7;c++) {
59032 if (this.eventStore) {
59033 this.eventStore= Roo.factory(this.eventStore, Roo.data);
59034 this.eventStore.on('load',this.onLoad, this);
59035 this.eventStore.on('beforeload',this.clearEvents, this);
59039 this.dataSource = new Roo.data.Store({
59040 proxy: new Roo.data.MemoryProxy(rows),
59041 reader: new Roo.data.ArrayReader({}, [
59042 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
59045 this.dataSource.load();
59046 this.ds = this.dataSource;
59047 this.ds.xmodule = this.xmodule || false;
59050 var cellRender = function(v,x,r)
59052 return String.format(
59053 '<div class="fc-day fc-widget-content"><div>' +
59054 '<div class="fc-event-container"></div>' +
59055 '<div class="fc-day-number">{0}</div>'+
59057 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
59058 '</div></div>', v);
59063 this.colModel = new Roo.grid.ColumnModel( [
59065 xtype: 'ColumnModel',
59067 dataIndex : 'weekday0',
59069 renderer : cellRender
59072 xtype: 'ColumnModel',
59074 dataIndex : 'weekday1',
59076 renderer : cellRender
59079 xtype: 'ColumnModel',
59081 dataIndex : 'weekday2',
59082 header : 'Tuesday',
59083 renderer : cellRender
59086 xtype: 'ColumnModel',
59088 dataIndex : 'weekday3',
59089 header : 'Wednesday',
59090 renderer : cellRender
59093 xtype: 'ColumnModel',
59095 dataIndex : 'weekday4',
59096 header : 'Thursday',
59097 renderer : cellRender
59100 xtype: 'ColumnModel',
59102 dataIndex : 'weekday5',
59104 renderer : cellRender
59107 xtype: 'ColumnModel',
59109 dataIndex : 'weekday6',
59110 header : 'Saturday',
59111 renderer : cellRender
59114 this.cm = this.colModel;
59115 this.cm.xmodule = this.xmodule || false;
59119 //this.selModel = new Roo.grid.CellSelectionModel();
59120 //this.sm = this.selModel;
59121 //this.selModel.init(this);
59125 this.container.setWidth(this.width);
59129 this.container.setHeight(this.height);
59136 * The raw click event for the entire grid.
59137 * @param {Roo.EventObject} e
59142 * The raw dblclick event for the entire grid.
59143 * @param {Roo.EventObject} e
59147 * @event contextmenu
59148 * The raw contextmenu event for the entire grid.
59149 * @param {Roo.EventObject} e
59151 "contextmenu" : true,
59154 * The raw mousedown event for the entire grid.
59155 * @param {Roo.EventObject} e
59157 "mousedown" : true,
59160 * The raw mouseup event for the entire grid.
59161 * @param {Roo.EventObject} e
59166 * The raw mouseover event for the entire grid.
59167 * @param {Roo.EventObject} e
59169 "mouseover" : true,
59172 * The raw mouseout event for the entire grid.
59173 * @param {Roo.EventObject} e
59178 * The raw keypress event for the entire grid.
59179 * @param {Roo.EventObject} e
59184 * The raw keydown event for the entire grid.
59185 * @param {Roo.EventObject} e
59193 * Fires when a cell is clicked
59194 * @param {Grid} this
59195 * @param {Number} rowIndex
59196 * @param {Number} columnIndex
59197 * @param {Roo.EventObject} e
59199 "cellclick" : true,
59201 * @event celldblclick
59202 * Fires when a cell is double clicked
59203 * @param {Grid} this
59204 * @param {Number} rowIndex
59205 * @param {Number} columnIndex
59206 * @param {Roo.EventObject} e
59208 "celldblclick" : true,
59211 * Fires when a row is clicked
59212 * @param {Grid} this
59213 * @param {Number} rowIndex
59214 * @param {Roo.EventObject} e
59218 * @event rowdblclick
59219 * Fires when a row is double clicked
59220 * @param {Grid} this
59221 * @param {Number} rowIndex
59222 * @param {Roo.EventObject} e
59224 "rowdblclick" : true,
59226 * @event headerclick
59227 * Fires when a header is clicked
59228 * @param {Grid} this
59229 * @param {Number} columnIndex
59230 * @param {Roo.EventObject} e
59232 "headerclick" : true,
59234 * @event headerdblclick
59235 * Fires when a header cell is double clicked
59236 * @param {Grid} this
59237 * @param {Number} columnIndex
59238 * @param {Roo.EventObject} e
59240 "headerdblclick" : true,
59242 * @event rowcontextmenu
59243 * Fires when a row is right clicked
59244 * @param {Grid} this
59245 * @param {Number} rowIndex
59246 * @param {Roo.EventObject} e
59248 "rowcontextmenu" : true,
59250 * @event cellcontextmenu
59251 * Fires when a cell is right clicked
59252 * @param {Grid} this
59253 * @param {Number} rowIndex
59254 * @param {Number} cellIndex
59255 * @param {Roo.EventObject} e
59257 "cellcontextmenu" : true,
59259 * @event headercontextmenu
59260 * Fires when a header is right clicked
59261 * @param {Grid} this
59262 * @param {Number} columnIndex
59263 * @param {Roo.EventObject} e
59265 "headercontextmenu" : true,
59267 * @event bodyscroll
59268 * Fires when the body element is scrolled
59269 * @param {Number} scrollLeft
59270 * @param {Number} scrollTop
59272 "bodyscroll" : true,
59274 * @event columnresize
59275 * Fires when the user resizes a column
59276 * @param {Number} columnIndex
59277 * @param {Number} newSize
59279 "columnresize" : true,
59281 * @event columnmove
59282 * Fires when the user moves a column
59283 * @param {Number} oldIndex
59284 * @param {Number} newIndex
59286 "columnmove" : true,
59289 * Fires when row(s) start being dragged
59290 * @param {Grid} this
59291 * @param {Roo.GridDD} dd The drag drop object
59292 * @param {event} e The raw browser event
59294 "startdrag" : true,
59297 * Fires when a drag operation is complete
59298 * @param {Grid} this
59299 * @param {Roo.GridDD} dd The drag drop object
59300 * @param {event} e The raw browser event
59305 * Fires when dragged row(s) are dropped on a valid DD target
59306 * @param {Grid} this
59307 * @param {Roo.GridDD} dd The drag drop object
59308 * @param {String} targetId The target drag drop object
59309 * @param {event} e The raw browser event
59314 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59315 * @param {Grid} this
59316 * @param {Roo.GridDD} dd The drag drop object
59317 * @param {String} targetId The target drag drop object
59318 * @param {event} e The raw browser event
59323 * Fires when the dragged row(s) first cross another DD target while being dragged
59324 * @param {Grid} this
59325 * @param {Roo.GridDD} dd The drag drop object
59326 * @param {String} targetId The target drag drop object
59327 * @param {event} e The raw browser event
59329 "dragenter" : true,
59332 * Fires when the dragged row(s) leave another DD target while being dragged
59333 * @param {Grid} this
59334 * @param {Roo.GridDD} dd The drag drop object
59335 * @param {String} targetId The target drag drop object
59336 * @param {event} e The raw browser event
59341 * Fires when a row is rendered, so you can change add a style to it.
59342 * @param {GridView} gridview The grid view
59343 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59349 * Fires when the grid is rendered
59350 * @param {Grid} grid
59355 * Fires when a date is selected
59356 * @param {DatePicker} this
59357 * @param {Date} date The selected date
59361 * @event monthchange
59362 * Fires when the displayed month changes
59363 * @param {DatePicker} this
59364 * @param {Date} date The selected month
59366 'monthchange': true,
59368 * @event evententer
59369 * Fires when mouse over an event
59370 * @param {Calendar} this
59371 * @param {event} Event
59373 'evententer': true,
59375 * @event eventleave
59376 * Fires when the mouse leaves an
59377 * @param {Calendar} this
59380 'eventleave': true,
59382 * @event eventclick
59383 * Fires when the mouse click an
59384 * @param {Calendar} this
59387 'eventclick': true,
59389 * @event eventrender
59390 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59391 * @param {Calendar} this
59392 * @param {data} data to be modified
59394 'eventrender': true
59398 Roo.grid.Grid.superclass.constructor.call(this);
59399 this.on('render', function() {
59400 this.view.el.addClass('x-grid-cal');
59402 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59406 if (!Roo.grid.Calendar.style) {
59407 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59410 '.x-grid-cal .x-grid-col' : {
59411 height: 'auto !important',
59412 'vertical-align': 'top'
59414 '.x-grid-cal .fc-event-hori' : {
59425 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59427 * @cfg {Store} eventStore The store that loads events.
59432 activeDate : false,
59435 monitorWindowResize : false,
59438 resizeColumns : function() {
59439 var col = (this.view.el.getWidth() / 7) - 3;
59440 // loop through cols, and setWidth
59441 for(var i =0 ; i < 7 ; i++){
59442 this.cm.setColumnWidth(i, col);
59445 setDate :function(date) {
59447 Roo.log('setDate?');
59449 this.resizeColumns();
59450 var vd = this.activeDate;
59451 this.activeDate = date;
59452 // if(vd && this.el){
59453 // var t = date.getTime();
59454 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59455 // Roo.log('using add remove');
59457 // this.fireEvent('monthchange', this, date);
59459 // this.cells.removeClass("fc-state-highlight");
59460 // this.cells.each(function(c){
59461 // if(c.dateValue == t){
59462 // c.addClass("fc-state-highlight");
59463 // setTimeout(function(){
59464 // try{c.dom.firstChild.focus();}catch(e){}
59474 var days = date.getDaysInMonth();
59476 var firstOfMonth = date.getFirstDateOfMonth();
59477 var startingPos = firstOfMonth.getDay()-this.startDay;
59479 if(startingPos < this.startDay){
59483 var pm = date.add(Date.MONTH, -1);
59484 var prevStart = pm.getDaysInMonth()-startingPos;
59488 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59490 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59491 //this.cells.addClassOnOver('fc-state-hover');
59493 var cells = this.cells.elements;
59494 var textEls = this.textNodes;
59496 //Roo.each(cells, function(cell){
59497 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59500 days += startingPos;
59502 // convert everything to numbers so it's fast
59503 var day = 86400000;
59504 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59507 //Roo.log(prevStart);
59509 var today = new Date().clearTime().getTime();
59510 var sel = date.clearTime().getTime();
59511 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59512 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59513 var ddMatch = this.disabledDatesRE;
59514 var ddText = this.disabledDatesText;
59515 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59516 var ddaysText = this.disabledDaysText;
59517 var format = this.format;
59519 var setCellClass = function(cal, cell){
59521 //Roo.log('set Cell Class');
59523 var t = d.getTime();
59528 cell.dateValue = t;
59530 cell.className += " fc-today";
59531 cell.className += " fc-state-highlight";
59532 cell.title = cal.todayText;
59535 // disable highlight in other month..
59536 cell.className += " fc-state-highlight";
59541 //cell.className = " fc-state-disabled";
59542 cell.title = cal.minText;
59546 //cell.className = " fc-state-disabled";
59547 cell.title = cal.maxText;
59551 if(ddays.indexOf(d.getDay()) != -1){
59552 // cell.title = ddaysText;
59553 // cell.className = " fc-state-disabled";
59556 if(ddMatch && format){
59557 var fvalue = d.dateFormat(format);
59558 if(ddMatch.test(fvalue)){
59559 cell.title = ddText.replace("%0", fvalue);
59560 cell.className = " fc-state-disabled";
59564 if (!cell.initialClassName) {
59565 cell.initialClassName = cell.dom.className;
59568 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59573 for(; i < startingPos; i++) {
59574 cells[i].dayName = (++prevStart);
59575 Roo.log(textEls[i]);
59576 d.setDate(d.getDate()+1);
59578 //cells[i].className = "fc-past fc-other-month";
59579 setCellClass(this, cells[i]);
59584 for(; i < days; i++){
59585 intDay = i - startingPos + 1;
59586 cells[i].dayName = (intDay);
59587 d.setDate(d.getDate()+1);
59589 cells[i].className = ''; // "x-date-active";
59590 setCellClass(this, cells[i]);
59594 for(; i < 42; i++) {
59595 //textEls[i].innerHTML = (++extraDays);
59597 d.setDate(d.getDate()+1);
59598 cells[i].dayName = (++extraDays);
59599 cells[i].className = "fc-future fc-other-month";
59600 setCellClass(this, cells[i]);
59603 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59605 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59607 // this will cause all the cells to mis
59610 for (var r = 0;r < 6;r++) {
59611 for (var c =0;c < 7;c++) {
59612 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59616 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59617 for(i=0;i<cells.length;i++) {
59619 this.cells.elements[i].dayName = cells[i].dayName ;
59620 this.cells.elements[i].className = cells[i].className;
59621 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59622 this.cells.elements[i].title = cells[i].title ;
59623 this.cells.elements[i].dateValue = cells[i].dateValue ;
59629 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59630 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59632 ////if(totalRows != 6){
59633 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59634 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59637 this.fireEvent('monthchange', this, date);
59642 * Returns the grid's SelectionModel.
59643 * @return {SelectionModel}
59645 getSelectionModel : function(){
59646 if(!this.selModel){
59647 this.selModel = new Roo.grid.CellSelectionModel();
59649 return this.selModel;
59653 this.eventStore.load()
59659 findCell : function(dt) {
59660 dt = dt.clearTime().getTime();
59662 this.cells.each(function(c){
59663 //Roo.log("check " +c.dateValue + '?=' + dt);
59664 if(c.dateValue == dt){
59674 findCells : function(rec) {
59675 var s = rec.data.start_dt.clone().clearTime().getTime();
59677 var e= rec.data.end_dt.clone().clearTime().getTime();
59680 this.cells.each(function(c){
59681 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59683 if(c.dateValue > e){
59686 if(c.dateValue < s){
59695 findBestRow: function(cells)
59699 for (var i =0 ; i < cells.length;i++) {
59700 ret = Math.max(cells[i].rows || 0,ret);
59707 addItem : function(rec)
59709 // look for vertical location slot in
59710 var cells = this.findCells(rec);
59712 rec.row = this.findBestRow(cells);
59714 // work out the location.
59718 for(var i =0; i < cells.length; i++) {
59726 if (crow.start.getY() == cells[i].getY()) {
59728 crow.end = cells[i];
59744 for (var i = 0; i < cells.length;i++) {
59745 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59752 clearEvents: function() {
59754 if (!this.eventStore.getCount()) {
59757 // reset number of rows in cells.
59758 Roo.each(this.cells.elements, function(c){
59762 this.eventStore.each(function(e) {
59763 this.clearEvent(e);
59768 clearEvent : function(ev)
59771 Roo.each(ev.els, function(el) {
59772 el.un('mouseenter' ,this.onEventEnter, this);
59773 el.un('mouseleave' ,this.onEventLeave, this);
59781 renderEvent : function(ev,ctr) {
59783 ctr = this.view.el.select('.fc-event-container',true).first();
59787 this.clearEvent(ev);
59793 var cells = ev.cells;
59794 var rows = ev.rows;
59795 this.fireEvent('eventrender', this, ev);
59797 for(var i =0; i < rows.length; i++) {
59801 cls += ' fc-event-start';
59803 if ((i+1) == rows.length) {
59804 cls += ' fc-event-end';
59807 //Roo.log(ev.data);
59808 // how many rows should it span..
59809 var cg = this.eventTmpl.append(ctr,Roo.apply({
59812 }, ev.data) , true);
59815 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59816 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59817 cg.on('click', this.onEventClick, this, ev);
59821 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59822 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59825 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59826 cg.setWidth(ebox.right - sbox.x -2);
59830 renderEvents: function()
59832 // first make sure there is enough space..
59834 if (!this.eventTmpl) {
59835 this.eventTmpl = new Roo.Template(
59836 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59837 '<div class="fc-event-inner">' +
59838 '<span class="fc-event-time">{time}</span>' +
59839 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59841 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59849 this.cells.each(function(c) {
59850 //Roo.log(c.select('.fc-day-content div',true).first());
59851 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59854 var ctr = this.view.el.select('.fc-event-container',true).first();
59857 this.eventStore.each(function(ev){
59859 this.renderEvent(ev);
59863 this.view.layout();
59867 onEventEnter: function (e, el,event,d) {
59868 this.fireEvent('evententer', this, el, event);
59871 onEventLeave: function (e, el,event,d) {
59872 this.fireEvent('eventleave', this, el, event);
59875 onEventClick: function (e, el,event,d) {
59876 this.fireEvent('eventclick', this, el, event);
59879 onMonthChange: function () {
59883 onLoad: function () {
59885 //Roo.log('calendar onload');
59887 if(this.eventStore.getCount() > 0){
59891 this.eventStore.each(function(d){
59896 if (typeof(add.end_dt) == 'undefined') {
59897 Roo.log("Missing End time in calendar data: ");
59901 if (typeof(add.start_dt) == 'undefined') {
59902 Roo.log("Missing Start time in calendar data: ");
59906 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59907 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59908 add.id = add.id || d.id;
59909 add.title = add.title || '??';
59917 this.renderEvents();
59927 render : function ()
59931 if (!this.view.el.hasClass('course-timesheet')) {
59932 this.view.el.addClass('course-timesheet');
59934 if (this.tsStyle) {
59939 Roo.log(_this.grid.view.el.getWidth());
59942 this.tsStyle = Roo.util.CSS.createStyleSheet({
59943 '.course-timesheet .x-grid-row' : {
59946 '.x-grid-row td' : {
59947 'vertical-align' : 0
59949 '.course-edit-link' : {
59951 'text-overflow' : 'ellipsis',
59952 'overflow' : 'hidden',
59953 'white-space' : 'nowrap',
59954 'cursor' : 'pointer'
59959 '.de-act-sup-link' : {
59960 'color' : 'purple',
59961 'text-decoration' : 'line-through'
59965 'text-decoration' : 'line-through'
59967 '.course-timesheet .course-highlight' : {
59968 'border-top-style': 'dashed !important',
59969 'border-bottom-bottom': 'dashed !important'
59971 '.course-timesheet .course-item' : {
59972 'font-family' : 'tahoma, arial, helvetica',
59973 'font-size' : '11px',
59974 'overflow' : 'hidden',
59975 'padding-left' : '10px',
59976 'padding-right' : '10px',
59977 'padding-top' : '10px'
59985 monitorWindowResize : false,
59986 cellrenderer : function(v,x,r)
59991 xtype: 'CellSelectionModel',
59998 beforeload : function (_self, options)
60000 options.params = options.params || {};
60001 options.params._month = _this.monthField.getValue();
60002 options.params.limit = 9999;
60003 options.params['sort'] = 'when_dt';
60004 options.params['dir'] = 'ASC';
60005 this.proxy.loadResponse = this.loadResponse;
60007 //this.addColumns();
60009 load : function (_self, records, options)
60011 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
60012 // if you click on the translation.. you can edit it...
60013 var el = Roo.get(this);
60014 var id = el.dom.getAttribute('data-id');
60015 var d = el.dom.getAttribute('data-date');
60016 var t = el.dom.getAttribute('data-time');
60017 //var id = this.child('span').dom.textContent;
60020 Pman.Dialog.CourseCalendar.show({
60024 productitem_active : id ? 1 : 0
60026 _this.grid.ds.load({});
60031 _this.panel.fireEvent('resize', [ '', '' ]);
60034 loadResponse : function(o, success, response){
60035 // this is overridden on before load..
60037 Roo.log("our code?");
60038 //Roo.log(success);
60039 //Roo.log(response)
60040 delete this.activeRequest;
60042 this.fireEvent("loadexception", this, o, response);
60043 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60048 result = o.reader.read(response);
60050 Roo.log("load exception?");
60051 this.fireEvent("loadexception", this, o, response, e);
60052 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60055 Roo.log("ready...");
60056 // loop through result.records;
60057 // and set this.tdate[date] = [] << array of records..
60059 Roo.each(result.records, function(r){
60061 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
60062 _this.tdata[r.data.when_dt.format('j')] = [];
60064 _this.tdata[r.data.when_dt.format('j')].push(r.data);
60067 //Roo.log(_this.tdata);
60069 result.records = [];
60070 result.totalRecords = 6;
60072 // let's generate some duumy records for the rows.
60073 //var st = _this.dateField.getValue();
60075 // work out monday..
60076 //st = st.add(Date.DAY, -1 * st.format('w'));
60078 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60080 var firstOfMonth = date.getFirstDayOfMonth();
60081 var days = date.getDaysInMonth();
60083 var firstAdded = false;
60084 for (var i = 0; i < result.totalRecords ; i++) {
60085 //var d= st.add(Date.DAY, i);
60088 for(var w = 0 ; w < 7 ; w++){
60089 if(!firstAdded && firstOfMonth != w){
60096 var dd = (d > 0 && d < 10) ? "0"+d : d;
60097 row['weekday'+w] = String.format(
60098 '<span style="font-size: 16px;"><b>{0}</b></span>'+
60099 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
60101 date.format('Y-m-')+dd
60104 if(typeof(_this.tdata[d]) != 'undefined'){
60105 Roo.each(_this.tdata[d], function(r){
60109 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
60110 if(r.parent_id*1>0){
60111 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
60114 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
60115 deactive = 'de-act-link';
60118 row['weekday'+w] += String.format(
60119 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
60121 r.product_id_name, //1
60122 r.when_dt.format('h:ia'), //2
60132 // only do this if something added..
60134 result.records.push(_this.grid.dataSource.reader.newRow(row));
60138 // push it twice. (second one with an hour..
60142 this.fireEvent("load", this, o, o.request.arg);
60143 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60145 sortInfo : {field: 'when_dt', direction : 'ASC' },
60147 xtype: 'HttpProxy',
60150 url : baseURL + '/Roo/Shop_course.php'
60153 xtype: 'JsonReader',
60170 'name': 'parent_id',
60174 'name': 'product_id',
60178 'name': 'productitem_id',
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({});
60207 xtype: 'Separator',
60211 xtype: 'MonthField',
60214 render : function (_self)
60216 _this.monthField = _self;
60217 // _this.monthField.set today
60219 select : function (combo, date)
60221 _this.grid.ds.load({});
60224 value : (function() { return new Date(); })()
60227 xtype: 'Separator',
60233 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60243 click : function (_self, e)
60245 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60246 sd.setMonth(sd.getMonth()+1);
60247 _this.monthField.setValue(sd.format('Y-m-d'));
60248 _this.grid.ds.load({});
60261 * Ext JS Library 1.1.1
60262 * Copyright(c) 2006-2007, Ext JS, LLC.
60264 * Originally Released Under LGPL - original licence link has changed is not relivant.
60267 * <script type="text/javascript">
60271 * @class Roo.LoadMask
60272 * A simple utility class for generically masking elements while loading data. If the element being masked has
60273 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60274 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60275 * element's UpdateManager load indicator and will be destroyed after the initial load.
60277 * Create a new LoadMask
60278 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60279 * @param {Object} config The config object
60281 Roo.LoadMask = function(el, config){
60282 this.el = Roo.get(el);
60283 Roo.apply(this, config);
60285 this.store.on('beforeload', this.onBeforeLoad, this);
60286 this.store.on('load', this.onLoad, this);
60287 this.store.on('loadexception', this.onLoadException, this);
60288 this.removeMask = false;
60290 var um = this.el.getUpdateManager();
60291 um.showLoadIndicator = false; // disable the default indicator
60292 um.on('beforeupdate', this.onBeforeLoad, this);
60293 um.on('update', this.onLoad, this);
60294 um.on('failure', this.onLoad, this);
60295 this.removeMask = true;
60299 Roo.LoadMask.prototype = {
60301 * @cfg {Boolean} removeMask
60302 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60303 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60306 * @cfg {String} msg
60307 * The text to display in a centered loading message box (defaults to 'Loading...')
60309 msg : 'Loading...',
60311 * @cfg {String} msgCls
60312 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60314 msgCls : 'x-mask-loading',
60317 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60323 * Disables the mask to prevent it from being displayed
60325 disable : function(){
60326 this.disabled = true;
60330 * Enables the mask so that it can be displayed
60332 enable : function(){
60333 this.disabled = false;
60336 onLoadException : function()
60338 Roo.log(arguments);
60340 if (typeof(arguments[3]) != 'undefined') {
60341 Roo.MessageBox.alert("Error loading",arguments[3]);
60345 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60346 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60353 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60356 onLoad : function()
60358 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60362 onBeforeLoad : function(){
60363 if(!this.disabled){
60364 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60369 destroy : function(){
60371 this.store.un('beforeload', this.onBeforeLoad, this);
60372 this.store.un('load', this.onLoad, this);
60373 this.store.un('loadexception', this.onLoadException, this);
60375 var um = this.el.getUpdateManager();
60376 um.un('beforeupdate', this.onBeforeLoad, this);
60377 um.un('update', this.onLoad, this);
60378 um.un('failure', this.onLoad, this);
60383 * Ext JS Library 1.1.1
60384 * Copyright(c) 2006-2007, Ext JS, LLC.
60386 * Originally Released Under LGPL - original licence link has changed is not relivant.
60389 * <script type="text/javascript">
60394 * @class Roo.XTemplate
60395 * @extends Roo.Template
60396 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60398 var t = new Roo.XTemplate(
60399 '<select name="{name}">',
60400 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60404 // then append, applying the master template values
60407 * Supported features:
60412 {a_variable} - output encoded.
60413 {a_variable.format:("Y-m-d")} - call a method on the variable
60414 {a_variable:raw} - unencoded output
60415 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60416 {a_variable:this.method_on_template(...)} - call a method on the template object.
60421 <tpl for="a_variable or condition.."></tpl>
60422 <tpl if="a_variable or condition"></tpl>
60423 <tpl exec="some javascript"></tpl>
60424 <tpl name="named_template"></tpl> (experimental)
60426 <tpl for="."></tpl> - just iterate the property..
60427 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60431 Roo.XTemplate = function()
60433 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60440 Roo.extend(Roo.XTemplate, Roo.Template, {
60443 * The various sub templates
60448 * basic tag replacing syntax
60451 * // you can fake an object call by doing this
60455 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60458 * compile the template
60460 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60463 compile: function()
60467 s = ['<tpl>', s, '</tpl>'].join('');
60469 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60470 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60471 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60472 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60473 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60478 while(true == !!(m = s.match(re))){
60479 var forMatch = m[0].match(nameRe),
60480 ifMatch = m[0].match(ifRe),
60481 execMatch = m[0].match(execRe),
60482 namedMatch = m[0].match(namedRe),
60487 name = forMatch && forMatch[1] ? forMatch[1] : '';
60490 // if - puts fn into test..
60491 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60493 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60498 // exec - calls a function... returns empty if true is returned.
60499 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60501 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60509 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60510 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60511 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60514 var uid = namedMatch ? namedMatch[1] : id;
60518 id: namedMatch ? namedMatch[1] : id,
60525 s = s.replace(m[0], '');
60527 s = s.replace(m[0], '{xtpl'+ id + '}');
60532 for(var i = tpls.length-1; i >= 0; --i){
60533 this.compileTpl(tpls[i]);
60534 this.tpls[tpls[i].id] = tpls[i];
60536 this.master = tpls[tpls.length-1];
60540 * same as applyTemplate, except it's done to one of the subTemplates
60541 * when using named templates, you can do:
60543 * var str = pl.applySubTemplate('your-name', values);
60546 * @param {Number} id of the template
60547 * @param {Object} values to apply to template
60548 * @param {Object} parent (normaly the instance of this object)
60550 applySubTemplate : function(id, values, parent)
60554 var t = this.tpls[id];
60558 if(t.test && !t.test.call(this, values, parent)){
60562 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60563 Roo.log(e.toString());
60569 if(t.exec && t.exec.call(this, values, parent)){
60573 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60574 Roo.log(e.toString());
60579 var vs = t.target ? t.target.call(this, values, parent) : values;
60580 parent = t.target ? values : parent;
60581 if(t.target && vs instanceof Array){
60583 for(var i = 0, len = vs.length; i < len; i++){
60584 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60586 return buf.join('');
60588 return t.compiled.call(this, vs, parent);
60590 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60591 Roo.log(e.toString());
60592 Roo.log(t.compiled);
60597 compileTpl : function(tpl)
60599 var fm = Roo.util.Format;
60600 var useF = this.disableFormats !== true;
60601 var sep = Roo.isGecko ? "+" : ",";
60602 var undef = function(str) {
60603 Roo.log("Property not found :" + str);
60607 var fn = function(m, name, format, args)
60609 //Roo.log(arguments);
60610 args = args ? args.replace(/\\'/g,"'") : args;
60611 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60612 if (typeof(format) == 'undefined') {
60613 format= 'htmlEncode';
60615 if (format == 'raw' ) {
60619 if(name.substr(0, 4) == 'xtpl'){
60620 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60623 // build an array of options to determine if value is undefined..
60625 // basically get 'xxxx.yyyy' then do
60626 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60627 // (function () { Roo.log("Property not found"); return ''; })() :
60632 Roo.each(name.split('.'), function(st) {
60633 lookfor += (lookfor.length ? '.': '') + st;
60634 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60637 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60640 if(format && useF){
60642 args = args ? ',' + args : "";
60644 if(format.substr(0, 5) != "this."){
60645 format = "fm." + format + '(';
60647 format = 'this.call("'+ format.substr(5) + '", ';
60651 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60655 // called with xxyx.yuu:(test,test)
60657 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60659 // raw.. - :raw modifier..
60660 return "'"+ sep + udef_st + name + ")"+sep+"'";
60664 // branched to use + in gecko and [].join() in others
60666 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60667 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60670 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60671 body.push(tpl.body.replace(/(\r\n|\n)/g,
60672 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60673 body.push("'].join('');};};");
60674 body = body.join('');
60677 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60679 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60685 applyTemplate : function(values){
60686 return this.master.compiled.call(this, values, {});
60687 //var s = this.subs;
60690 apply : function(){
60691 return this.applyTemplate.apply(this, arguments);
60696 Roo.XTemplate.from = function(el){
60697 el = Roo.getDom(el);
60698 return new Roo.XTemplate(el.value || el.innerHTML);