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 = undefined;
11824 this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
11825 Roo.lib.Ajax.defaultPostHeader = 'application/x-www-form-urlencoded';
11833 * Ext JS Library 1.1.1
11834 * Copyright(c) 2006-2007, Ext JS, LLC.
11836 * Originally Released Under LGPL - original licence link has changed is not relivant.
11839 * <script type="text/javascript">
11843 * Global Ajax request class.
11846 * @extends Roo.data.Connection
11849 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11850 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11851 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11852 * @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)
11853 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11854 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11855 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11857 Roo.Ajax = new Roo.data.Connection({
11866 * Serialize the passed form into a url encoded string
11868 * @param {String/HTMLElement} form
11871 serializeForm : function(form){
11872 return Roo.lib.Ajax.serializeForm(form);
11876 * Ext JS Library 1.1.1
11877 * Copyright(c) 2006-2007, Ext JS, LLC.
11879 * Originally Released Under LGPL - original licence link has changed is not relivant.
11882 * <script type="text/javascript">
11887 * @class Roo.UpdateManager
11888 * @extends Roo.util.Observable
11889 * Provides AJAX-style update for Element object.<br><br>
11892 * // Get it from a Roo.Element object
11893 * var el = Roo.get("foo");
11894 * var mgr = el.getUpdateManager();
11895 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11897 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11899 * // or directly (returns the same UpdateManager instance)
11900 * var mgr = new Roo.UpdateManager("myElementId");
11901 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11902 * mgr.on("update", myFcnNeedsToKnow);
11904 // short handed call directly from the element object
11905 Roo.get("foo").load({
11909 text: "Loading Foo..."
11913 * Create new UpdateManager directly.
11914 * @param {String/HTMLElement/Roo.Element} el The element to update
11915 * @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).
11917 Roo.UpdateManager = function(el, forceNew){
11919 if(!forceNew && el.updateManager){
11920 return el.updateManager;
11923 * The Element object
11924 * @type Roo.Element
11928 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11931 this.defaultUrl = null;
11935 * @event beforeupdate
11936 * Fired before an update is made, return false from your handler and the update is cancelled.
11937 * @param {Roo.Element} el
11938 * @param {String/Object/Function} url
11939 * @param {String/Object} params
11941 "beforeupdate": true,
11944 * Fired after successful update is made.
11945 * @param {Roo.Element} el
11946 * @param {Object} oResponseObject The response Object
11951 * Fired on update failure.
11952 * @param {Roo.Element} el
11953 * @param {Object} oResponseObject The response Object
11957 var d = Roo.UpdateManager.defaults;
11959 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11962 this.sslBlankUrl = d.sslBlankUrl;
11964 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11967 this.disableCaching = d.disableCaching;
11969 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11972 this.indicatorText = d.indicatorText;
11974 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11977 this.showLoadIndicator = d.showLoadIndicator;
11979 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11982 this.timeout = d.timeout;
11985 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11988 this.loadScripts = d.loadScripts;
11991 * Transaction object of current executing transaction
11993 this.transaction = null;
11998 this.autoRefreshProcId = null;
12000 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12003 this.refreshDelegate = this.refresh.createDelegate(this);
12005 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12008 this.updateDelegate = this.update.createDelegate(this);
12010 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12013 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12017 this.successDelegate = this.processSuccess.createDelegate(this);
12021 this.failureDelegate = this.processFailure.createDelegate(this);
12023 if(!this.renderer){
12025 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12027 this.renderer = new Roo.UpdateManager.BasicRenderer();
12030 Roo.UpdateManager.superclass.constructor.call(this);
12033 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12035 * Get the Element this UpdateManager is bound to
12036 * @return {Roo.Element} The element
12038 getEl : function(){
12042 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12043 * @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:
12046 url: "your-url.php",<br/>
12047 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12048 callback: yourFunction,<br/>
12049 scope: yourObject, //(optional scope) <br/>
12050 discardUrl: false, <br/>
12051 nocache: false,<br/>
12052 text: "Loading...",<br/>
12054 scripts: false<br/>
12057 * The only required property is url. The optional properties nocache, text and scripts
12058 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12059 * @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}
12060 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12061 * @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.
12063 update : function(url, params, callback, discardUrl){
12064 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12065 var method = this.method,
12067 if(typeof url == "object"){ // must be config object
12070 params = params || cfg.params;
12071 callback = callback || cfg.callback;
12072 discardUrl = discardUrl || cfg.discardUrl;
12073 if(callback && cfg.scope){
12074 callback = callback.createDelegate(cfg.scope);
12076 if(typeof cfg.method != "undefined"){method = cfg.method;};
12077 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12078 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12079 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12080 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12082 this.showLoading();
12084 this.defaultUrl = url;
12086 if(typeof url == "function"){
12087 url = url.call(this);
12090 method = method || (params ? "POST" : "GET");
12091 if(method == "GET"){
12092 url = this.prepareUrl(url);
12095 var o = Roo.apply(cfg ||{}, {
12098 success: this.successDelegate,
12099 failure: this.failureDelegate,
12100 callback: undefined,
12101 timeout: (this.timeout*1000),
12102 argument: {"url": url, "form": null, "callback": callback, "params": params}
12104 Roo.log("updated manager called with timeout of " + o.timeout);
12105 this.transaction = Roo.Ajax.request(o);
12110 * 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.
12111 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12112 * @param {String/HTMLElement} form The form Id or form element
12113 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12114 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12115 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12117 formUpdate : function(form, url, reset, callback){
12118 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12119 if(typeof url == "function"){
12120 url = url.call(this);
12122 form = Roo.getDom(form);
12123 this.transaction = Roo.Ajax.request({
12126 success: this.successDelegate,
12127 failure: this.failureDelegate,
12128 timeout: (this.timeout*1000),
12129 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12131 this.showLoading.defer(1, this);
12136 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12137 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12139 refresh : function(callback){
12140 if(this.defaultUrl == null){
12143 this.update(this.defaultUrl, null, callback, true);
12147 * Set this element to auto refresh.
12148 * @param {Number} interval How often to update (in seconds).
12149 * @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)
12150 * @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}
12151 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12152 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12154 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12156 this.update(url || this.defaultUrl, params, callback, true);
12158 if(this.autoRefreshProcId){
12159 clearInterval(this.autoRefreshProcId);
12161 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12165 * Stop auto refresh on this element.
12167 stopAutoRefresh : function(){
12168 if(this.autoRefreshProcId){
12169 clearInterval(this.autoRefreshProcId);
12170 delete this.autoRefreshProcId;
12174 isAutoRefreshing : function(){
12175 return this.autoRefreshProcId ? true : false;
12178 * Called to update the element to "Loading" state. Override to perform custom action.
12180 showLoading : function(){
12181 if(this.showLoadIndicator){
12182 this.el.update(this.indicatorText);
12187 * Adds unique parameter to query string if disableCaching = true
12190 prepareUrl : function(url){
12191 if(this.disableCaching){
12192 var append = "_dc=" + (new Date().getTime());
12193 if(url.indexOf("?") !== -1){
12194 url += "&" + append;
12196 url += "?" + append;
12205 processSuccess : function(response){
12206 this.transaction = null;
12207 if(response.argument.form && response.argument.reset){
12208 try{ // put in try/catch since some older FF releases had problems with this
12209 response.argument.form.reset();
12212 if(this.loadScripts){
12213 this.renderer.render(this.el, response, this,
12214 this.updateComplete.createDelegate(this, [response]));
12216 this.renderer.render(this.el, response, this);
12217 this.updateComplete(response);
12221 updateComplete : function(response){
12222 this.fireEvent("update", this.el, response);
12223 if(typeof response.argument.callback == "function"){
12224 response.argument.callback(this.el, true, response);
12231 processFailure : function(response){
12232 this.transaction = null;
12233 this.fireEvent("failure", this.el, response);
12234 if(typeof response.argument.callback == "function"){
12235 response.argument.callback(this.el, false, response);
12240 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12241 * @param {Object} renderer The object implementing the render() method
12243 setRenderer : function(renderer){
12244 this.renderer = renderer;
12247 getRenderer : function(){
12248 return this.renderer;
12252 * Set the defaultUrl used for updates
12253 * @param {String/Function} defaultUrl The url or a function to call to get the url
12255 setDefaultUrl : function(defaultUrl){
12256 this.defaultUrl = defaultUrl;
12260 * Aborts the executing transaction
12262 abort : function(){
12263 if(this.transaction){
12264 Roo.Ajax.abort(this.transaction);
12269 * Returns true if an update is in progress
12270 * @return {Boolean}
12272 isUpdating : function(){
12273 if(this.transaction){
12274 return Roo.Ajax.isLoading(this.transaction);
12281 * @class Roo.UpdateManager.defaults
12282 * @static (not really - but it helps the doc tool)
12283 * The defaults collection enables customizing the default properties of UpdateManager
12285 Roo.UpdateManager.defaults = {
12287 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12293 * True to process scripts by default (Defaults to false).
12296 loadScripts : false,
12299 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12302 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12304 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12307 disableCaching : false,
12309 * Whether to show indicatorText when loading (Defaults to true).
12312 showLoadIndicator : true,
12314 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12317 indicatorText : '<div class="loading-indicator">Loading...</div>'
12321 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12323 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12324 * @param {String/HTMLElement/Roo.Element} el The element to update
12325 * @param {String} url The url
12326 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12327 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12330 * @member Roo.UpdateManager
12332 Roo.UpdateManager.updateElement = function(el, url, params, options){
12333 var um = Roo.get(el, true).getUpdateManager();
12334 Roo.apply(um, options);
12335 um.update(url, params, options ? options.callback : null);
12337 // alias for backwards compat
12338 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12340 * @class Roo.UpdateManager.BasicRenderer
12341 * Default Content renderer. Updates the elements innerHTML with the responseText.
12343 Roo.UpdateManager.BasicRenderer = function(){};
12345 Roo.UpdateManager.BasicRenderer.prototype = {
12347 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12348 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12349 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12350 * @param {Roo.Element} el The element being rendered
12351 * @param {Object} response The YUI Connect response object
12352 * @param {UpdateManager} updateManager The calling update manager
12353 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12355 render : function(el, response, updateManager, callback){
12356 el.update(response.responseText, updateManager.loadScripts, callback);
12362 * (c)) Alan Knowles
12368 * @class Roo.DomTemplate
12369 * @extends Roo.Template
12370 * An effort at a dom based template engine..
12372 * Similar to XTemplate, except it uses dom parsing to create the template..
12374 * Supported features:
12379 {a_variable} - output encoded.
12380 {a_variable.format:("Y-m-d")} - call a method on the variable
12381 {a_variable:raw} - unencoded output
12382 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12383 {a_variable:this.method_on_template(...)} - call a method on the template object.
12388 <div roo-for="a_variable or condition.."></div>
12389 <div roo-if="a_variable or condition"></div>
12390 <div roo-exec="some javascript"></div>
12391 <div roo-name="named_template"></div>
12396 Roo.DomTemplate = function()
12398 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12405 Roo.extend(Roo.DomTemplate, Roo.Template, {
12407 * id counter for sub templates.
12411 * flag to indicate if dom parser is inside a pre,
12412 * it will strip whitespace if not.
12417 * The various sub templates
12425 * basic tag replacing syntax
12428 * // you can fake an object call by doing this
12432 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12433 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12435 iterChild : function (node, method) {
12437 var oldPre = this.inPre;
12438 if (node.tagName == 'PRE') {
12441 for( var i = 0; i < node.childNodes.length; i++) {
12442 method.call(this, node.childNodes[i]);
12444 this.inPre = oldPre;
12450 * compile the template
12452 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12455 compile: function()
12459 // covert the html into DOM...
12463 doc = document.implementation.createHTMLDocument("");
12464 doc.documentElement.innerHTML = this.html ;
12465 div = doc.documentElement;
12467 // old IE... - nasty -- it causes all sorts of issues.. with
12468 // images getting pulled from server..
12469 div = document.createElement('div');
12470 div.innerHTML = this.html;
12472 //doc.documentElement.innerHTML = htmlBody
12478 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12480 var tpls = this.tpls;
12482 // create a top level template from the snippet..
12484 //Roo.log(div.innerHTML);
12491 body : div.innerHTML,
12504 Roo.each(tpls, function(tp){
12505 this.compileTpl(tp);
12506 this.tpls[tp.id] = tp;
12509 this.master = tpls[0];
12515 compileNode : function(node, istop) {
12520 // skip anything not a tag..
12521 if (node.nodeType != 1) {
12522 if (node.nodeType == 3 && !this.inPre) {
12523 // reduce white space..
12524 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12547 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12548 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12549 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12550 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12556 // just itterate children..
12557 this.iterChild(node,this.compileNode);
12560 tpl.uid = this.id++;
12561 tpl.value = node.getAttribute('roo-' + tpl.attr);
12562 node.removeAttribute('roo-'+ tpl.attr);
12563 if (tpl.attr != 'name') {
12564 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12565 node.parentNode.replaceChild(placeholder, node);
12568 var placeholder = document.createElement('span');
12569 placeholder.className = 'roo-tpl-' + tpl.value;
12570 node.parentNode.replaceChild(placeholder, node);
12573 // parent now sees '{domtplXXXX}
12574 this.iterChild(node,this.compileNode);
12576 // we should now have node body...
12577 var div = document.createElement('div');
12578 div.appendChild(node);
12580 // this has the unfortunate side effect of converting tagged attributes
12581 // eg. href="{...}" into %7C...%7D
12582 // this has been fixed by searching for those combo's although it's a bit hacky..
12585 tpl.body = div.innerHTML;
12592 switch (tpl.value) {
12593 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12594 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12595 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12600 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12604 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12608 tpl.id = tpl.value; // replace non characters???
12614 this.tpls.push(tpl);
12624 * Compile a segment of the template into a 'sub-template'
12630 compileTpl : function(tpl)
12632 var fm = Roo.util.Format;
12633 var useF = this.disableFormats !== true;
12635 var sep = Roo.isGecko ? "+\n" : ",\n";
12637 var undef = function(str) {
12638 Roo.debug && Roo.log("Property not found :" + str);
12642 //Roo.log(tpl.body);
12646 var fn = function(m, lbrace, name, format, args)
12649 //Roo.log(arguments);
12650 args = args ? args.replace(/\\'/g,"'") : args;
12651 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12652 if (typeof(format) == 'undefined') {
12653 format = 'htmlEncode';
12655 if (format == 'raw' ) {
12659 if(name.substr(0, 6) == 'domtpl'){
12660 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12663 // build an array of options to determine if value is undefined..
12665 // basically get 'xxxx.yyyy' then do
12666 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12667 // (function () { Roo.log("Property not found"); return ''; })() :
12672 Roo.each(name.split('.'), function(st) {
12673 lookfor += (lookfor.length ? '.': '') + st;
12674 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12677 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12680 if(format && useF){
12682 args = args ? ',' + args : "";
12684 if(format.substr(0, 5) != "this."){
12685 format = "fm." + format + '(';
12687 format = 'this.call("'+ format.substr(5) + '", ';
12691 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12694 if (args && args.length) {
12695 // called with xxyx.yuu:(test,test)
12697 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12699 // raw.. - :raw modifier..
12700 return "'"+ sep + udef_st + name + ")"+sep+"'";
12704 // branched to use + in gecko and [].join() in others
12706 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12707 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12710 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12711 body.push(tpl.body.replace(/(\r\n|\n)/g,
12712 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12713 body.push("'].join('');};};");
12714 body = body.join('');
12717 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12719 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12726 * same as applyTemplate, except it's done to one of the subTemplates
12727 * when using named templates, you can do:
12729 * var str = pl.applySubTemplate('your-name', values);
12732 * @param {Number} id of the template
12733 * @param {Object} values to apply to template
12734 * @param {Object} parent (normaly the instance of this object)
12736 applySubTemplate : function(id, values, parent)
12740 var t = this.tpls[id];
12744 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12745 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12749 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12756 if(t.execCall && t.execCall.call(this, values, parent)){
12760 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12766 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12767 parent = t.target ? values : parent;
12768 if(t.forCall && vs instanceof Array){
12770 for(var i = 0, len = vs.length; i < len; i++){
12772 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12774 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12776 //Roo.log(t.compiled);
12780 return buf.join('');
12783 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12788 return t.compiled.call(this, vs, parent);
12790 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12792 //Roo.log(t.compiled);
12800 applyTemplate : function(values){
12801 return this.master.compiled.call(this, values, {});
12802 //var s = this.subs;
12805 apply : function(){
12806 return this.applyTemplate.apply(this, arguments);
12811 Roo.DomTemplate.from = function(el){
12812 el = Roo.getDom(el);
12813 return new Roo.Domtemplate(el.value || el.innerHTML);
12816 * Ext JS Library 1.1.1
12817 * Copyright(c) 2006-2007, Ext JS, LLC.
12819 * Originally Released Under LGPL - original licence link has changed is not relivant.
12822 * <script type="text/javascript">
12826 * @class Roo.util.DelayedTask
12827 * Provides a convenient method of performing setTimeout where a new
12828 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12829 * You can use this class to buffer
12830 * the keypress events for a certain number of milliseconds, and perform only if they stop
12831 * for that amount of time.
12832 * @constructor The parameters to this constructor serve as defaults and are not required.
12833 * @param {Function} fn (optional) The default function to timeout
12834 * @param {Object} scope (optional) The default scope of that timeout
12835 * @param {Array} args (optional) The default Array of arguments
12837 Roo.util.DelayedTask = function(fn, scope, args){
12838 var id = null, d, t;
12840 var call = function(){
12841 var now = new Date().getTime();
12845 fn.apply(scope, args || []);
12849 * Cancels any pending timeout and queues a new one
12850 * @param {Number} delay The milliseconds to delay
12851 * @param {Function} newFn (optional) Overrides function passed to constructor
12852 * @param {Object} newScope (optional) Overrides scope passed to constructor
12853 * @param {Array} newArgs (optional) Overrides args passed to constructor
12855 this.delay = function(delay, newFn, newScope, newArgs){
12856 if(id && delay != d){
12860 t = new Date().getTime();
12862 scope = newScope || scope;
12863 args = newArgs || args;
12865 id = setInterval(call, d);
12870 * Cancel the last queued timeout
12872 this.cancel = function(){
12880 * Ext JS Library 1.1.1
12881 * Copyright(c) 2006-2007, Ext JS, LLC.
12883 * Originally Released Under LGPL - original licence link has changed is not relivant.
12886 * <script type="text/javascript">
12890 Roo.util.TaskRunner = function(interval){
12891 interval = interval || 10;
12892 var tasks = [], removeQueue = [];
12894 var running = false;
12896 var stopThread = function(){
12902 var startThread = function(){
12905 id = setInterval(runTasks, interval);
12909 var removeTask = function(task){
12910 removeQueue.push(task);
12916 var runTasks = function(){
12917 if(removeQueue.length > 0){
12918 for(var i = 0, len = removeQueue.length; i < len; i++){
12919 tasks.remove(removeQueue[i]);
12922 if(tasks.length < 1){
12927 var now = new Date().getTime();
12928 for(var i = 0, len = tasks.length; i < len; ++i){
12930 var itime = now - t.taskRunTime;
12931 if(t.interval <= itime){
12932 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12933 t.taskRunTime = now;
12934 if(rt === false || t.taskRunCount === t.repeat){
12939 if(t.duration && t.duration <= (now - t.taskStartTime)){
12946 * Queues a new task.
12947 * @param {Object} task
12949 this.start = function(task){
12951 task.taskStartTime = new Date().getTime();
12952 task.taskRunTime = 0;
12953 task.taskRunCount = 0;
12958 this.stop = function(task){
12963 this.stopAll = function(){
12965 for(var i = 0, len = tasks.length; i < len; i++){
12966 if(tasks[i].onStop){
12975 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12977 * Ext JS Library 1.1.1
12978 * Copyright(c) 2006-2007, Ext JS, LLC.
12980 * Originally Released Under LGPL - original licence link has changed is not relivant.
12983 * <script type="text/javascript">
12988 * @class Roo.util.MixedCollection
12989 * @extends Roo.util.Observable
12990 * A Collection class that maintains both numeric indexes and keys and exposes events.
12992 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12993 * collection (defaults to false)
12994 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12995 * and return the key value for that item. This is used when available to look up the key on items that
12996 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12997 * equivalent to providing an implementation for the {@link #getKey} method.
12999 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13007 * Fires when the collection is cleared.
13012 * Fires when an item is added to the collection.
13013 * @param {Number} index The index at which the item was added.
13014 * @param {Object} o The item added.
13015 * @param {String} key The key associated with the added item.
13020 * Fires when an item is replaced in the collection.
13021 * @param {String} key he key associated with the new added.
13022 * @param {Object} old The item being replaced.
13023 * @param {Object} new The new item.
13028 * Fires when an item is removed from the collection.
13029 * @param {Object} o The item being removed.
13030 * @param {String} key (optional) The key associated with the removed item.
13035 this.allowFunctions = allowFunctions === true;
13037 this.getKey = keyFn;
13039 Roo.util.MixedCollection.superclass.constructor.call(this);
13042 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13043 allowFunctions : false,
13046 * Adds an item to the collection.
13047 * @param {String} key The key to associate with the item
13048 * @param {Object} o The item to add.
13049 * @return {Object} The item added.
13051 add : function(key, o){
13052 if(arguments.length == 1){
13054 key = this.getKey(o);
13056 if(typeof key == "undefined" || key === null){
13058 this.items.push(o);
13059 this.keys.push(null);
13061 var old = this.map[key];
13063 return this.replace(key, o);
13066 this.items.push(o);
13068 this.keys.push(key);
13070 this.fireEvent("add", this.length-1, o, key);
13075 * MixedCollection has a generic way to fetch keys if you implement getKey.
13078 var mc = new Roo.util.MixedCollection();
13079 mc.add(someEl.dom.id, someEl);
13080 mc.add(otherEl.dom.id, otherEl);
13084 var mc = new Roo.util.MixedCollection();
13085 mc.getKey = function(el){
13091 // or via the constructor
13092 var mc = new Roo.util.MixedCollection(false, function(el){
13098 * @param o {Object} The item for which to find the key.
13099 * @return {Object} The key for the passed item.
13101 getKey : function(o){
13106 * Replaces an item in the collection.
13107 * @param {String} key The key associated with the item to replace, or the item to replace.
13108 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13109 * @return {Object} The new item.
13111 replace : function(key, o){
13112 if(arguments.length == 1){
13114 key = this.getKey(o);
13116 var old = this.item(key);
13117 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13118 return this.add(key, o);
13120 var index = this.indexOfKey(key);
13121 this.items[index] = o;
13123 this.fireEvent("replace", key, old, o);
13128 * Adds all elements of an Array or an Object to the collection.
13129 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13130 * an Array of values, each of which are added to the collection.
13132 addAll : function(objs){
13133 if(arguments.length > 1 || objs instanceof Array){
13134 var args = arguments.length > 1 ? arguments : objs;
13135 for(var i = 0, len = args.length; i < len; i++){
13139 for(var key in objs){
13140 if(this.allowFunctions || typeof objs[key] != "function"){
13141 this.add(key, objs[key]);
13148 * Executes the specified function once for every item in the collection, passing each
13149 * item as the first and only parameter. returning false from the function will stop the iteration.
13150 * @param {Function} fn The function to execute for each item.
13151 * @param {Object} scope (optional) The scope in which to execute the function.
13153 each : function(fn, scope){
13154 var items = [].concat(this.items); // each safe for removal
13155 for(var i = 0, len = items.length; i < len; i++){
13156 if(fn.call(scope || items[i], items[i], i, len) === false){
13163 * Executes the specified function once for every key in the collection, passing each
13164 * key, and its associated item as the first two parameters.
13165 * @param {Function} fn The function to execute for each item.
13166 * @param {Object} scope (optional) The scope in which to execute the function.
13168 eachKey : function(fn, scope){
13169 for(var i = 0, len = this.keys.length; i < len; i++){
13170 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13175 * Returns the first item in the collection which elicits a true return value from the
13176 * passed selection function.
13177 * @param {Function} fn The selection function to execute for each item.
13178 * @param {Object} scope (optional) The scope in which to execute the function.
13179 * @return {Object} The first item in the collection which returned true from the selection function.
13181 find : function(fn, scope){
13182 for(var i = 0, len = this.items.length; i < len; i++){
13183 if(fn.call(scope || window, this.items[i], this.keys[i])){
13184 return this.items[i];
13191 * Inserts an item at the specified index in the collection.
13192 * @param {Number} index The index to insert the item at.
13193 * @param {String} key The key to associate with the new item, or the item itself.
13194 * @param {Object} o (optional) If the second parameter was a key, the new item.
13195 * @return {Object} The item inserted.
13197 insert : function(index, key, o){
13198 if(arguments.length == 2){
13200 key = this.getKey(o);
13202 if(index >= this.length){
13203 return this.add(key, o);
13206 this.items.splice(index, 0, o);
13207 if(typeof key != "undefined" && key != null){
13210 this.keys.splice(index, 0, key);
13211 this.fireEvent("add", index, o, key);
13216 * Removed an item from the collection.
13217 * @param {Object} o The item to remove.
13218 * @return {Object} The item removed.
13220 remove : function(o){
13221 return this.removeAt(this.indexOf(o));
13225 * Remove an item from a specified index in the collection.
13226 * @param {Number} index The index within the collection of the item to remove.
13228 removeAt : function(index){
13229 if(index < this.length && index >= 0){
13231 var o = this.items[index];
13232 this.items.splice(index, 1);
13233 var key = this.keys[index];
13234 if(typeof key != "undefined"){
13235 delete this.map[key];
13237 this.keys.splice(index, 1);
13238 this.fireEvent("remove", o, key);
13243 * Removed an item associated with the passed key fom the collection.
13244 * @param {String} key The key of the item to remove.
13246 removeKey : function(key){
13247 return this.removeAt(this.indexOfKey(key));
13251 * Returns the number of items in the collection.
13252 * @return {Number} the number of items in the collection.
13254 getCount : function(){
13255 return this.length;
13259 * Returns index within the collection of the passed Object.
13260 * @param {Object} o The item to find the index of.
13261 * @return {Number} index of the item.
13263 indexOf : function(o){
13264 if(!this.items.indexOf){
13265 for(var i = 0, len = this.items.length; i < len; i++){
13266 if(this.items[i] == o) {
13272 return this.items.indexOf(o);
13277 * Returns index within the collection of the passed key.
13278 * @param {String} key The key to find the index of.
13279 * @return {Number} index of the key.
13281 indexOfKey : function(key){
13282 if(!this.keys.indexOf){
13283 for(var i = 0, len = this.keys.length; i < len; i++){
13284 if(this.keys[i] == key) {
13290 return this.keys.indexOf(key);
13295 * Returns the item associated with the passed key OR index. Key has priority over index.
13296 * @param {String/Number} key The key or index of the item.
13297 * @return {Object} The item associated with the passed key.
13299 item : function(key){
13300 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13301 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13305 * Returns the item at the specified index.
13306 * @param {Number} index The index of the item.
13309 itemAt : function(index){
13310 return this.items[index];
13314 * Returns the item associated with the passed key.
13315 * @param {String/Number} key The key of the item.
13316 * @return {Object} The item associated with the passed key.
13318 key : function(key){
13319 return this.map[key];
13323 * Returns true if the collection contains the passed Object as an item.
13324 * @param {Object} o The Object to look for in the collection.
13325 * @return {Boolean} True if the collection contains the Object as an item.
13327 contains : function(o){
13328 return this.indexOf(o) != -1;
13332 * Returns true if the collection contains the passed Object as a key.
13333 * @param {String} key The key to look for in the collection.
13334 * @return {Boolean} True if the collection contains the Object as a key.
13336 containsKey : function(key){
13337 return typeof this.map[key] != "undefined";
13341 * Removes all items from the collection.
13343 clear : function(){
13348 this.fireEvent("clear");
13352 * Returns the first item in the collection.
13353 * @return {Object} the first item in the collection..
13355 first : function(){
13356 return this.items[0];
13360 * Returns the last item in the collection.
13361 * @return {Object} the last item in the collection..
13364 return this.items[this.length-1];
13367 _sort : function(property, dir, fn){
13368 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13369 fn = fn || function(a, b){
13372 var c = [], k = this.keys, items = this.items;
13373 for(var i = 0, len = items.length; i < len; i++){
13374 c[c.length] = {key: k[i], value: items[i], index: i};
13376 c.sort(function(a, b){
13377 var v = fn(a[property], b[property]) * dsc;
13379 v = (a.index < b.index ? -1 : 1);
13383 for(var i = 0, len = c.length; i < len; i++){
13384 items[i] = c[i].value;
13387 this.fireEvent("sort", this);
13391 * Sorts this collection with the passed comparison function
13392 * @param {String} direction (optional) "ASC" or "DESC"
13393 * @param {Function} fn (optional) comparison function
13395 sort : function(dir, fn){
13396 this._sort("value", dir, fn);
13400 * Sorts this collection by keys
13401 * @param {String} direction (optional) "ASC" or "DESC"
13402 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13404 keySort : function(dir, fn){
13405 this._sort("key", dir, fn || function(a, b){
13406 return String(a).toUpperCase()-String(b).toUpperCase();
13411 * Returns a range of items in this collection
13412 * @param {Number} startIndex (optional) defaults to 0
13413 * @param {Number} endIndex (optional) default to the last item
13414 * @return {Array} An array of items
13416 getRange : function(start, end){
13417 var items = this.items;
13418 if(items.length < 1){
13421 start = start || 0;
13422 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13425 for(var i = start; i <= end; i++) {
13426 r[r.length] = items[i];
13429 for(var i = start; i >= end; i--) {
13430 r[r.length] = items[i];
13437 * Filter the <i>objects</i> in this collection by a specific property.
13438 * Returns a new collection that has been filtered.
13439 * @param {String} property A property on your objects
13440 * @param {String/RegExp} value Either string that the property values
13441 * should start with or a RegExp to test against the property
13442 * @return {MixedCollection} The new filtered collection
13444 filter : function(property, value){
13445 if(!value.exec){ // not a regex
13446 value = String(value);
13447 if(value.length == 0){
13448 return this.clone();
13450 value = new RegExp("^" + Roo.escapeRe(value), "i");
13452 return this.filterBy(function(o){
13453 return o && value.test(o[property]);
13458 * Filter by a function. * Returns a new collection that has been filtered.
13459 * The passed function will be called with each
13460 * object in the collection. If the function returns true, the value is included
13461 * otherwise it is filtered.
13462 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13463 * @param {Object} scope (optional) The scope of the function (defaults to this)
13464 * @return {MixedCollection} The new filtered collection
13466 filterBy : function(fn, scope){
13467 var r = new Roo.util.MixedCollection();
13468 r.getKey = this.getKey;
13469 var k = this.keys, it = this.items;
13470 for(var i = 0, len = it.length; i < len; i++){
13471 if(fn.call(scope||this, it[i], k[i])){
13472 r.add(k[i], it[i]);
13479 * Creates a duplicate of this collection
13480 * @return {MixedCollection}
13482 clone : function(){
13483 var r = new Roo.util.MixedCollection();
13484 var k = this.keys, it = this.items;
13485 for(var i = 0, len = it.length; i < len; i++){
13486 r.add(k[i], it[i]);
13488 r.getKey = this.getKey;
13493 * Returns the item associated with the passed key or index.
13495 * @param {String/Number} key The key or index of the item.
13496 * @return {Object} The item associated with the passed key.
13498 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13500 * Ext JS Library 1.1.1
13501 * Copyright(c) 2006-2007, Ext JS, LLC.
13503 * Originally Released Under LGPL - original licence link has changed is not relivant.
13506 * <script type="text/javascript">
13509 * @class Roo.util.JSON
13510 * Modified version of Douglas Crockford"s json.js that doesn"t
13511 * mess with the Object prototype
13512 * http://www.json.org/js.html
13515 Roo.util.JSON = new (function(){
13516 var useHasOwn = {}.hasOwnProperty ? true : false;
13518 // crashes Safari in some instances
13519 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13521 var pad = function(n) {
13522 return n < 10 ? "0" + n : n;
13535 var encodeString = function(s){
13536 if (/["\\\x00-\x1f]/.test(s)) {
13537 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13542 c = b.charCodeAt();
13544 Math.floor(c / 16).toString(16) +
13545 (c % 16).toString(16);
13548 return '"' + s + '"';
13551 var encodeArray = function(o){
13552 var a = ["["], b, i, l = o.length, v;
13553 for (i = 0; i < l; i += 1) {
13555 switch (typeof v) {
13564 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13572 var encodeDate = function(o){
13573 return '"' + o.getFullYear() + "-" +
13574 pad(o.getMonth() + 1) + "-" +
13575 pad(o.getDate()) + "T" +
13576 pad(o.getHours()) + ":" +
13577 pad(o.getMinutes()) + ":" +
13578 pad(o.getSeconds()) + '"';
13582 * Encodes an Object, Array or other value
13583 * @param {Mixed} o The variable to encode
13584 * @return {String} The JSON string
13586 this.encode = function(o)
13588 // should this be extended to fully wrap stringify..
13590 if(typeof o == "undefined" || o === null){
13592 }else if(o instanceof Array){
13593 return encodeArray(o);
13594 }else if(o instanceof Date){
13595 return encodeDate(o);
13596 }else if(typeof o == "string"){
13597 return encodeString(o);
13598 }else if(typeof o == "number"){
13599 return isFinite(o) ? String(o) : "null";
13600 }else if(typeof o == "boolean"){
13603 var a = ["{"], b, i, v;
13605 if(!useHasOwn || o.hasOwnProperty(i)) {
13607 switch (typeof v) {
13616 a.push(this.encode(i), ":",
13617 v === null ? "null" : this.encode(v));
13628 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13629 * @param {String} json The JSON string
13630 * @return {Object} The resulting object
13632 this.decode = function(json){
13634 return /** eval:var:json */ eval("(" + json + ')');
13638 * Shorthand for {@link Roo.util.JSON#encode}
13639 * @member Roo encode
13641 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13643 * Shorthand for {@link Roo.util.JSON#decode}
13644 * @member Roo decode
13646 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13649 * Ext JS Library 1.1.1
13650 * Copyright(c) 2006-2007, Ext JS, LLC.
13652 * Originally Released Under LGPL - original licence link has changed is not relivant.
13655 * <script type="text/javascript">
13659 * @class Roo.util.Format
13660 * Reusable data formatting functions
13663 Roo.util.Format = function(){
13664 var trimRe = /^\s+|\s+$/g;
13667 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13668 * @param {String} value The string to truncate
13669 * @param {Number} length The maximum length to allow before truncating
13670 * @return {String} The converted text
13672 ellipsis : function(value, len){
13673 if(value && value.length > len){
13674 return value.substr(0, len-3)+"...";
13680 * Checks a reference and converts it to empty string if it is undefined
13681 * @param {Mixed} value Reference to check
13682 * @return {Mixed} Empty string if converted, otherwise the original value
13684 undef : function(value){
13685 return typeof value != "undefined" ? value : "";
13689 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13690 * @param {String} value The string to encode
13691 * @return {String} The encoded text
13693 htmlEncode : function(value){
13694 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13698 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13699 * @param {String} value The string to decode
13700 * @return {String} The decoded text
13702 htmlDecode : function(value){
13703 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13707 * Trims any whitespace from either side of a string
13708 * @param {String} value The text to trim
13709 * @return {String} The trimmed text
13711 trim : function(value){
13712 return String(value).replace(trimRe, "");
13716 * Returns a substring from within an original string
13717 * @param {String} value The original text
13718 * @param {Number} start The start index of the substring
13719 * @param {Number} length The length of the substring
13720 * @return {String} The substring
13722 substr : function(value, start, length){
13723 return String(value).substr(start, length);
13727 * Converts a string to all lower case letters
13728 * @param {String} value The text to convert
13729 * @return {String} The converted text
13731 lowercase : function(value){
13732 return String(value).toLowerCase();
13736 * Converts a string to all upper case letters
13737 * @param {String} value The text to convert
13738 * @return {String} The converted text
13740 uppercase : function(value){
13741 return String(value).toUpperCase();
13745 * Converts the first character only of a string to upper case
13746 * @param {String} value The text to convert
13747 * @return {String} The converted text
13749 capitalize : function(value){
13750 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13754 call : function(value, fn){
13755 if(arguments.length > 2){
13756 var args = Array.prototype.slice.call(arguments, 2);
13757 args.unshift(value);
13759 return /** eval:var:value */ eval(fn).apply(window, args);
13761 /** eval:var:value */
13762 return /** eval:var:value */ eval(fn).call(window, value);
13768 * safer version of Math.toFixed..??/
13769 * @param {Number/String} value The numeric value to format
13770 * @param {Number/String} value Decimal places
13771 * @return {String} The formatted currency string
13773 toFixed : function(v, n)
13775 // why not use to fixed - precision is buggered???
13777 return Math.round(v-0);
13779 var fact = Math.pow(10,n+1);
13780 v = (Math.round((v-0)*fact))/fact;
13781 var z = (''+fact).substring(2);
13782 if (v == Math.floor(v)) {
13783 return Math.floor(v) + '.' + z;
13786 // now just padd decimals..
13787 var ps = String(v).split('.');
13788 var fd = (ps[1] + z);
13789 var r = fd.substring(0,n);
13790 var rm = fd.substring(n);
13792 return ps[0] + '.' + r;
13794 r*=1; // turn it into a number;
13796 if (String(r).length != n) {
13799 r = String(r).substring(1); // chop the end off.
13802 return ps[0] + '.' + r;
13807 * Format a number as US currency
13808 * @param {Number/String} value The numeric value to format
13809 * @return {String} The formatted currency string
13811 usMoney : function(v){
13812 return '$' + Roo.util.Format.number(v);
13817 * eventually this should probably emulate php's number_format
13818 * @param {Number/String} value The numeric value to format
13819 * @param {Number} decimals number of decimal places
13820 * @param {String} delimiter for thousands (default comma)
13821 * @return {String} The formatted currency string
13823 number : function(v, decimals, thousandsDelimiter)
13825 // multiply and round.
13826 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13827 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13829 var mul = Math.pow(10, decimals);
13830 var zero = String(mul).substring(1);
13831 v = (Math.round((v-0)*mul))/mul;
13833 // if it's '0' number.. then
13835 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13837 var ps = v.split('.');
13840 var r = /(\d+)(\d{3})/;
13843 if(thousandsDelimiter.length != 0) {
13844 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13849 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13850 // does not have decimals
13851 (decimals ? ('.' + zero) : '');
13854 return whole + sub ;
13858 * Parse a value into a formatted date using the specified format pattern.
13859 * @param {Mixed} value The value to format
13860 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13861 * @return {String} The formatted date string
13863 date : function(v, format){
13867 if(!(v instanceof Date)){
13868 v = new Date(Date.parse(v));
13870 return v.dateFormat(format || Roo.util.Format.defaults.date);
13874 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13875 * @param {String} format Any valid date format string
13876 * @return {Function} The date formatting function
13878 dateRenderer : function(format){
13879 return function(v){
13880 return Roo.util.Format.date(v, format);
13885 stripTagsRE : /<\/?[^>]+>/gi,
13888 * Strips all HTML tags
13889 * @param {Mixed} value The text from which to strip tags
13890 * @return {String} The stripped text
13892 stripTags : function(v){
13893 return !v ? v : String(v).replace(this.stripTagsRE, "");
13897 Roo.util.Format.defaults = {
13901 * Ext JS Library 1.1.1
13902 * Copyright(c) 2006-2007, Ext JS, LLC.
13904 * Originally Released Under LGPL - original licence link has changed is not relivant.
13907 * <script type="text/javascript">
13914 * @class Roo.MasterTemplate
13915 * @extends Roo.Template
13916 * Provides a template that can have child templates. The syntax is:
13918 var t = new Roo.MasterTemplate(
13919 '<select name="{name}">',
13920 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13923 t.add('options', {value: 'foo', text: 'bar'});
13924 // or you can add multiple child elements in one shot
13925 t.addAll('options', [
13926 {value: 'foo', text: 'bar'},
13927 {value: 'foo2', text: 'bar2'},
13928 {value: 'foo3', text: 'bar3'}
13930 // then append, applying the master template values
13931 t.append('my-form', {name: 'my-select'});
13933 * A name attribute for the child template is not required if you have only one child
13934 * template or you want to refer to them by index.
13936 Roo.MasterTemplate = function(){
13937 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13938 this.originalHtml = this.html;
13940 var m, re = this.subTemplateRe;
13943 while(m = re.exec(this.html)){
13944 var name = m[1], content = m[2];
13949 tpl : new Roo.Template(content)
13952 st[name] = st[subIndex];
13954 st[subIndex].tpl.compile();
13955 st[subIndex].tpl.call = this.call.createDelegate(this);
13958 this.subCount = subIndex;
13961 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13963 * The regular expression used to match sub templates
13967 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13970 * Applies the passed values to a child template.
13971 * @param {String/Number} name (optional) The name or index of the child template
13972 * @param {Array/Object} values The values to be applied to the template
13973 * @return {MasterTemplate} this
13975 add : function(name, values){
13976 if(arguments.length == 1){
13977 values = arguments[0];
13980 var s = this.subs[name];
13981 s.buffer[s.buffer.length] = s.tpl.apply(values);
13986 * Applies all the passed values to a child template.
13987 * @param {String/Number} name (optional) The name or index of the child template
13988 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13989 * @param {Boolean} reset (optional) True to reset the template first
13990 * @return {MasterTemplate} this
13992 fill : function(name, values, reset){
13994 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14002 for(var i = 0, len = values.length; i < len; i++){
14003 this.add(name, values[i]);
14009 * Resets the template for reuse
14010 * @return {MasterTemplate} this
14012 reset : function(){
14014 for(var i = 0; i < this.subCount; i++){
14020 applyTemplate : function(values){
14022 var replaceIndex = -1;
14023 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14024 return s[++replaceIndex].buffer.join("");
14026 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14029 apply : function(){
14030 return this.applyTemplate.apply(this, arguments);
14033 compile : function(){return this;}
14037 * Alias for fill().
14040 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14042 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14043 * var tpl = Roo.MasterTemplate.from('element-id');
14044 * @param {String/HTMLElement} el
14045 * @param {Object} config
14048 Roo.MasterTemplate.from = function(el, config){
14049 el = Roo.getDom(el);
14050 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14053 * Ext JS Library 1.1.1
14054 * Copyright(c) 2006-2007, Ext JS, LLC.
14056 * Originally Released Under LGPL - original licence link has changed is not relivant.
14059 * <script type="text/javascript">
14064 * @class Roo.util.CSS
14065 * Utility class for manipulating CSS rules
14068 Roo.util.CSS = function(){
14070 var doc = document;
14072 var camelRe = /(-[a-z])/gi;
14073 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14077 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14078 * tag and appended to the HEAD of the document.
14079 * @param {String|Object} cssText The text containing the css rules
14080 * @param {String} id An id to add to the stylesheet for later removal
14081 * @return {StyleSheet}
14083 createStyleSheet : function(cssText, id){
14085 var head = doc.getElementsByTagName("head")[0];
14086 var nrules = doc.createElement("style");
14087 nrules.setAttribute("type", "text/css");
14089 nrules.setAttribute("id", id);
14091 if (typeof(cssText) != 'string') {
14092 // support object maps..
14093 // not sure if this a good idea..
14094 // perhaps it should be merged with the general css handling
14095 // and handle js style props.
14096 var cssTextNew = [];
14097 for(var n in cssText) {
14099 for(var k in cssText[n]) {
14100 citems.push( k + ' : ' +cssText[n][k] + ';' );
14102 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14105 cssText = cssTextNew.join("\n");
14111 head.appendChild(nrules);
14112 ss = nrules.styleSheet;
14113 ss.cssText = cssText;
14116 nrules.appendChild(doc.createTextNode(cssText));
14118 nrules.cssText = cssText;
14120 head.appendChild(nrules);
14121 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14123 this.cacheStyleSheet(ss);
14128 * Removes a style or link tag by id
14129 * @param {String} id The id of the tag
14131 removeStyleSheet : function(id){
14132 var existing = doc.getElementById(id);
14134 existing.parentNode.removeChild(existing);
14139 * Dynamically swaps an existing stylesheet reference for a new one
14140 * @param {String} id The id of an existing link tag to remove
14141 * @param {String} url The href of the new stylesheet to include
14143 swapStyleSheet : function(id, url){
14144 this.removeStyleSheet(id);
14145 var ss = doc.createElement("link");
14146 ss.setAttribute("rel", "stylesheet");
14147 ss.setAttribute("type", "text/css");
14148 ss.setAttribute("id", id);
14149 ss.setAttribute("href", url);
14150 doc.getElementsByTagName("head")[0].appendChild(ss);
14154 * Refresh the rule cache if you have dynamically added stylesheets
14155 * @return {Object} An object (hash) of rules indexed by selector
14157 refreshCache : function(){
14158 return this.getRules(true);
14162 cacheStyleSheet : function(stylesheet){
14166 try{// try catch for cross domain access issue
14167 var ssRules = stylesheet.cssRules || stylesheet.rules;
14168 for(var j = ssRules.length-1; j >= 0; --j){
14169 rules[ssRules[j].selectorText] = ssRules[j];
14175 * Gets all css rules for the document
14176 * @param {Boolean} refreshCache true to refresh the internal cache
14177 * @return {Object} An object (hash) of rules indexed by selector
14179 getRules : function(refreshCache){
14180 if(rules == null || refreshCache){
14182 var ds = doc.styleSheets;
14183 for(var i =0, len = ds.length; i < len; i++){
14185 this.cacheStyleSheet(ds[i]);
14193 * Gets an an individual CSS rule by selector(s)
14194 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14195 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14196 * @return {CSSRule} The CSS rule or null if one is not found
14198 getRule : function(selector, refreshCache){
14199 var rs = this.getRules(refreshCache);
14200 if(!(selector instanceof Array)){
14201 return rs[selector];
14203 for(var i = 0; i < selector.length; i++){
14204 if(rs[selector[i]]){
14205 return rs[selector[i]];
14213 * Updates a rule property
14214 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14215 * @param {String} property The css property
14216 * @param {String} value The new value for the property
14217 * @return {Boolean} true If a rule was found and updated
14219 updateRule : function(selector, property, value){
14220 if(!(selector instanceof Array)){
14221 var rule = this.getRule(selector);
14223 rule.style[property.replace(camelRe, camelFn)] = value;
14227 for(var i = 0; i < selector.length; i++){
14228 if(this.updateRule(selector[i], property, value)){
14238 * Ext JS Library 1.1.1
14239 * Copyright(c) 2006-2007, Ext JS, LLC.
14241 * Originally Released Under LGPL - original licence link has changed is not relivant.
14244 * <script type="text/javascript">
14250 * @class Roo.util.ClickRepeater
14251 * @extends Roo.util.Observable
14253 * A wrapper class which can be applied to any element. Fires a "click" event while the
14254 * mouse is pressed. The interval between firings may be specified in the config but
14255 * defaults to 10 milliseconds.
14257 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14259 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14260 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14261 * Similar to an autorepeat key delay.
14262 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14263 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14264 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14265 * "interval" and "delay" are ignored. "immediate" is honored.
14266 * @cfg {Boolean} preventDefault True to prevent the default click event
14267 * @cfg {Boolean} stopDefault True to stop the default click event
14270 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14271 * 2007-02-02 jvs Renamed to ClickRepeater
14272 * 2007-02-03 jvs Modifications for FF Mac and Safari
14275 * @param {String/HTMLElement/Element} el The element to listen on
14276 * @param {Object} config
14278 Roo.util.ClickRepeater = function(el, config)
14280 this.el = Roo.get(el);
14281 this.el.unselectable();
14283 Roo.apply(this, config);
14288 * Fires when the mouse button is depressed.
14289 * @param {Roo.util.ClickRepeater} this
14291 "mousedown" : true,
14294 * Fires on a specified interval during the time the element is pressed.
14295 * @param {Roo.util.ClickRepeater} this
14300 * Fires when the mouse key is released.
14301 * @param {Roo.util.ClickRepeater} this
14306 this.el.on("mousedown", this.handleMouseDown, this);
14307 if(this.preventDefault || this.stopDefault){
14308 this.el.on("click", function(e){
14309 if(this.preventDefault){
14310 e.preventDefault();
14312 if(this.stopDefault){
14318 // allow inline handler
14320 this.on("click", this.handler, this.scope || this);
14323 Roo.util.ClickRepeater.superclass.constructor.call(this);
14326 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14329 preventDefault : true,
14330 stopDefault : false,
14334 handleMouseDown : function(){
14335 clearTimeout(this.timer);
14337 if(this.pressClass){
14338 this.el.addClass(this.pressClass);
14340 this.mousedownTime = new Date();
14342 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14343 this.el.on("mouseout", this.handleMouseOut, this);
14345 this.fireEvent("mousedown", this);
14346 this.fireEvent("click", this);
14348 this.timer = this.click.defer(this.delay || this.interval, this);
14352 click : function(){
14353 this.fireEvent("click", this);
14354 this.timer = this.click.defer(this.getInterval(), this);
14358 getInterval: function(){
14359 if(!this.accelerate){
14360 return this.interval;
14362 var pressTime = this.mousedownTime.getElapsed();
14363 if(pressTime < 500){
14365 }else if(pressTime < 1700){
14367 }else if(pressTime < 2600){
14369 }else if(pressTime < 3500){
14371 }else if(pressTime < 4400){
14373 }else if(pressTime < 5300){
14375 }else if(pressTime < 6200){
14383 handleMouseOut : function(){
14384 clearTimeout(this.timer);
14385 if(this.pressClass){
14386 this.el.removeClass(this.pressClass);
14388 this.el.on("mouseover", this.handleMouseReturn, this);
14392 handleMouseReturn : function(){
14393 this.el.un("mouseover", this.handleMouseReturn);
14394 if(this.pressClass){
14395 this.el.addClass(this.pressClass);
14401 handleMouseUp : function(){
14402 clearTimeout(this.timer);
14403 this.el.un("mouseover", this.handleMouseReturn);
14404 this.el.un("mouseout", this.handleMouseOut);
14405 Roo.get(document).un("mouseup", this.handleMouseUp);
14406 this.el.removeClass(this.pressClass);
14407 this.fireEvent("mouseup", this);
14411 * Ext JS Library 1.1.1
14412 * Copyright(c) 2006-2007, Ext JS, LLC.
14414 * Originally Released Under LGPL - original licence link has changed is not relivant.
14417 * <script type="text/javascript">
14422 * @class Roo.KeyNav
14423 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14424 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14425 * way to implement custom navigation schemes for any UI component.</p>
14426 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14427 * pageUp, pageDown, del, home, end. Usage:</p>
14429 var nav = new Roo.KeyNav("my-element", {
14430 "left" : function(e){
14431 this.moveLeft(e.ctrlKey);
14433 "right" : function(e){
14434 this.moveRight(e.ctrlKey);
14436 "enter" : function(e){
14443 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14444 * @param {Object} config The config
14446 Roo.KeyNav = function(el, config){
14447 this.el = Roo.get(el);
14448 Roo.apply(this, config);
14449 if(!this.disabled){
14450 this.disabled = true;
14455 Roo.KeyNav.prototype = {
14457 * @cfg {Boolean} disabled
14458 * True to disable this KeyNav instance (defaults to false)
14462 * @cfg {String} defaultEventAction
14463 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14464 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14465 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14467 defaultEventAction: "stopEvent",
14469 * @cfg {Boolean} forceKeyDown
14470 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14471 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14472 * handle keydown instead of keypress.
14474 forceKeyDown : false,
14477 prepareEvent : function(e){
14478 var k = e.getKey();
14479 var h = this.keyToHandler[k];
14480 //if(h && this[h]){
14481 // e.stopPropagation();
14483 if(Roo.isSafari && h && k >= 37 && k <= 40){
14489 relay : function(e){
14490 var k = e.getKey();
14491 var h = this.keyToHandler[k];
14493 if(this.doRelay(e, this[h], h) !== true){
14494 e[this.defaultEventAction]();
14500 doRelay : function(e, h, hname){
14501 return h.call(this.scope || this, e);
14504 // possible handlers
14518 // quick lookup hash
14535 * Enable this KeyNav
14537 enable: function(){
14539 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14540 // the EventObject will normalize Safari automatically
14541 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14542 this.el.on("keydown", this.relay, this);
14544 this.el.on("keydown", this.prepareEvent, this);
14545 this.el.on("keypress", this.relay, this);
14547 this.disabled = false;
14552 * Disable this KeyNav
14554 disable: function(){
14555 if(!this.disabled){
14556 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14557 this.el.un("keydown", this.relay);
14559 this.el.un("keydown", this.prepareEvent);
14560 this.el.un("keypress", this.relay);
14562 this.disabled = true;
14567 * Ext JS Library 1.1.1
14568 * Copyright(c) 2006-2007, Ext JS, LLC.
14570 * Originally Released Under LGPL - original licence link has changed is not relivant.
14573 * <script type="text/javascript">
14578 * @class Roo.KeyMap
14579 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14580 * The constructor accepts the same config object as defined by {@link #addBinding}.
14581 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14582 * combination it will call the function with this signature (if the match is a multi-key
14583 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14584 * A KeyMap can also handle a string representation of keys.<br />
14587 // map one key by key code
14588 var map = new Roo.KeyMap("my-element", {
14589 key: 13, // or Roo.EventObject.ENTER
14594 // map multiple keys to one action by string
14595 var map = new Roo.KeyMap("my-element", {
14601 // map multiple keys to multiple actions by strings and array of codes
14602 var map = new Roo.KeyMap("my-element", [
14605 fn: function(){ alert("Return was pressed"); }
14608 fn: function(){ alert('a, b or c was pressed'); }
14613 fn: function(){ alert('Control + shift + tab was pressed.'); }
14617 * <b>Note: A KeyMap starts enabled</b>
14619 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14620 * @param {Object} config The config (see {@link #addBinding})
14621 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14623 Roo.KeyMap = function(el, config, eventName){
14624 this.el = Roo.get(el);
14625 this.eventName = eventName || "keydown";
14626 this.bindings = [];
14628 this.addBinding(config);
14633 Roo.KeyMap.prototype = {
14635 * True to stop the event from bubbling and prevent the default browser action if the
14636 * key was handled by the KeyMap (defaults to false)
14642 * Add a new binding to this KeyMap. The following config object properties are supported:
14644 Property Type Description
14645 ---------- --------------- ----------------------------------------------------------------------
14646 key String/Array A single keycode or an array of keycodes to handle
14647 shift Boolean True to handle key only when shift is pressed (defaults to false)
14648 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14649 alt Boolean True to handle key only when alt is pressed (defaults to false)
14650 fn Function The function to call when KeyMap finds the expected key combination
14651 scope Object The scope of the callback function
14657 var map = new Roo.KeyMap(document, {
14658 key: Roo.EventObject.ENTER,
14663 //Add a new binding to the existing KeyMap later
14671 * @param {Object/Array} config A single KeyMap config or an array of configs
14673 addBinding : function(config){
14674 if(config instanceof Array){
14675 for(var i = 0, len = config.length; i < len; i++){
14676 this.addBinding(config[i]);
14680 var keyCode = config.key,
14681 shift = config.shift,
14682 ctrl = config.ctrl,
14685 scope = config.scope;
14686 if(typeof keyCode == "string"){
14688 var keyString = keyCode.toUpperCase();
14689 for(var j = 0, len = keyString.length; j < len; j++){
14690 ks.push(keyString.charCodeAt(j));
14694 var keyArray = keyCode instanceof Array;
14695 var handler = function(e){
14696 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14697 var k = e.getKey();
14699 for(var i = 0, len = keyCode.length; i < len; i++){
14700 if(keyCode[i] == k){
14701 if(this.stopEvent){
14704 fn.call(scope || window, k, e);
14710 if(this.stopEvent){
14713 fn.call(scope || window, k, e);
14718 this.bindings.push(handler);
14722 * Shorthand for adding a single key listener
14723 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14724 * following options:
14725 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14726 * @param {Function} fn The function to call
14727 * @param {Object} scope (optional) The scope of the function
14729 on : function(key, fn, scope){
14730 var keyCode, shift, ctrl, alt;
14731 if(typeof key == "object" && !(key instanceof Array)){
14750 handleKeyDown : function(e){
14751 if(this.enabled){ //just in case
14752 var b = this.bindings;
14753 for(var i = 0, len = b.length; i < len; i++){
14754 b[i].call(this, e);
14760 * Returns true if this KeyMap is enabled
14761 * @return {Boolean}
14763 isEnabled : function(){
14764 return this.enabled;
14768 * Enables this KeyMap
14770 enable: function(){
14772 this.el.on(this.eventName, this.handleKeyDown, this);
14773 this.enabled = true;
14778 * Disable this KeyMap
14780 disable: function(){
14782 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14783 this.enabled = false;
14788 * Ext JS Library 1.1.1
14789 * Copyright(c) 2006-2007, Ext JS, LLC.
14791 * Originally Released Under LGPL - original licence link has changed is not relivant.
14794 * <script type="text/javascript">
14799 * @class Roo.util.TextMetrics
14800 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14801 * wide, in pixels, a given block of text will be.
14804 Roo.util.TextMetrics = function(){
14808 * Measures the size of the specified text
14809 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14810 * that can affect the size of the rendered text
14811 * @param {String} text The text to measure
14812 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14813 * in order to accurately measure the text height
14814 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14816 measure : function(el, text, fixedWidth){
14818 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14821 shared.setFixedWidth(fixedWidth || 'auto');
14822 return shared.getSize(text);
14826 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14827 * the overhead of multiple calls to initialize the style properties on each measurement.
14828 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14829 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14830 * in order to accurately measure the text height
14831 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14833 createInstance : function(el, fixedWidth){
14834 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14841 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14842 var ml = new Roo.Element(document.createElement('div'));
14843 document.body.appendChild(ml.dom);
14844 ml.position('absolute');
14845 ml.setLeftTop(-1000, -1000);
14849 ml.setWidth(fixedWidth);
14854 * Returns the size of the specified text based on the internal element's style and width properties
14855 * @memberOf Roo.util.TextMetrics.Instance#
14856 * @param {String} text The text to measure
14857 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14859 getSize : function(text){
14861 var s = ml.getSize();
14867 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14868 * that can affect the size of the rendered text
14869 * @memberOf Roo.util.TextMetrics.Instance#
14870 * @param {String/HTMLElement} el The element, dom node or id
14872 bind : function(el){
14874 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14879 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14880 * to set a fixed width in order to accurately measure the text height.
14881 * @memberOf Roo.util.TextMetrics.Instance#
14882 * @param {Number} width The width to set on the element
14884 setFixedWidth : function(width){
14885 ml.setWidth(width);
14889 * Returns the measured width of the specified text
14890 * @memberOf Roo.util.TextMetrics.Instance#
14891 * @param {String} text The text to measure
14892 * @return {Number} width The width in pixels
14894 getWidth : function(text){
14895 ml.dom.style.width = 'auto';
14896 return this.getSize(text).width;
14900 * Returns the measured height of the specified text. For multiline text, be sure to call
14901 * {@link #setFixedWidth} if necessary.
14902 * @memberOf Roo.util.TextMetrics.Instance#
14903 * @param {String} text The text to measure
14904 * @return {Number} height The height in pixels
14906 getHeight : function(text){
14907 return this.getSize(text).height;
14911 instance.bind(bindTo);
14916 // backwards compat
14917 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14919 * Ext JS Library 1.1.1
14920 * Copyright(c) 2006-2007, Ext JS, LLC.
14922 * Originally Released Under LGPL - original licence link has changed is not relivant.
14925 * <script type="text/javascript">
14929 * @class Roo.state.Provider
14930 * Abstract base class for state provider implementations. This class provides methods
14931 * for encoding and decoding <b>typed</b> variables including dates and defines the
14932 * Provider interface.
14934 Roo.state.Provider = function(){
14936 * @event statechange
14937 * Fires when a state change occurs.
14938 * @param {Provider} this This state provider
14939 * @param {String} key The state key which was changed
14940 * @param {String} value The encoded value for the state
14943 "statechange": true
14946 Roo.state.Provider.superclass.constructor.call(this);
14948 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14950 * Returns the current value for a key
14951 * @param {String} name The key name
14952 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14953 * @return {Mixed} The state data
14955 get : function(name, defaultValue){
14956 return typeof this.state[name] == "undefined" ?
14957 defaultValue : this.state[name];
14961 * Clears a value from the state
14962 * @param {String} name The key name
14964 clear : function(name){
14965 delete this.state[name];
14966 this.fireEvent("statechange", this, name, null);
14970 * Sets the value for a key
14971 * @param {String} name The key name
14972 * @param {Mixed} value The value to set
14974 set : function(name, value){
14975 this.state[name] = value;
14976 this.fireEvent("statechange", this, name, value);
14980 * Decodes a string previously encoded with {@link #encodeValue}.
14981 * @param {String} value The value to decode
14982 * @return {Mixed} The decoded value
14984 decodeValue : function(cookie){
14985 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14986 var matches = re.exec(unescape(cookie));
14987 if(!matches || !matches[1]) {
14988 return; // non state cookie
14990 var type = matches[1];
14991 var v = matches[2];
14994 return parseFloat(v);
14996 return new Date(Date.parse(v));
15001 var values = v.split("^");
15002 for(var i = 0, len = values.length; i < len; i++){
15003 all.push(this.decodeValue(values[i]));
15008 var values = v.split("^");
15009 for(var i = 0, len = values.length; i < len; i++){
15010 var kv = values[i].split("=");
15011 all[kv[0]] = this.decodeValue(kv[1]);
15020 * Encodes a value including type information. Decode with {@link #decodeValue}.
15021 * @param {Mixed} value The value to encode
15022 * @return {String} The encoded value
15024 encodeValue : function(v){
15026 if(typeof v == "number"){
15028 }else if(typeof v == "boolean"){
15029 enc = "b:" + (v ? "1" : "0");
15030 }else if(v instanceof Date){
15031 enc = "d:" + v.toGMTString();
15032 }else if(v instanceof Array){
15034 for(var i = 0, len = v.length; i < len; i++){
15035 flat += this.encodeValue(v[i]);
15041 }else if(typeof v == "object"){
15044 if(typeof v[key] != "function"){
15045 flat += key + "=" + this.encodeValue(v[key]) + "^";
15048 enc = "o:" + flat.substring(0, flat.length-1);
15052 return escape(enc);
15058 * Ext JS Library 1.1.1
15059 * Copyright(c) 2006-2007, Ext JS, LLC.
15061 * Originally Released Under LGPL - original licence link has changed is not relivant.
15064 * <script type="text/javascript">
15067 * @class Roo.state.Manager
15068 * This is the global state manager. By default all components that are "state aware" check this class
15069 * for state information if you don't pass them a custom state provider. In order for this class
15070 * to be useful, it must be initialized with a provider when your application initializes.
15072 // in your initialization function
15074 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15076 // supposed you have a {@link Roo.BorderLayout}
15077 var layout = new Roo.BorderLayout(...);
15078 layout.restoreState();
15079 // or a {Roo.BasicDialog}
15080 var dialog = new Roo.BasicDialog(...);
15081 dialog.restoreState();
15085 Roo.state.Manager = function(){
15086 var provider = new Roo.state.Provider();
15090 * Configures the default state provider for your application
15091 * @param {Provider} stateProvider The state provider to set
15093 setProvider : function(stateProvider){
15094 provider = stateProvider;
15098 * Returns the current value for a key
15099 * @param {String} name The key name
15100 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15101 * @return {Mixed} The state data
15103 get : function(key, defaultValue){
15104 return provider.get(key, defaultValue);
15108 * Sets the value for a key
15109 * @param {String} name The key name
15110 * @param {Mixed} value The state data
15112 set : function(key, value){
15113 provider.set(key, value);
15117 * Clears a value from the state
15118 * @param {String} name The key name
15120 clear : function(key){
15121 provider.clear(key);
15125 * Gets the currently configured state provider
15126 * @return {Provider} The state provider
15128 getProvider : function(){
15135 * Ext JS Library 1.1.1
15136 * Copyright(c) 2006-2007, Ext JS, LLC.
15138 * Originally Released Under LGPL - original licence link has changed is not relivant.
15141 * <script type="text/javascript">
15144 * @class Roo.state.CookieProvider
15145 * @extends Roo.state.Provider
15146 * The default Provider implementation which saves state via cookies.
15149 var cp = new Roo.state.CookieProvider({
15151 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15152 domain: "roojs.com"
15154 Roo.state.Manager.setProvider(cp);
15156 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15157 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15158 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15159 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15160 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15161 * domain the page is running on including the 'www' like 'www.roojs.com')
15162 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15164 * Create a new CookieProvider
15165 * @param {Object} config The configuration object
15167 Roo.state.CookieProvider = function(config){
15168 Roo.state.CookieProvider.superclass.constructor.call(this);
15170 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15171 this.domain = null;
15172 this.secure = false;
15173 Roo.apply(this, config);
15174 this.state = this.readCookies();
15177 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15179 set : function(name, value){
15180 if(typeof value == "undefined" || value === null){
15184 this.setCookie(name, value);
15185 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15189 clear : function(name){
15190 this.clearCookie(name);
15191 Roo.state.CookieProvider.superclass.clear.call(this, name);
15195 readCookies : function(){
15197 var c = document.cookie + ";";
15198 var re = /\s?(.*?)=(.*?);/g;
15200 while((matches = re.exec(c)) != null){
15201 var name = matches[1];
15202 var value = matches[2];
15203 if(name && name.substring(0,3) == "ys-"){
15204 cookies[name.substr(3)] = this.decodeValue(value);
15211 setCookie : function(name, value){
15212 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15213 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15214 ((this.path == null) ? "" : ("; path=" + this.path)) +
15215 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15216 ((this.secure == true) ? "; secure" : "");
15220 clearCookie : function(name){
15221 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15222 ((this.path == null) ? "" : ("; path=" + this.path)) +
15223 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15224 ((this.secure == true) ? "; secure" : "");
15228 * Ext JS Library 1.1.1
15229 * Copyright(c) 2006-2007, Ext JS, LLC.
15231 * Originally Released Under LGPL - original licence link has changed is not relivant.
15234 * <script type="text/javascript">
15239 * @class Roo.ComponentMgr
15240 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15243 Roo.ComponentMgr = function(){
15244 var all = new Roo.util.MixedCollection();
15248 * Registers a component.
15249 * @param {Roo.Component} c The component
15251 register : function(c){
15256 * Unregisters a component.
15257 * @param {Roo.Component} c The component
15259 unregister : function(c){
15264 * Returns a component by id
15265 * @param {String} id The component id
15267 get : function(id){
15268 return all.get(id);
15272 * Registers a function that will be called when a specified component is added to ComponentMgr
15273 * @param {String} id The component id
15274 * @param {Funtction} fn The callback function
15275 * @param {Object} scope The scope of the callback
15277 onAvailable : function(id, fn, scope){
15278 all.on("add", function(index, o){
15280 fn.call(scope || o, o);
15281 all.un("add", fn, scope);
15288 * Ext JS Library 1.1.1
15289 * Copyright(c) 2006-2007, Ext JS, LLC.
15291 * Originally Released Under LGPL - original licence link has changed is not relivant.
15294 * <script type="text/javascript">
15298 * @class Roo.Component
15299 * @extends Roo.util.Observable
15300 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15301 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15302 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15303 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15304 * All visual components (widgets) that require rendering into a layout should subclass Component.
15306 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15307 * 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
15308 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15310 Roo.Component = function(config){
15311 config = config || {};
15312 if(config.tagName || config.dom || typeof config == "string"){ // element object
15313 config = {el: config, id: config.id || config};
15315 this.initialConfig = config;
15317 Roo.apply(this, config);
15321 * Fires after the component is disabled.
15322 * @param {Roo.Component} this
15327 * Fires after the component is enabled.
15328 * @param {Roo.Component} this
15332 * @event beforeshow
15333 * Fires before the component is shown. Return false to stop the show.
15334 * @param {Roo.Component} this
15339 * Fires after the component is shown.
15340 * @param {Roo.Component} this
15344 * @event beforehide
15345 * Fires before the component is hidden. Return false to stop the hide.
15346 * @param {Roo.Component} this
15351 * Fires after the component is hidden.
15352 * @param {Roo.Component} this
15356 * @event beforerender
15357 * Fires before the component is rendered. Return false to stop the render.
15358 * @param {Roo.Component} this
15360 beforerender : true,
15363 * Fires after the component is rendered.
15364 * @param {Roo.Component} this
15368 * @event beforedestroy
15369 * Fires before the component is destroyed. Return false to stop the destroy.
15370 * @param {Roo.Component} this
15372 beforedestroy : true,
15375 * Fires after the component is destroyed.
15376 * @param {Roo.Component} this
15381 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15383 Roo.ComponentMgr.register(this);
15384 Roo.Component.superclass.constructor.call(this);
15385 this.initComponent();
15386 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15387 this.render(this.renderTo);
15388 delete this.renderTo;
15393 Roo.Component.AUTO_ID = 1000;
15395 Roo.extend(Roo.Component, Roo.util.Observable, {
15397 * @scope Roo.Component.prototype
15399 * true if this component is hidden. Read-only.
15404 * true if this component is disabled. Read-only.
15409 * true if this component has been rendered. Read-only.
15413 /** @cfg {String} disableClass
15414 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15416 disabledClass : "x-item-disabled",
15417 /** @cfg {Boolean} allowDomMove
15418 * Whether the component can move the Dom node when rendering (defaults to true).
15420 allowDomMove : true,
15421 /** @cfg {String} hideMode (display|visibility)
15422 * How this component should hidden. Supported values are
15423 * "visibility" (css visibility), "offsets" (negative offset position) and
15424 * "display" (css display) - defaults to "display".
15426 hideMode: 'display',
15429 ctype : "Roo.Component",
15432 * @cfg {String} actionMode
15433 * which property holds the element that used for hide() / show() / disable() / enable()
15439 getActionEl : function(){
15440 return this[this.actionMode];
15443 initComponent : Roo.emptyFn,
15445 * If this is a lazy rendering component, render it to its container element.
15446 * @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.
15448 render : function(container, position){
15454 if(this.fireEvent("beforerender", this) === false){
15458 if(!container && this.el){
15459 this.el = Roo.get(this.el);
15460 container = this.el.dom.parentNode;
15461 this.allowDomMove = false;
15463 this.container = Roo.get(container);
15464 this.rendered = true;
15465 if(position !== undefined){
15466 if(typeof position == 'number'){
15467 position = this.container.dom.childNodes[position];
15469 position = Roo.getDom(position);
15472 this.onRender(this.container, position || null);
15474 this.el.addClass(this.cls);
15478 this.el.applyStyles(this.style);
15481 this.fireEvent("render", this);
15482 this.afterRender(this.container);
15495 // default function is not really useful
15496 onRender : function(ct, position){
15498 this.el = Roo.get(this.el);
15499 if(this.allowDomMove !== false){
15500 ct.dom.insertBefore(this.el.dom, position);
15506 getAutoCreate : function(){
15507 var cfg = typeof this.autoCreate == "object" ?
15508 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15509 if(this.id && !cfg.id){
15516 afterRender : Roo.emptyFn,
15519 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15520 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15522 destroy : function(){
15523 if(this.fireEvent("beforedestroy", this) !== false){
15524 this.purgeListeners();
15525 this.beforeDestroy();
15527 this.el.removeAllListeners();
15529 if(this.actionMode == "container"){
15530 this.container.remove();
15534 Roo.ComponentMgr.unregister(this);
15535 this.fireEvent("destroy", this);
15540 beforeDestroy : function(){
15545 onDestroy : function(){
15550 * Returns the underlying {@link Roo.Element}.
15551 * @return {Roo.Element} The element
15553 getEl : function(){
15558 * Returns the id of this component.
15561 getId : function(){
15566 * Try to focus this component.
15567 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15568 * @return {Roo.Component} this
15570 focus : function(selectText){
15573 if(selectText === true){
15574 this.el.dom.select();
15589 * Disable this component.
15590 * @return {Roo.Component} this
15592 disable : function(){
15596 this.disabled = true;
15597 this.fireEvent("disable", this);
15602 onDisable : function(){
15603 this.getActionEl().addClass(this.disabledClass);
15604 this.el.dom.disabled = true;
15608 * Enable this component.
15609 * @return {Roo.Component} this
15611 enable : function(){
15615 this.disabled = false;
15616 this.fireEvent("enable", this);
15621 onEnable : function(){
15622 this.getActionEl().removeClass(this.disabledClass);
15623 this.el.dom.disabled = false;
15627 * Convenience function for setting disabled/enabled by boolean.
15628 * @param {Boolean} disabled
15630 setDisabled : function(disabled){
15631 this[disabled ? "disable" : "enable"]();
15635 * Show this component.
15636 * @return {Roo.Component} this
15639 if(this.fireEvent("beforeshow", this) !== false){
15640 this.hidden = false;
15644 this.fireEvent("show", this);
15650 onShow : function(){
15651 var ae = this.getActionEl();
15652 if(this.hideMode == 'visibility'){
15653 ae.dom.style.visibility = "visible";
15654 }else if(this.hideMode == 'offsets'){
15655 ae.removeClass('x-hidden');
15657 ae.dom.style.display = "";
15662 * Hide this component.
15663 * @return {Roo.Component} this
15666 if(this.fireEvent("beforehide", this) !== false){
15667 this.hidden = true;
15671 this.fireEvent("hide", this);
15677 onHide : function(){
15678 var ae = this.getActionEl();
15679 if(this.hideMode == 'visibility'){
15680 ae.dom.style.visibility = "hidden";
15681 }else if(this.hideMode == 'offsets'){
15682 ae.addClass('x-hidden');
15684 ae.dom.style.display = "none";
15689 * Convenience function to hide or show this component by boolean.
15690 * @param {Boolean} visible True to show, false to hide
15691 * @return {Roo.Component} this
15693 setVisible: function(visible){
15703 * Returns true if this component is visible.
15705 isVisible : function(){
15706 return this.getActionEl().isVisible();
15709 cloneConfig : function(overrides){
15710 overrides = overrides || {};
15711 var id = overrides.id || Roo.id();
15712 var cfg = Roo.applyIf(overrides, this.initialConfig);
15713 cfg.id = id; // prevent dup id
15714 return new this.constructor(cfg);
15718 * Ext JS Library 1.1.1
15719 * Copyright(c) 2006-2007, Ext JS, LLC.
15721 * Originally Released Under LGPL - original licence link has changed is not relivant.
15724 * <script type="text/javascript">
15728 * @class Roo.BoxComponent
15729 * @extends Roo.Component
15730 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15731 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15732 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15733 * layout containers.
15735 * @param {Roo.Element/String/Object} config The configuration options.
15737 Roo.BoxComponent = function(config){
15738 Roo.Component.call(this, config);
15742 * Fires after the component is resized.
15743 * @param {Roo.Component} this
15744 * @param {Number} adjWidth The box-adjusted width that was set
15745 * @param {Number} adjHeight The box-adjusted height that was set
15746 * @param {Number} rawWidth The width that was originally specified
15747 * @param {Number} rawHeight The height that was originally specified
15752 * Fires after the component is moved.
15753 * @param {Roo.Component} this
15754 * @param {Number} x The new x position
15755 * @param {Number} y The new y position
15761 Roo.extend(Roo.BoxComponent, Roo.Component, {
15762 // private, set in afterRender to signify that the component has been rendered
15764 // private, used to defer height settings to subclasses
15765 deferHeight: false,
15766 /** @cfg {Number} width
15767 * width (optional) size of component
15769 /** @cfg {Number} height
15770 * height (optional) size of component
15774 * Sets the width and height of the component. This method fires the resize event. This method can accept
15775 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15776 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15777 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15778 * @return {Roo.BoxComponent} this
15780 setSize : function(w, h){
15781 // support for standard size objects
15782 if(typeof w == 'object'){
15787 if(!this.boxReady){
15793 // prevent recalcs when not needed
15794 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15797 this.lastSize = {width: w, height: h};
15799 var adj = this.adjustSize(w, h);
15800 var aw = adj.width, ah = adj.height;
15801 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15802 var rz = this.getResizeEl();
15803 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15804 rz.setSize(aw, ah);
15805 }else if(!this.deferHeight && ah !== undefined){
15807 }else if(aw !== undefined){
15810 this.onResize(aw, ah, w, h);
15811 this.fireEvent('resize', this, aw, ah, w, h);
15817 * Gets the current size of the component's underlying element.
15818 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15820 getSize : function(){
15821 return this.el.getSize();
15825 * Gets the current XY position of the component's underlying element.
15826 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15827 * @return {Array} The XY position of the element (e.g., [100, 200])
15829 getPosition : function(local){
15830 if(local === true){
15831 return [this.el.getLeft(true), this.el.getTop(true)];
15833 return this.xy || this.el.getXY();
15837 * Gets the current box measurements of the component's underlying element.
15838 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15839 * @returns {Object} box An object in the format {x, y, width, height}
15841 getBox : function(local){
15842 var s = this.el.getSize();
15844 s.x = this.el.getLeft(true);
15845 s.y = this.el.getTop(true);
15847 var xy = this.xy || this.el.getXY();
15855 * Sets the current box measurements of the component's underlying element.
15856 * @param {Object} box An object in the format {x, y, width, height}
15857 * @returns {Roo.BoxComponent} this
15859 updateBox : function(box){
15860 this.setSize(box.width, box.height);
15861 this.setPagePosition(box.x, box.y);
15866 getResizeEl : function(){
15867 return this.resizeEl || this.el;
15871 getPositionEl : function(){
15872 return this.positionEl || this.el;
15876 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15877 * This method fires the move event.
15878 * @param {Number} left The new left
15879 * @param {Number} top The new top
15880 * @returns {Roo.BoxComponent} this
15882 setPosition : function(x, y){
15885 if(!this.boxReady){
15888 var adj = this.adjustPosition(x, y);
15889 var ax = adj.x, ay = adj.y;
15891 var el = this.getPositionEl();
15892 if(ax !== undefined || ay !== undefined){
15893 if(ax !== undefined && ay !== undefined){
15894 el.setLeftTop(ax, ay);
15895 }else if(ax !== undefined){
15897 }else if(ay !== undefined){
15900 this.onPosition(ax, ay);
15901 this.fireEvent('move', this, ax, ay);
15907 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15908 * This method fires the move event.
15909 * @param {Number} x The new x position
15910 * @param {Number} y The new y position
15911 * @returns {Roo.BoxComponent} this
15913 setPagePosition : function(x, y){
15916 if(!this.boxReady){
15919 if(x === undefined || y === undefined){ // cannot translate undefined points
15922 var p = this.el.translatePoints(x, y);
15923 this.setPosition(p.left, p.top);
15928 onRender : function(ct, position){
15929 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15931 this.resizeEl = Roo.get(this.resizeEl);
15933 if(this.positionEl){
15934 this.positionEl = Roo.get(this.positionEl);
15939 afterRender : function(){
15940 Roo.BoxComponent.superclass.afterRender.call(this);
15941 this.boxReady = true;
15942 this.setSize(this.width, this.height);
15943 if(this.x || this.y){
15944 this.setPosition(this.x, this.y);
15946 if(this.pageX || this.pageY){
15947 this.setPagePosition(this.pageX, this.pageY);
15952 * Force the component's size to recalculate based on the underlying element's current height and width.
15953 * @returns {Roo.BoxComponent} this
15955 syncSize : function(){
15956 delete this.lastSize;
15957 this.setSize(this.el.getWidth(), this.el.getHeight());
15962 * Called after the component is resized, this method is empty by default but can be implemented by any
15963 * subclass that needs to perform custom logic after a resize occurs.
15964 * @param {Number} adjWidth The box-adjusted width that was set
15965 * @param {Number} adjHeight The box-adjusted height that was set
15966 * @param {Number} rawWidth The width that was originally specified
15967 * @param {Number} rawHeight The height that was originally specified
15969 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15974 * Called after the component is moved, this method is empty by default but can be implemented by any
15975 * subclass that needs to perform custom logic after a move occurs.
15976 * @param {Number} x The new x position
15977 * @param {Number} y The new y position
15979 onPosition : function(x, y){
15984 adjustSize : function(w, h){
15985 if(this.autoWidth){
15988 if(this.autoHeight){
15991 return {width : w, height: h};
15995 adjustPosition : function(x, y){
15996 return {x : x, y: y};
15999 * Original code for Roojs - LGPL
16000 * <script type="text/javascript">
16004 * @class Roo.XComponent
16005 * A delayed Element creator...
16006 * Or a way to group chunks of interface together.
16007 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16008 * used in conjunction with XComponent.build() it will create an instance of each element,
16009 * then call addxtype() to build the User interface.
16011 * Mypart.xyx = new Roo.XComponent({
16013 parent : 'Mypart.xyz', // empty == document.element.!!
16017 disabled : function() {}
16019 tree : function() { // return an tree of xtype declared components
16023 xtype : 'NestedLayoutPanel',
16030 * It can be used to build a big heiracy, with parent etc.
16031 * or you can just use this to render a single compoent to a dom element
16032 * MYPART.render(Roo.Element | String(id) | dom_element )
16039 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16040 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16042 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16044 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16045 * - if mulitple topModules exist, the last one is defined as the top module.
16049 * When the top level or multiple modules are to embedded into a existing HTML page,
16050 * the parent element can container '#id' of the element where the module will be drawn.
16054 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16055 * it relies more on a include mechanism, where sub modules are included into an outer page.
16056 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16058 * Bootstrap Roo Included elements
16060 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16061 * hence confusing the component builder as it thinks there are multiple top level elements.
16063 * String Over-ride & Translations
16065 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16066 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16067 * are needed. @see Roo.XComponent.overlayString
16071 * @extends Roo.util.Observable
16073 * @param cfg {Object} configuration of component
16076 Roo.XComponent = function(cfg) {
16077 Roo.apply(this, cfg);
16081 * Fires when this the componnt is built
16082 * @param {Roo.XComponent} c the component
16087 this.region = this.region || 'center'; // default..
16088 Roo.XComponent.register(this);
16089 this.modules = false;
16090 this.el = false; // where the layout goes..
16094 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16097 * The created element (with Roo.factory())
16098 * @type {Roo.Layout}
16104 * for BC - use el in new code
16105 * @type {Roo.Layout}
16111 * for BC - use el in new code
16112 * @type {Roo.Layout}
16117 * @cfg {Function|boolean} disabled
16118 * If this module is disabled by some rule, return true from the funtion
16123 * @cfg {String} parent
16124 * Name of parent element which it get xtype added to..
16129 * @cfg {String} order
16130 * Used to set the order in which elements are created (usefull for multiple tabs)
16135 * @cfg {String} name
16136 * String to display while loading.
16140 * @cfg {String} region
16141 * Region to render component to (defaults to center)
16146 * @cfg {Array} items
16147 * A single item array - the first element is the root of the tree..
16148 * It's done this way to stay compatible with the Xtype system...
16154 * The method that retuns the tree of parts that make up this compoennt
16161 * render element to dom or tree
16162 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16165 render : function(el)
16169 var hp = this.parent ? 1 : 0;
16170 Roo.debug && Roo.log(this);
16172 var tree = this._tree ? this._tree() : this.tree();
16175 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16176 // if parent is a '#.....' string, then let's use that..
16177 var ename = this.parent.substr(1);
16178 this.parent = false;
16179 Roo.debug && Roo.log(ename);
16181 case 'bootstrap-body':
16182 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16183 // this is the BorderLayout standard?
16184 this.parent = { el : true };
16187 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16188 // need to insert stuff...
16190 el : new Roo.bootstrap.layout.Border({
16191 el : document.body,
16197 tabPosition: 'top',
16198 //resizeTabs: true,
16199 alwaysShowTabs: true,
16209 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16210 this.parent = { el : new Roo.bootstrap.Body() };
16211 Roo.debug && Roo.log("setting el to doc body");
16214 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16218 this.parent = { el : true};
16221 el = Roo.get(ename);
16222 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16223 this.parent = { el : true};
16230 if (!el && !this.parent) {
16231 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16236 Roo.debug && Roo.log("EL:");
16237 Roo.debug && Roo.log(el);
16238 Roo.debug && Roo.log("this.parent.el:");
16239 Roo.debug && Roo.log(this.parent.el);
16242 // altertive root elements ??? - we need a better way to indicate these.
16243 var is_alt = Roo.XComponent.is_alt ||
16244 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16245 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16246 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16250 if (!this.parent && is_alt) {
16251 //el = Roo.get(document.body);
16252 this.parent = { el : true };
16257 if (!this.parent) {
16259 Roo.debug && Roo.log("no parent - creating one");
16261 el = el ? Roo.get(el) : false;
16263 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16266 el : new Roo.bootstrap.layout.Border({
16267 el: el || document.body,
16273 tabPosition: 'top',
16274 //resizeTabs: true,
16275 alwaysShowTabs: false,
16278 overflow: 'visible'
16284 // it's a top level one..
16286 el : new Roo.BorderLayout(el || document.body, {
16291 tabPosition: 'top',
16292 //resizeTabs: true,
16293 alwaysShowTabs: el && hp? false : true,
16294 hideTabs: el || !hp ? true : false,
16302 if (!this.parent.el) {
16303 // probably an old style ctor, which has been disabled.
16307 // The 'tree' method is '_tree now'
16309 tree.region = tree.region || this.region;
16310 var is_body = false;
16311 if (this.parent.el === true) {
16312 // bootstrap... - body..
16316 this.parent.el = Roo.factory(tree);
16320 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16321 this.fireEvent('built', this);
16323 this.panel = this.el;
16324 this.layout = this.panel.layout;
16325 this.parentLayout = this.parent.layout || false;
16331 Roo.apply(Roo.XComponent, {
16333 * @property hideProgress
16334 * true to disable the building progress bar.. usefull on single page renders.
16337 hideProgress : false,
16339 * @property buildCompleted
16340 * True when the builder has completed building the interface.
16343 buildCompleted : false,
16346 * @property topModule
16347 * the upper most module - uses document.element as it's constructor.
16354 * @property modules
16355 * array of modules to be created by registration system.
16356 * @type {Array} of Roo.XComponent
16361 * @property elmodules
16362 * array of modules to be created by which use #ID
16363 * @type {Array} of Roo.XComponent
16370 * Is an alternative Root - normally used by bootstrap or other systems,
16371 * where the top element in the tree can wrap 'body'
16372 * @type {boolean} (default false)
16377 * @property build_from_html
16378 * Build elements from html - used by bootstrap HTML stuff
16379 * - this is cleared after build is completed
16380 * @type {boolean} (default false)
16383 build_from_html : false,
16385 * Register components to be built later.
16387 * This solves the following issues
16388 * - Building is not done on page load, but after an authentication process has occured.
16389 * - Interface elements are registered on page load
16390 * - Parent Interface elements may not be loaded before child, so this handles that..
16397 module : 'Pman.Tab.projectMgr',
16399 parent : 'Pman.layout',
16400 disabled : false, // or use a function..
16403 * * @param {Object} details about module
16405 register : function(obj) {
16407 Roo.XComponent.event.fireEvent('register', obj);
16408 switch(typeof(obj.disabled) ) {
16414 if ( obj.disabled() ) {
16420 if (obj.disabled) {
16426 this.modules.push(obj);
16430 * convert a string to an object..
16431 * eg. 'AAA.BBB' -> finds AAA.BBB
16435 toObject : function(str)
16437 if (!str || typeof(str) == 'object') {
16440 if (str.substring(0,1) == '#') {
16444 var ar = str.split('.');
16449 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16451 throw "Module not found : " + str;
16455 throw "Module not found : " + str;
16457 Roo.each(ar, function(e) {
16458 if (typeof(o[e]) == 'undefined') {
16459 throw "Module not found : " + str;
16470 * move modules into their correct place in the tree..
16473 preBuild : function ()
16476 Roo.each(this.modules , function (obj)
16478 Roo.XComponent.event.fireEvent('beforebuild', obj);
16480 var opar = obj.parent;
16482 obj.parent = this.toObject(opar);
16484 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16489 Roo.debug && Roo.log("GOT top level module");
16490 Roo.debug && Roo.log(obj);
16491 obj.modules = new Roo.util.MixedCollection(false,
16492 function(o) { return o.order + '' }
16494 this.topModule = obj;
16497 // parent is a string (usually a dom element name..)
16498 if (typeof(obj.parent) == 'string') {
16499 this.elmodules.push(obj);
16502 if (obj.parent.constructor != Roo.XComponent) {
16503 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16505 if (!obj.parent.modules) {
16506 obj.parent.modules = new Roo.util.MixedCollection(false,
16507 function(o) { return o.order + '' }
16510 if (obj.parent.disabled) {
16511 obj.disabled = true;
16513 obj.parent.modules.add(obj);
16518 * make a list of modules to build.
16519 * @return {Array} list of modules.
16522 buildOrder : function()
16525 var cmp = function(a,b) {
16526 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16528 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16529 throw "No top level modules to build";
16532 // make a flat list in order of modules to build.
16533 var mods = this.topModule ? [ this.topModule ] : [];
16536 // elmodules (is a list of DOM based modules )
16537 Roo.each(this.elmodules, function(e) {
16539 if (!this.topModule &&
16540 typeof(e.parent) == 'string' &&
16541 e.parent.substring(0,1) == '#' &&
16542 Roo.get(e.parent.substr(1))
16545 _this.topModule = e;
16551 // add modules to their parents..
16552 var addMod = function(m) {
16553 Roo.debug && Roo.log("build Order: add: " + m.name);
16556 if (m.modules && !m.disabled) {
16557 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16558 m.modules.keySort('ASC', cmp );
16559 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16561 m.modules.each(addMod);
16563 Roo.debug && Roo.log("build Order: no child modules");
16565 // not sure if this is used any more..
16567 m.finalize.name = m.name + " (clean up) ";
16568 mods.push(m.finalize);
16572 if (this.topModule && this.topModule.modules) {
16573 this.topModule.modules.keySort('ASC', cmp );
16574 this.topModule.modules.each(addMod);
16580 * Build the registered modules.
16581 * @param {Object} parent element.
16582 * @param {Function} optional method to call after module has been added.
16586 build : function(opts)
16589 if (typeof(opts) != 'undefined') {
16590 Roo.apply(this,opts);
16594 var mods = this.buildOrder();
16596 //this.allmods = mods;
16597 //Roo.debug && Roo.log(mods);
16599 if (!mods.length) { // should not happen
16600 throw "NO modules!!!";
16604 var msg = "Building Interface...";
16605 // flash it up as modal - so we store the mask!?
16606 if (!this.hideProgress && Roo.MessageBox) {
16607 Roo.MessageBox.show({ title: 'loading' });
16608 Roo.MessageBox.show({
16609 title: "Please wait...",
16619 var total = mods.length;
16622 var progressRun = function() {
16623 if (!mods.length) {
16624 Roo.debug && Roo.log('hide?');
16625 if (!this.hideProgress && Roo.MessageBox) {
16626 Roo.MessageBox.hide();
16628 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16630 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16636 var m = mods.shift();
16639 Roo.debug && Roo.log(m);
16640 // not sure if this is supported any more.. - modules that are are just function
16641 if (typeof(m) == 'function') {
16643 return progressRun.defer(10, _this);
16647 msg = "Building Interface " + (total - mods.length) +
16649 (m.name ? (' - ' + m.name) : '');
16650 Roo.debug && Roo.log(msg);
16651 if (!_this.hideProgress && Roo.MessageBox) {
16652 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16656 // is the module disabled?
16657 var disabled = (typeof(m.disabled) == 'function') ?
16658 m.disabled.call(m.module.disabled) : m.disabled;
16662 return progressRun(); // we do not update the display!
16670 // it's 10 on top level, and 1 on others??? why...
16671 return progressRun.defer(10, _this);
16674 progressRun.defer(1, _this);
16680 * Overlay a set of modified strings onto a component
16681 * This is dependant on our builder exporting the strings and 'named strings' elements.
16683 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16684 * @param {Object} associative array of 'named' string and it's new value.
16687 overlayStrings : function( component, strings )
16689 if (typeof(component['_named_strings']) == 'undefined') {
16690 throw "ERROR: component does not have _named_strings";
16692 for ( var k in strings ) {
16693 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16694 if (md !== false) {
16695 component['_strings'][md] = strings[k];
16697 Roo.log('could not find named string: ' + k + ' in');
16698 Roo.log(component);
16713 * wrapper for event.on - aliased later..
16714 * Typically use to register a event handler for register:
16716 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16725 Roo.XComponent.event = new Roo.util.Observable({
16729 * Fires when an Component is registered,
16730 * set the disable property on the Component to stop registration.
16731 * @param {Roo.XComponent} c the component being registerd.
16736 * @event beforebuild
16737 * Fires before each Component is built
16738 * can be used to apply permissions.
16739 * @param {Roo.XComponent} c the component being registerd.
16742 'beforebuild' : true,
16744 * @event buildcomplete
16745 * Fires on the top level element when all elements have been built
16746 * @param {Roo.XComponent} the top level component.
16748 'buildcomplete' : true
16753 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16756 * marked - a markdown parser
16757 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16758 * https://github.com/chjj/marked
16764 * Roo.Markdown - is a very crude wrapper around marked..
16768 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16770 * Note: move the sample code to the bottom of this
16771 * file before uncommenting it.
16776 Roo.Markdown.toHtml = function(text) {
16778 var c = new Roo.Markdown.marked.setOptions({
16779 renderer: new Roo.Markdown.marked.Renderer(),
16790 text = text.replace(/\\\n/g,' ');
16791 return Roo.Markdown.marked(text);
16796 // Wraps all "globals" so that the only thing
16797 // exposed is makeHtml().
16802 * Block-Level Grammar
16807 code: /^( {4}[^\n]+\n*)+/,
16809 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16810 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16812 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16813 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16814 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16815 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16816 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16818 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16822 block.bullet = /(?:[*+-]|\d+\.)/;
16823 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16824 block.item = replace(block.item, 'gm')
16825 (/bull/g, block.bullet)
16828 block.list = replace(block.list)
16829 (/bull/g, block.bullet)
16830 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16831 ('def', '\\n+(?=' + block.def.source + ')')
16834 block.blockquote = replace(block.blockquote)
16838 block._tag = '(?!(?:'
16839 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16840 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16841 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16843 block.html = replace(block.html)
16844 ('comment', /<!--[\s\S]*?-->/)
16845 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16846 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16847 (/tag/g, block._tag)
16850 block.paragraph = replace(block.paragraph)
16852 ('heading', block.heading)
16853 ('lheading', block.lheading)
16854 ('blockquote', block.blockquote)
16855 ('tag', '<' + block._tag)
16860 * Normal Block Grammar
16863 block.normal = merge({}, block);
16866 * GFM Block Grammar
16869 block.gfm = merge({}, block.normal, {
16870 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16872 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16875 block.gfm.paragraph = replace(block.paragraph)
16877 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16878 + block.list.source.replace('\\1', '\\3') + '|')
16882 * GFM + Tables Block Grammar
16885 block.tables = merge({}, block.gfm, {
16886 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16887 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16894 function Lexer(options) {
16896 this.tokens.links = {};
16897 this.options = options || marked.defaults;
16898 this.rules = block.normal;
16900 if (this.options.gfm) {
16901 if (this.options.tables) {
16902 this.rules = block.tables;
16904 this.rules = block.gfm;
16910 * Expose Block Rules
16913 Lexer.rules = block;
16916 * Static Lex Method
16919 Lexer.lex = function(src, options) {
16920 var lexer = new Lexer(options);
16921 return lexer.lex(src);
16928 Lexer.prototype.lex = function(src) {
16930 .replace(/\r\n|\r/g, '\n')
16931 .replace(/\t/g, ' ')
16932 .replace(/\u00a0/g, ' ')
16933 .replace(/\u2424/g, '\n');
16935 return this.token(src, true);
16942 Lexer.prototype.token = function(src, top, bq) {
16943 var src = src.replace(/^ +$/gm, '')
16956 if (cap = this.rules.newline.exec(src)) {
16957 src = src.substring(cap[0].length);
16958 if (cap[0].length > 1) {
16966 if (cap = this.rules.code.exec(src)) {
16967 src = src.substring(cap[0].length);
16968 cap = cap[0].replace(/^ {4}/gm, '');
16971 text: !this.options.pedantic
16972 ? cap.replace(/\n+$/, '')
16979 if (cap = this.rules.fences.exec(src)) {
16980 src = src.substring(cap[0].length);
16990 if (cap = this.rules.heading.exec(src)) {
16991 src = src.substring(cap[0].length);
16994 depth: cap[1].length,
17000 // table no leading pipe (gfm)
17001 if (top && (cap = this.rules.nptable.exec(src))) {
17002 src = src.substring(cap[0].length);
17006 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17007 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17008 cells: cap[3].replace(/\n$/, '').split('\n')
17011 for (i = 0; i < item.align.length; i++) {
17012 if (/^ *-+: *$/.test(item.align[i])) {
17013 item.align[i] = 'right';
17014 } else if (/^ *:-+: *$/.test(item.align[i])) {
17015 item.align[i] = 'center';
17016 } else if (/^ *:-+ *$/.test(item.align[i])) {
17017 item.align[i] = 'left';
17019 item.align[i] = null;
17023 for (i = 0; i < item.cells.length; i++) {
17024 item.cells[i] = item.cells[i].split(/ *\| */);
17027 this.tokens.push(item);
17033 if (cap = this.rules.lheading.exec(src)) {
17034 src = src.substring(cap[0].length);
17037 depth: cap[2] === '=' ? 1 : 2,
17044 if (cap = this.rules.hr.exec(src)) {
17045 src = src.substring(cap[0].length);
17053 if (cap = this.rules.blockquote.exec(src)) {
17054 src = src.substring(cap[0].length);
17057 type: 'blockquote_start'
17060 cap = cap[0].replace(/^ *> ?/gm, '');
17062 // Pass `top` to keep the current
17063 // "toplevel" state. This is exactly
17064 // how markdown.pl works.
17065 this.token(cap, top, true);
17068 type: 'blockquote_end'
17075 if (cap = this.rules.list.exec(src)) {
17076 src = src.substring(cap[0].length);
17080 type: 'list_start',
17081 ordered: bull.length > 1
17084 // Get each top-level item.
17085 cap = cap[0].match(this.rules.item);
17091 for (; i < l; i++) {
17094 // Remove the list item's bullet
17095 // so it is seen as the next token.
17096 space = item.length;
17097 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17099 // Outdent whatever the
17100 // list item contains. Hacky.
17101 if (~item.indexOf('\n ')) {
17102 space -= item.length;
17103 item = !this.options.pedantic
17104 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17105 : item.replace(/^ {1,4}/gm, '');
17108 // Determine whether the next list item belongs here.
17109 // Backpedal if it does not belong in this list.
17110 if (this.options.smartLists && i !== l - 1) {
17111 b = block.bullet.exec(cap[i + 1])[0];
17112 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17113 src = cap.slice(i + 1).join('\n') + src;
17118 // Determine whether item is loose or not.
17119 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17120 // for discount behavior.
17121 loose = next || /\n\n(?!\s*$)/.test(item);
17123 next = item.charAt(item.length - 1) === '\n';
17124 if (!loose) { loose = next; }
17129 ? 'loose_item_start'
17130 : 'list_item_start'
17134 this.token(item, false, bq);
17137 type: 'list_item_end'
17149 if (cap = this.rules.html.exec(src)) {
17150 src = src.substring(cap[0].length);
17152 type: this.options.sanitize
17155 pre: !this.options.sanitizer
17156 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17163 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17164 src = src.substring(cap[0].length);
17165 this.tokens.links[cap[1].toLowerCase()] = {
17173 if (top && (cap = this.rules.table.exec(src))) {
17174 src = src.substring(cap[0].length);
17178 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17179 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17180 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17183 for (i = 0; i < item.align.length; i++) {
17184 if (/^ *-+: *$/.test(item.align[i])) {
17185 item.align[i] = 'right';
17186 } else if (/^ *:-+: *$/.test(item.align[i])) {
17187 item.align[i] = 'center';
17188 } else if (/^ *:-+ *$/.test(item.align[i])) {
17189 item.align[i] = 'left';
17191 item.align[i] = null;
17195 for (i = 0; i < item.cells.length; i++) {
17196 item.cells[i] = item.cells[i]
17197 .replace(/^ *\| *| *\| *$/g, '')
17201 this.tokens.push(item);
17206 // top-level paragraph
17207 if (top && (cap = this.rules.paragraph.exec(src))) {
17208 src = src.substring(cap[0].length);
17211 text: cap[1].charAt(cap[1].length - 1) === '\n'
17212 ? cap[1].slice(0, -1)
17219 if (cap = this.rules.text.exec(src)) {
17220 // Top-level should never reach here.
17221 src = src.substring(cap[0].length);
17231 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17235 return this.tokens;
17239 * Inline-Level Grammar
17243 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17244 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17246 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17247 link: /^!?\[(inside)\]\(href\)/,
17248 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17249 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17250 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17251 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17252 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17253 br: /^ {2,}\n(?!\s*$)/,
17255 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17258 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17259 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17261 inline.link = replace(inline.link)
17262 ('inside', inline._inside)
17263 ('href', inline._href)
17266 inline.reflink = replace(inline.reflink)
17267 ('inside', inline._inside)
17271 * Normal Inline Grammar
17274 inline.normal = merge({}, inline);
17277 * Pedantic Inline Grammar
17280 inline.pedantic = merge({}, inline.normal, {
17281 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17282 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17286 * GFM Inline Grammar
17289 inline.gfm = merge({}, inline.normal, {
17290 escape: replace(inline.escape)('])', '~|])')(),
17291 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17292 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17293 text: replace(inline.text)
17295 ('|', '|https?://|')
17300 * GFM + Line Breaks Inline Grammar
17303 inline.breaks = merge({}, inline.gfm, {
17304 br: replace(inline.br)('{2,}', '*')(),
17305 text: replace(inline.gfm.text)('{2,}', '*')()
17309 * Inline Lexer & Compiler
17312 function InlineLexer(links, options) {
17313 this.options = options || marked.defaults;
17314 this.links = links;
17315 this.rules = inline.normal;
17316 this.renderer = this.options.renderer || new Renderer;
17317 this.renderer.options = this.options;
17321 Error('Tokens array requires a `links` property.');
17324 if (this.options.gfm) {
17325 if (this.options.breaks) {
17326 this.rules = inline.breaks;
17328 this.rules = inline.gfm;
17330 } else if (this.options.pedantic) {
17331 this.rules = inline.pedantic;
17336 * Expose Inline Rules
17339 InlineLexer.rules = inline;
17342 * Static Lexing/Compiling Method
17345 InlineLexer.output = function(src, links, options) {
17346 var inline = new InlineLexer(links, options);
17347 return inline.output(src);
17354 InlineLexer.prototype.output = function(src) {
17363 if (cap = this.rules.escape.exec(src)) {
17364 src = src.substring(cap[0].length);
17370 if (cap = this.rules.autolink.exec(src)) {
17371 src = src.substring(cap[0].length);
17372 if (cap[2] === '@') {
17373 text = cap[1].charAt(6) === ':'
17374 ? this.mangle(cap[1].substring(7))
17375 : this.mangle(cap[1]);
17376 href = this.mangle('mailto:') + text;
17378 text = escape(cap[1]);
17381 out += this.renderer.link(href, null, text);
17386 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17387 src = src.substring(cap[0].length);
17388 text = escape(cap[1]);
17390 out += this.renderer.link(href, null, text);
17395 if (cap = this.rules.tag.exec(src)) {
17396 if (!this.inLink && /^<a /i.test(cap[0])) {
17397 this.inLink = true;
17398 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17399 this.inLink = false;
17401 src = src.substring(cap[0].length);
17402 out += this.options.sanitize
17403 ? this.options.sanitizer
17404 ? this.options.sanitizer(cap[0])
17411 if (cap = this.rules.link.exec(src)) {
17412 src = src.substring(cap[0].length);
17413 this.inLink = true;
17414 out += this.outputLink(cap, {
17418 this.inLink = false;
17423 if ((cap = this.rules.reflink.exec(src))
17424 || (cap = this.rules.nolink.exec(src))) {
17425 src = src.substring(cap[0].length);
17426 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17427 link = this.links[link.toLowerCase()];
17428 if (!link || !link.href) {
17429 out += cap[0].charAt(0);
17430 src = cap[0].substring(1) + src;
17433 this.inLink = true;
17434 out += this.outputLink(cap, link);
17435 this.inLink = false;
17440 if (cap = this.rules.strong.exec(src)) {
17441 src = src.substring(cap[0].length);
17442 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17447 if (cap = this.rules.em.exec(src)) {
17448 src = src.substring(cap[0].length);
17449 out += this.renderer.em(this.output(cap[2] || cap[1]));
17454 if (cap = this.rules.code.exec(src)) {
17455 src = src.substring(cap[0].length);
17456 out += this.renderer.codespan(escape(cap[2], true));
17461 if (cap = this.rules.br.exec(src)) {
17462 src = src.substring(cap[0].length);
17463 out += this.renderer.br();
17468 if (cap = this.rules.del.exec(src)) {
17469 src = src.substring(cap[0].length);
17470 out += this.renderer.del(this.output(cap[1]));
17475 if (cap = this.rules.text.exec(src)) {
17476 src = src.substring(cap[0].length);
17477 out += this.renderer.text(escape(this.smartypants(cap[0])));
17483 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17494 InlineLexer.prototype.outputLink = function(cap, link) {
17495 var href = escape(link.href)
17496 , title = link.title ? escape(link.title) : null;
17498 return cap[0].charAt(0) !== '!'
17499 ? this.renderer.link(href, title, this.output(cap[1]))
17500 : this.renderer.image(href, title, escape(cap[1]));
17504 * Smartypants Transformations
17507 InlineLexer.prototype.smartypants = function(text) {
17508 if (!this.options.smartypants) { return text; }
17511 .replace(/---/g, '\u2014')
17513 .replace(/--/g, '\u2013')
17515 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17516 // closing singles & apostrophes
17517 .replace(/'/g, '\u2019')
17519 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17521 .replace(/"/g, '\u201d')
17523 .replace(/\.{3}/g, '\u2026');
17530 InlineLexer.prototype.mangle = function(text) {
17531 if (!this.options.mangle) { return text; }
17537 for (; i < l; i++) {
17538 ch = text.charCodeAt(i);
17539 if (Math.random() > 0.5) {
17540 ch = 'x' + ch.toString(16);
17542 out += '&#' + ch + ';';
17552 function Renderer(options) {
17553 this.options = options || {};
17556 Renderer.prototype.code = function(code, lang, escaped) {
17557 if (this.options.highlight) {
17558 var out = this.options.highlight(code, lang);
17559 if (out != null && out !== code) {
17564 // hack!!! - it's already escapeD?
17569 return '<pre><code>'
17570 + (escaped ? code : escape(code, true))
17571 + '\n</code></pre>';
17574 return '<pre><code class="'
17575 + this.options.langPrefix
17576 + escape(lang, true)
17578 + (escaped ? code : escape(code, true))
17579 + '\n</code></pre>\n';
17582 Renderer.prototype.blockquote = function(quote) {
17583 return '<blockquote>\n' + quote + '</blockquote>\n';
17586 Renderer.prototype.html = function(html) {
17590 Renderer.prototype.heading = function(text, level, raw) {
17594 + this.options.headerPrefix
17595 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17603 Renderer.prototype.hr = function() {
17604 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17607 Renderer.prototype.list = function(body, ordered) {
17608 var type = ordered ? 'ol' : 'ul';
17609 return '<' + type + '>\n' + body + '</' + type + '>\n';
17612 Renderer.prototype.listitem = function(text) {
17613 return '<li>' + text + '</li>\n';
17616 Renderer.prototype.paragraph = function(text) {
17617 return '<p>' + text + '</p>\n';
17620 Renderer.prototype.table = function(header, body) {
17621 return '<table class="table table-striped">\n'
17631 Renderer.prototype.tablerow = function(content) {
17632 return '<tr>\n' + content + '</tr>\n';
17635 Renderer.prototype.tablecell = function(content, flags) {
17636 var type = flags.header ? 'th' : 'td';
17637 var tag = flags.align
17638 ? '<' + type + ' style="text-align:' + flags.align + '">'
17639 : '<' + type + '>';
17640 return tag + content + '</' + type + '>\n';
17643 // span level renderer
17644 Renderer.prototype.strong = function(text) {
17645 return '<strong>' + text + '</strong>';
17648 Renderer.prototype.em = function(text) {
17649 return '<em>' + text + '</em>';
17652 Renderer.prototype.codespan = function(text) {
17653 return '<code>' + text + '</code>';
17656 Renderer.prototype.br = function() {
17657 return this.options.xhtml ? '<br/>' : '<br>';
17660 Renderer.prototype.del = function(text) {
17661 return '<del>' + text + '</del>';
17664 Renderer.prototype.link = function(href, title, text) {
17665 if (this.options.sanitize) {
17667 var prot = decodeURIComponent(unescape(href))
17668 .replace(/[^\w:]/g, '')
17673 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17677 var out = '<a href="' + href + '"';
17679 out += ' title="' + title + '"';
17681 out += '>' + text + '</a>';
17685 Renderer.prototype.image = function(href, title, text) {
17686 var out = '<img src="' + href + '" alt="' + text + '"';
17688 out += ' title="' + title + '"';
17690 out += this.options.xhtml ? '/>' : '>';
17694 Renderer.prototype.text = function(text) {
17699 * Parsing & Compiling
17702 function Parser(options) {
17705 this.options = options || marked.defaults;
17706 this.options.renderer = this.options.renderer || new Renderer;
17707 this.renderer = this.options.renderer;
17708 this.renderer.options = this.options;
17712 * Static Parse Method
17715 Parser.parse = function(src, options, renderer) {
17716 var parser = new Parser(options, renderer);
17717 return parser.parse(src);
17724 Parser.prototype.parse = function(src) {
17725 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17726 this.tokens = src.reverse();
17729 while (this.next()) {
17740 Parser.prototype.next = function() {
17741 return this.token = this.tokens.pop();
17745 * Preview Next Token
17748 Parser.prototype.peek = function() {
17749 return this.tokens[this.tokens.length - 1] || 0;
17753 * Parse Text Tokens
17756 Parser.prototype.parseText = function() {
17757 var body = this.token.text;
17759 while (this.peek().type === 'text') {
17760 body += '\n' + this.next().text;
17763 return this.inline.output(body);
17767 * Parse Current Token
17770 Parser.prototype.tok = function() {
17771 switch (this.token.type) {
17776 return this.renderer.hr();
17779 return this.renderer.heading(
17780 this.inline.output(this.token.text),
17785 return this.renderer.code(this.token.text,
17787 this.token.escaped);
17800 for (i = 0; i < this.token.header.length; i++) {
17801 flags = { header: true, align: this.token.align[i] };
17802 cell += this.renderer.tablecell(
17803 this.inline.output(this.token.header[i]),
17804 { header: true, align: this.token.align[i] }
17807 header += this.renderer.tablerow(cell);
17809 for (i = 0; i < this.token.cells.length; i++) {
17810 row = this.token.cells[i];
17813 for (j = 0; j < row.length; j++) {
17814 cell += this.renderer.tablecell(
17815 this.inline.output(row[j]),
17816 { header: false, align: this.token.align[j] }
17820 body += this.renderer.tablerow(cell);
17822 return this.renderer.table(header, body);
17824 case 'blockquote_start': {
17827 while (this.next().type !== 'blockquote_end') {
17828 body += this.tok();
17831 return this.renderer.blockquote(body);
17833 case 'list_start': {
17835 , ordered = this.token.ordered;
17837 while (this.next().type !== 'list_end') {
17838 body += this.tok();
17841 return this.renderer.list(body, ordered);
17843 case 'list_item_start': {
17846 while (this.next().type !== 'list_item_end') {
17847 body += this.token.type === 'text'
17852 return this.renderer.listitem(body);
17854 case 'loose_item_start': {
17857 while (this.next().type !== 'list_item_end') {
17858 body += this.tok();
17861 return this.renderer.listitem(body);
17864 var html = !this.token.pre && !this.options.pedantic
17865 ? this.inline.output(this.token.text)
17867 return this.renderer.html(html);
17869 case 'paragraph': {
17870 return this.renderer.paragraph(this.inline.output(this.token.text));
17873 return this.renderer.paragraph(this.parseText());
17882 function escape(html, encode) {
17884 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17885 .replace(/</g, '<')
17886 .replace(/>/g, '>')
17887 .replace(/"/g, '"')
17888 .replace(/'/g, ''');
17891 function unescape(html) {
17892 // explicitly match decimal, hex, and named HTML entities
17893 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17894 n = n.toLowerCase();
17895 if (n === 'colon') { return ':'; }
17896 if (n.charAt(0) === '#') {
17897 return n.charAt(1) === 'x'
17898 ? String.fromCharCode(parseInt(n.substring(2), 16))
17899 : String.fromCharCode(+n.substring(1));
17905 function replace(regex, opt) {
17906 regex = regex.source;
17908 return function self(name, val) {
17909 if (!name) { return new RegExp(regex, opt); }
17910 val = val.source || val;
17911 val = val.replace(/(^|[^\[])\^/g, '$1');
17912 regex = regex.replace(name, val);
17920 function merge(obj) {
17925 for (; i < arguments.length; i++) {
17926 target = arguments[i];
17927 for (key in target) {
17928 if (Object.prototype.hasOwnProperty.call(target, key)) {
17929 obj[key] = target[key];
17942 function marked(src, opt, callback) {
17943 if (callback || typeof opt === 'function') {
17949 opt = merge({}, marked.defaults, opt || {});
17951 var highlight = opt.highlight
17957 tokens = Lexer.lex(src, opt)
17959 return callback(e);
17962 pending = tokens.length;
17964 var done = function(err) {
17966 opt.highlight = highlight;
17967 return callback(err);
17973 out = Parser.parse(tokens, opt);
17978 opt.highlight = highlight;
17982 : callback(null, out);
17985 if (!highlight || highlight.length < 3) {
17989 delete opt.highlight;
17991 if (!pending) { return done(); }
17993 for (; i < tokens.length; i++) {
17995 if (token.type !== 'code') {
17996 return --pending || done();
17998 return highlight(token.text, token.lang, function(err, code) {
17999 if (err) { return done(err); }
18000 if (code == null || code === token.text) {
18001 return --pending || done();
18004 token.escaped = true;
18005 --pending || done();
18013 if (opt) { opt = merge({}, marked.defaults, opt); }
18014 return Parser.parse(Lexer.lex(src, opt), opt);
18016 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18017 if ((opt || marked.defaults).silent) {
18018 return '<p>An error occured:</p><pre>'
18019 + escape(e.message + '', true)
18031 marked.setOptions = function(opt) {
18032 merge(marked.defaults, opt);
18036 marked.defaults = {
18047 langPrefix: 'lang-',
18048 smartypants: false,
18050 renderer: new Renderer,
18058 marked.Parser = Parser;
18059 marked.parser = Parser.parse;
18061 marked.Renderer = Renderer;
18063 marked.Lexer = Lexer;
18064 marked.lexer = Lexer.lex;
18066 marked.InlineLexer = InlineLexer;
18067 marked.inlineLexer = InlineLexer.output;
18069 marked.parse = marked;
18071 Roo.Markdown.marked = marked;
18075 * Ext JS Library 1.1.1
18076 * Copyright(c) 2006-2007, Ext JS, LLC.
18078 * Originally Released Under LGPL - original licence link has changed is not relivant.
18081 * <script type="text/javascript">
18087 * These classes are derivatives of the similarly named classes in the YUI Library.
18088 * The original license:
18089 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18090 * Code licensed under the BSD License:
18091 * http://developer.yahoo.net/yui/license.txt
18096 var Event=Roo.EventManager;
18097 var Dom=Roo.lib.Dom;
18100 * @class Roo.dd.DragDrop
18101 * @extends Roo.util.Observable
18102 * Defines the interface and base operation of items that that can be
18103 * dragged or can be drop targets. It was designed to be extended, overriding
18104 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18105 * Up to three html elements can be associated with a DragDrop instance:
18107 * <li>linked element: the element that is passed into the constructor.
18108 * This is the element which defines the boundaries for interaction with
18109 * other DragDrop objects.</li>
18110 * <li>handle element(s): The drag operation only occurs if the element that
18111 * was clicked matches a handle element. By default this is the linked
18112 * element, but there are times that you will want only a portion of the
18113 * linked element to initiate the drag operation, and the setHandleElId()
18114 * method provides a way to define this.</li>
18115 * <li>drag element: this represents the element that would be moved along
18116 * with the cursor during a drag operation. By default, this is the linked
18117 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18118 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18121 * This class should not be instantiated until the onload event to ensure that
18122 * the associated elements are available.
18123 * The following would define a DragDrop obj that would interact with any
18124 * other DragDrop obj in the "group1" group:
18126 * dd = new Roo.dd.DragDrop("div1", "group1");
18128 * Since none of the event handlers have been implemented, nothing would
18129 * actually happen if you were to run the code above. Normally you would
18130 * override this class or one of the default implementations, but you can
18131 * also override the methods you want on an instance of the class...
18133 * dd.onDragDrop = function(e, id) {
18134 * alert("dd was dropped on " + id);
18138 * @param {String} id of the element that is linked to this instance
18139 * @param {String} sGroup the group of related DragDrop objects
18140 * @param {object} config an object containing configurable attributes
18141 * Valid properties for DragDrop:
18142 * padding, isTarget, maintainOffset, primaryButtonOnly
18144 Roo.dd.DragDrop = function(id, sGroup, config) {
18146 this.init(id, sGroup, config);
18151 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18154 * The id of the element associated with this object. This is what we
18155 * refer to as the "linked element" because the size and position of
18156 * this element is used to determine when the drag and drop objects have
18164 * Configuration attributes passed into the constructor
18171 * The id of the element that will be dragged. By default this is same
18172 * as the linked element , but could be changed to another element. Ex:
18174 * @property dragElId
18181 * the id of the element that initiates the drag operation. By default
18182 * this is the linked element, but could be changed to be a child of this
18183 * element. This lets us do things like only starting the drag when the
18184 * header element within the linked html element is clicked.
18185 * @property handleElId
18192 * An associative array of HTML tags that will be ignored if clicked.
18193 * @property invalidHandleTypes
18194 * @type {string: string}
18196 invalidHandleTypes: null,
18199 * An associative array of ids for elements that will be ignored if clicked
18200 * @property invalidHandleIds
18201 * @type {string: string}
18203 invalidHandleIds: null,
18206 * An indexted array of css class names for elements that will be ignored
18208 * @property invalidHandleClasses
18211 invalidHandleClasses: null,
18214 * The linked element's absolute X position at the time the drag was
18216 * @property startPageX
18223 * The linked element's absolute X position at the time the drag was
18225 * @property startPageY
18232 * The group defines a logical collection of DragDrop objects that are
18233 * related. Instances only get events when interacting with other
18234 * DragDrop object in the same group. This lets us define multiple
18235 * groups using a single DragDrop subclass if we want.
18237 * @type {string: string}
18242 * Individual drag/drop instances can be locked. This will prevent
18243 * onmousedown start drag.
18251 * Lock this instance
18254 lock: function() { this.locked = true; },
18257 * Unlock this instace
18260 unlock: function() { this.locked = false; },
18263 * By default, all insances can be a drop target. This can be disabled by
18264 * setting isTarget to false.
18271 * The padding configured for this drag and drop object for calculating
18272 * the drop zone intersection with this object.
18279 * Cached reference to the linked element
18280 * @property _domRef
18286 * Internal typeof flag
18287 * @property __ygDragDrop
18290 __ygDragDrop: true,
18293 * Set to true when horizontal contraints are applied
18294 * @property constrainX
18301 * Set to true when vertical contraints are applied
18302 * @property constrainY
18309 * The left constraint
18317 * The right constraint
18325 * The up constraint
18334 * The down constraint
18342 * Maintain offsets when we resetconstraints. Set to true when you want
18343 * the position of the element relative to its parent to stay the same
18344 * when the page changes
18346 * @property maintainOffset
18349 maintainOffset: false,
18352 * Array of pixel locations the element will snap to if we specified a
18353 * horizontal graduation/interval. This array is generated automatically
18354 * when you define a tick interval.
18361 * Array of pixel locations the element will snap to if we specified a
18362 * vertical graduation/interval. This array is generated automatically
18363 * when you define a tick interval.
18370 * By default the drag and drop instance will only respond to the primary
18371 * button click (left button for a right-handed mouse). Set to true to
18372 * allow drag and drop to start with any mouse click that is propogated
18374 * @property primaryButtonOnly
18377 primaryButtonOnly: true,
18380 * The availabe property is false until the linked dom element is accessible.
18381 * @property available
18387 * By default, drags can only be initiated if the mousedown occurs in the
18388 * region the linked element is. This is done in part to work around a
18389 * bug in some browsers that mis-report the mousedown if the previous
18390 * mouseup happened outside of the window. This property is set to true
18391 * if outer handles are defined.
18393 * @property hasOuterHandles
18397 hasOuterHandles: false,
18400 * Code that executes immediately before the startDrag event
18401 * @method b4StartDrag
18404 b4StartDrag: function(x, y) { },
18407 * Abstract method called after a drag/drop object is clicked
18408 * and the drag or mousedown time thresholds have beeen met.
18409 * @method startDrag
18410 * @param {int} X click location
18411 * @param {int} Y click location
18413 startDrag: function(x, y) { /* override this */ },
18416 * Code that executes immediately before the onDrag event
18420 b4Drag: function(e) { },
18423 * Abstract method called during the onMouseMove event while dragging an
18426 * @param {Event} e the mousemove event
18428 onDrag: function(e) { /* override this */ },
18431 * Abstract method called when this element fist begins hovering over
18432 * another DragDrop obj
18433 * @method onDragEnter
18434 * @param {Event} e the mousemove event
18435 * @param {String|DragDrop[]} id In POINT mode, the element
18436 * id this is hovering over. In INTERSECT mode, an array of one or more
18437 * dragdrop items being hovered over.
18439 onDragEnter: function(e, id) { /* override this */ },
18442 * Code that executes immediately before the onDragOver event
18443 * @method b4DragOver
18446 b4DragOver: function(e) { },
18449 * Abstract method called when this element is hovering over another
18451 * @method onDragOver
18452 * @param {Event} e the mousemove event
18453 * @param {String|DragDrop[]} id In POINT mode, the element
18454 * id this is hovering over. In INTERSECT mode, an array of dd items
18455 * being hovered over.
18457 onDragOver: function(e, id) { /* override this */ },
18460 * Code that executes immediately before the onDragOut event
18461 * @method b4DragOut
18464 b4DragOut: function(e) { },
18467 * Abstract method called when we are no longer hovering over an element
18468 * @method onDragOut
18469 * @param {Event} e the mousemove event
18470 * @param {String|DragDrop[]} id In POINT mode, the element
18471 * id this was hovering over. In INTERSECT mode, an array of dd items
18472 * that the mouse is no longer over.
18474 onDragOut: function(e, id) { /* override this */ },
18477 * Code that executes immediately before the onDragDrop event
18478 * @method b4DragDrop
18481 b4DragDrop: function(e) { },
18484 * Abstract method called when this item is dropped on another DragDrop
18486 * @method onDragDrop
18487 * @param {Event} e the mouseup event
18488 * @param {String|DragDrop[]} id In POINT mode, the element
18489 * id this was dropped on. In INTERSECT mode, an array of dd items this
18492 onDragDrop: function(e, id) { /* override this */ },
18495 * Abstract method called when this item is dropped on an area with no
18497 * @method onInvalidDrop
18498 * @param {Event} e the mouseup event
18500 onInvalidDrop: function(e) { /* override this */ },
18503 * Code that executes immediately before the endDrag event
18504 * @method b4EndDrag
18507 b4EndDrag: function(e) { },
18510 * Fired when we are done dragging the object
18512 * @param {Event} e the mouseup event
18514 endDrag: function(e) { /* override this */ },
18517 * Code executed immediately before the onMouseDown event
18518 * @method b4MouseDown
18519 * @param {Event} e the mousedown event
18522 b4MouseDown: function(e) { },
18525 * Event handler that fires when a drag/drop obj gets a mousedown
18526 * @method onMouseDown
18527 * @param {Event} e the mousedown event
18529 onMouseDown: function(e) { /* override this */ },
18532 * Event handler that fires when a drag/drop obj gets a mouseup
18533 * @method onMouseUp
18534 * @param {Event} e the mouseup event
18536 onMouseUp: function(e) { /* override this */ },
18539 * Override the onAvailable method to do what is needed after the initial
18540 * position was determined.
18541 * @method onAvailable
18543 onAvailable: function () {
18547 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18550 defaultPadding : {left:0, right:0, top:0, bottom:0},
18553 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18557 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18558 { dragElId: "existingProxyDiv" });
18559 dd.startDrag = function(){
18560 this.constrainTo("parent-id");
18563 * Or you can initalize it using the {@link Roo.Element} object:
18565 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18566 startDrag : function(){
18567 this.constrainTo("parent-id");
18571 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18572 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18573 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18574 * an object containing the sides to pad. For example: {right:10, bottom:10}
18575 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18577 constrainTo : function(constrainTo, pad, inContent){
18578 if(typeof pad == "number"){
18579 pad = {left: pad, right:pad, top:pad, bottom:pad};
18581 pad = pad || this.defaultPadding;
18582 var b = Roo.get(this.getEl()).getBox();
18583 var ce = Roo.get(constrainTo);
18584 var s = ce.getScroll();
18585 var c, cd = ce.dom;
18586 if(cd == document.body){
18587 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18590 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18594 var topSpace = b.y - c.y;
18595 var leftSpace = b.x - c.x;
18597 this.resetConstraints();
18598 this.setXConstraint(leftSpace - (pad.left||0), // left
18599 c.width - leftSpace - b.width - (pad.right||0) //right
18601 this.setYConstraint(topSpace - (pad.top||0), //top
18602 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18607 * Returns a reference to the linked element
18609 * @return {HTMLElement} the html element
18611 getEl: function() {
18612 if (!this._domRef) {
18613 this._domRef = Roo.getDom(this.id);
18616 return this._domRef;
18620 * Returns a reference to the actual element to drag. By default this is
18621 * the same as the html element, but it can be assigned to another
18622 * element. An example of this can be found in Roo.dd.DDProxy
18623 * @method getDragEl
18624 * @return {HTMLElement} the html element
18626 getDragEl: function() {
18627 return Roo.getDom(this.dragElId);
18631 * Sets up the DragDrop object. Must be called in the constructor of any
18632 * Roo.dd.DragDrop subclass
18634 * @param id the id of the linked element
18635 * @param {String} sGroup the group of related items
18636 * @param {object} config configuration attributes
18638 init: function(id, sGroup, config) {
18639 this.initTarget(id, sGroup, config);
18640 if (!Roo.isTouch) {
18641 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18643 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18644 // Event.on(this.id, "selectstart", Event.preventDefault);
18648 * Initializes Targeting functionality only... the object does not
18649 * get a mousedown handler.
18650 * @method initTarget
18651 * @param id the id of the linked element
18652 * @param {String} sGroup the group of related items
18653 * @param {object} config configuration attributes
18655 initTarget: function(id, sGroup, config) {
18657 // configuration attributes
18658 this.config = config || {};
18660 // create a local reference to the drag and drop manager
18661 this.DDM = Roo.dd.DDM;
18662 // initialize the groups array
18665 // assume that we have an element reference instead of an id if the
18666 // parameter is not a string
18667 if (typeof id !== "string") {
18674 // add to an interaction group
18675 this.addToGroup((sGroup) ? sGroup : "default");
18677 // We don't want to register this as the handle with the manager
18678 // so we just set the id rather than calling the setter.
18679 this.handleElId = id;
18681 // the linked element is the element that gets dragged by default
18682 this.setDragElId(id);
18684 // by default, clicked anchors will not start drag operations.
18685 this.invalidHandleTypes = { A: "A" };
18686 this.invalidHandleIds = {};
18687 this.invalidHandleClasses = [];
18689 this.applyConfig();
18691 this.handleOnAvailable();
18695 * Applies the configuration parameters that were passed into the constructor.
18696 * This is supposed to happen at each level through the inheritance chain. So
18697 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18698 * DragDrop in order to get all of the parameters that are available in
18700 * @method applyConfig
18702 applyConfig: function() {
18704 // configurable properties:
18705 // padding, isTarget, maintainOffset, primaryButtonOnly
18706 this.padding = this.config.padding || [0, 0, 0, 0];
18707 this.isTarget = (this.config.isTarget !== false);
18708 this.maintainOffset = (this.config.maintainOffset);
18709 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18714 * Executed when the linked element is available
18715 * @method handleOnAvailable
18718 handleOnAvailable: function() {
18719 this.available = true;
18720 this.resetConstraints();
18721 this.onAvailable();
18725 * Configures the padding for the target zone in px. Effectively expands
18726 * (or reduces) the virtual object size for targeting calculations.
18727 * Supports css-style shorthand; if only one parameter is passed, all sides
18728 * will have that padding, and if only two are passed, the top and bottom
18729 * will have the first param, the left and right the second.
18730 * @method setPadding
18731 * @param {int} iTop Top pad
18732 * @param {int} iRight Right pad
18733 * @param {int} iBot Bot pad
18734 * @param {int} iLeft Left pad
18736 setPadding: function(iTop, iRight, iBot, iLeft) {
18737 // this.padding = [iLeft, iRight, iTop, iBot];
18738 if (!iRight && 0 !== iRight) {
18739 this.padding = [iTop, iTop, iTop, iTop];
18740 } else if (!iBot && 0 !== iBot) {
18741 this.padding = [iTop, iRight, iTop, iRight];
18743 this.padding = [iTop, iRight, iBot, iLeft];
18748 * Stores the initial placement of the linked element.
18749 * @method setInitialPosition
18750 * @param {int} diffX the X offset, default 0
18751 * @param {int} diffY the Y offset, default 0
18753 setInitPosition: function(diffX, diffY) {
18754 var el = this.getEl();
18756 if (!this.DDM.verifyEl(el)) {
18760 var dx = diffX || 0;
18761 var dy = diffY || 0;
18763 var p = Dom.getXY( el );
18765 this.initPageX = p[0] - dx;
18766 this.initPageY = p[1] - dy;
18768 this.lastPageX = p[0];
18769 this.lastPageY = p[1];
18772 this.setStartPosition(p);
18776 * Sets the start position of the element. This is set when the obj
18777 * is initialized, the reset when a drag is started.
18778 * @method setStartPosition
18779 * @param pos current position (from previous lookup)
18782 setStartPosition: function(pos) {
18783 var p = pos || Dom.getXY( this.getEl() );
18784 this.deltaSetXY = null;
18786 this.startPageX = p[0];
18787 this.startPageY = p[1];
18791 * Add this instance to a group of related drag/drop objects. All
18792 * instances belong to at least one group, and can belong to as many
18793 * groups as needed.
18794 * @method addToGroup
18795 * @param sGroup {string} the name of the group
18797 addToGroup: function(sGroup) {
18798 this.groups[sGroup] = true;
18799 this.DDM.regDragDrop(this, sGroup);
18803 * Remove's this instance from the supplied interaction group
18804 * @method removeFromGroup
18805 * @param {string} sGroup The group to drop
18807 removeFromGroup: function(sGroup) {
18808 if (this.groups[sGroup]) {
18809 delete this.groups[sGroup];
18812 this.DDM.removeDDFromGroup(this, sGroup);
18816 * Allows you to specify that an element other than the linked element
18817 * will be moved with the cursor during a drag
18818 * @method setDragElId
18819 * @param id {string} the id of the element that will be used to initiate the drag
18821 setDragElId: function(id) {
18822 this.dragElId = id;
18826 * Allows you to specify a child of the linked element that should be
18827 * used to initiate the drag operation. An example of this would be if
18828 * you have a content div with text and links. Clicking anywhere in the
18829 * content area would normally start the drag operation. Use this method
18830 * to specify that an element inside of the content div is the element
18831 * that starts the drag operation.
18832 * @method setHandleElId
18833 * @param id {string} the id of the element that will be used to
18834 * initiate the drag.
18836 setHandleElId: function(id) {
18837 if (typeof id !== "string") {
18840 this.handleElId = id;
18841 this.DDM.regHandle(this.id, id);
18845 * Allows you to set an element outside of the linked element as a drag
18847 * @method setOuterHandleElId
18848 * @param id the id of the element that will be used to initiate the drag
18850 setOuterHandleElId: function(id) {
18851 if (typeof id !== "string") {
18854 Event.on(id, "mousedown",
18855 this.handleMouseDown, this);
18856 this.setHandleElId(id);
18858 this.hasOuterHandles = true;
18862 * Remove all drag and drop hooks for this element
18865 unreg: function() {
18866 Event.un(this.id, "mousedown",
18867 this.handleMouseDown);
18868 Event.un(this.id, "touchstart",
18869 this.handleMouseDown);
18870 this._domRef = null;
18871 this.DDM._remove(this);
18874 destroy : function(){
18879 * Returns true if this instance is locked, or the drag drop mgr is locked
18880 * (meaning that all drag/drop is disabled on the page.)
18882 * @return {boolean} true if this obj or all drag/drop is locked, else
18885 isLocked: function() {
18886 return (this.DDM.isLocked() || this.locked);
18890 * Fired when this object is clicked
18891 * @method handleMouseDown
18893 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18896 handleMouseDown: function(e, oDD){
18898 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18899 //Roo.log('not touch/ button !=0');
18902 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18903 return; // double touch..
18907 if (this.isLocked()) {
18908 //Roo.log('locked');
18912 this.DDM.refreshCache(this.groups);
18913 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18914 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18915 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18916 //Roo.log('no outer handes or not over target');
18919 // Roo.log('check validator');
18920 if (this.clickValidator(e)) {
18921 // Roo.log('validate success');
18922 // set the initial element position
18923 this.setStartPosition();
18926 this.b4MouseDown(e);
18927 this.onMouseDown(e);
18929 this.DDM.handleMouseDown(e, this);
18931 this.DDM.stopEvent(e);
18939 clickValidator: function(e) {
18940 var target = e.getTarget();
18941 return ( this.isValidHandleChild(target) &&
18942 (this.id == this.handleElId ||
18943 this.DDM.handleWasClicked(target, this.id)) );
18947 * Allows you to specify a tag name that should not start a drag operation
18948 * when clicked. This is designed to facilitate embedding links within a
18949 * drag handle that do something other than start the drag.
18950 * @method addInvalidHandleType
18951 * @param {string} tagName the type of element to exclude
18953 addInvalidHandleType: function(tagName) {
18954 var type = tagName.toUpperCase();
18955 this.invalidHandleTypes[type] = type;
18959 * Lets you to specify an element id for a child of a drag handle
18960 * that should not initiate a drag
18961 * @method addInvalidHandleId
18962 * @param {string} id the element id of the element you wish to ignore
18964 addInvalidHandleId: function(id) {
18965 if (typeof id !== "string") {
18968 this.invalidHandleIds[id] = id;
18972 * Lets you specify a css class of elements that will not initiate a drag
18973 * @method addInvalidHandleClass
18974 * @param {string} cssClass the class of the elements you wish to ignore
18976 addInvalidHandleClass: function(cssClass) {
18977 this.invalidHandleClasses.push(cssClass);
18981 * Unsets an excluded tag name set by addInvalidHandleType
18982 * @method removeInvalidHandleType
18983 * @param {string} tagName the type of element to unexclude
18985 removeInvalidHandleType: function(tagName) {
18986 var type = tagName.toUpperCase();
18987 // this.invalidHandleTypes[type] = null;
18988 delete this.invalidHandleTypes[type];
18992 * Unsets an invalid handle id
18993 * @method removeInvalidHandleId
18994 * @param {string} id the id of the element to re-enable
18996 removeInvalidHandleId: function(id) {
18997 if (typeof id !== "string") {
19000 delete this.invalidHandleIds[id];
19004 * Unsets an invalid css class
19005 * @method removeInvalidHandleClass
19006 * @param {string} cssClass the class of the element(s) you wish to
19009 removeInvalidHandleClass: function(cssClass) {
19010 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19011 if (this.invalidHandleClasses[i] == cssClass) {
19012 delete this.invalidHandleClasses[i];
19018 * Checks the tag exclusion list to see if this click should be ignored
19019 * @method isValidHandleChild
19020 * @param {HTMLElement} node the HTMLElement to evaluate
19021 * @return {boolean} true if this is a valid tag type, false if not
19023 isValidHandleChild: function(node) {
19026 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19029 nodeName = node.nodeName.toUpperCase();
19031 nodeName = node.nodeName;
19033 valid = valid && !this.invalidHandleTypes[nodeName];
19034 valid = valid && !this.invalidHandleIds[node.id];
19036 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19037 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19046 * Create the array of horizontal tick marks if an interval was specified
19047 * in setXConstraint().
19048 * @method setXTicks
19051 setXTicks: function(iStartX, iTickSize) {
19053 this.xTickSize = iTickSize;
19057 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19059 this.xTicks[this.xTicks.length] = i;
19064 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19066 this.xTicks[this.xTicks.length] = i;
19071 this.xTicks.sort(this.DDM.numericSort) ;
19075 * Create the array of vertical tick marks if an interval was specified in
19076 * setYConstraint().
19077 * @method setYTicks
19080 setYTicks: function(iStartY, iTickSize) {
19082 this.yTickSize = iTickSize;
19086 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19088 this.yTicks[this.yTicks.length] = i;
19093 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19095 this.yTicks[this.yTicks.length] = i;
19100 this.yTicks.sort(this.DDM.numericSort) ;
19104 * By default, the element can be dragged any place on the screen. Use
19105 * this method to limit the horizontal travel of the element. Pass in
19106 * 0,0 for the parameters if you want to lock the drag to the y axis.
19107 * @method setXConstraint
19108 * @param {int} iLeft the number of pixels the element can move to the left
19109 * @param {int} iRight the number of pixels the element can move to the
19111 * @param {int} iTickSize optional parameter for specifying that the
19113 * should move iTickSize pixels at a time.
19115 setXConstraint: function(iLeft, iRight, iTickSize) {
19116 this.leftConstraint = iLeft;
19117 this.rightConstraint = iRight;
19119 this.minX = this.initPageX - iLeft;
19120 this.maxX = this.initPageX + iRight;
19121 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19123 this.constrainX = true;
19127 * Clears any constraints applied to this instance. Also clears ticks
19128 * since they can't exist independent of a constraint at this time.
19129 * @method clearConstraints
19131 clearConstraints: function() {
19132 this.constrainX = false;
19133 this.constrainY = false;
19138 * Clears any tick interval defined for this instance
19139 * @method clearTicks
19141 clearTicks: function() {
19142 this.xTicks = null;
19143 this.yTicks = null;
19144 this.xTickSize = 0;
19145 this.yTickSize = 0;
19149 * By default, the element can be dragged any place on the screen. Set
19150 * this to limit the vertical travel of the element. Pass in 0,0 for the
19151 * parameters if you want to lock the drag to the x axis.
19152 * @method setYConstraint
19153 * @param {int} iUp the number of pixels the element can move up
19154 * @param {int} iDown the number of pixels the element can move down
19155 * @param {int} iTickSize optional parameter for specifying that the
19156 * element should move iTickSize pixels at a time.
19158 setYConstraint: function(iUp, iDown, iTickSize) {
19159 this.topConstraint = iUp;
19160 this.bottomConstraint = iDown;
19162 this.minY = this.initPageY - iUp;
19163 this.maxY = this.initPageY + iDown;
19164 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19166 this.constrainY = true;
19171 * resetConstraints must be called if you manually reposition a dd element.
19172 * @method resetConstraints
19173 * @param {boolean} maintainOffset
19175 resetConstraints: function() {
19178 // Maintain offsets if necessary
19179 if (this.initPageX || this.initPageX === 0) {
19180 // figure out how much this thing has moved
19181 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19182 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19184 this.setInitPosition(dx, dy);
19186 // This is the first time we have detected the element's position
19188 this.setInitPosition();
19191 if (this.constrainX) {
19192 this.setXConstraint( this.leftConstraint,
19193 this.rightConstraint,
19197 if (this.constrainY) {
19198 this.setYConstraint( this.topConstraint,
19199 this.bottomConstraint,
19205 * Normally the drag element is moved pixel by pixel, but we can specify
19206 * that it move a number of pixels at a time. This method resolves the
19207 * location when we have it set up like this.
19209 * @param {int} val where we want to place the object
19210 * @param {int[]} tickArray sorted array of valid points
19211 * @return {int} the closest tick
19214 getTick: function(val, tickArray) {
19217 // If tick interval is not defined, it is effectively 1 pixel,
19218 // so we return the value passed to us.
19220 } else if (tickArray[0] >= val) {
19221 // The value is lower than the first tick, so we return the first
19223 return tickArray[0];
19225 for (var i=0, len=tickArray.length; i<len; ++i) {
19227 if (tickArray[next] && tickArray[next] >= val) {
19228 var diff1 = val - tickArray[i];
19229 var diff2 = tickArray[next] - val;
19230 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19234 // The value is larger than the last tick, so we return the last
19236 return tickArray[tickArray.length - 1];
19243 * @return {string} string representation of the dd obj
19245 toString: function() {
19246 return ("DragDrop " + this.id);
19254 * Ext JS Library 1.1.1
19255 * Copyright(c) 2006-2007, Ext JS, LLC.
19257 * Originally Released Under LGPL - original licence link has changed is not relivant.
19260 * <script type="text/javascript">
19265 * The drag and drop utility provides a framework for building drag and drop
19266 * applications. In addition to enabling drag and drop for specific elements,
19267 * the drag and drop elements are tracked by the manager class, and the
19268 * interactions between the various elements are tracked during the drag and
19269 * the implementing code is notified about these important moments.
19272 // Only load the library once. Rewriting the manager class would orphan
19273 // existing drag and drop instances.
19274 if (!Roo.dd.DragDropMgr) {
19277 * @class Roo.dd.DragDropMgr
19278 * DragDropMgr is a singleton that tracks the element interaction for
19279 * all DragDrop items in the window. Generally, you will not call
19280 * this class directly, but it does have helper methods that could
19281 * be useful in your DragDrop implementations.
19284 Roo.dd.DragDropMgr = function() {
19286 var Event = Roo.EventManager;
19291 * Two dimensional Array of registered DragDrop objects. The first
19292 * dimension is the DragDrop item group, the second the DragDrop
19295 * @type {string: string}
19302 * Array of element ids defined as drag handles. Used to determine
19303 * if the element that generated the mousedown event is actually the
19304 * handle and not the html element itself.
19305 * @property handleIds
19306 * @type {string: string}
19313 * the DragDrop object that is currently being dragged
19314 * @property dragCurrent
19322 * the DragDrop object(s) that are being hovered over
19323 * @property dragOvers
19331 * the X distance between the cursor and the object being dragged
19340 * the Y distance between the cursor and the object being dragged
19349 * Flag to determine if we should prevent the default behavior of the
19350 * events we define. By default this is true, but this can be set to
19351 * false if you need the default behavior (not recommended)
19352 * @property preventDefault
19356 preventDefault: true,
19359 * Flag to determine if we should stop the propagation of the events
19360 * we generate. This is true by default but you may want to set it to
19361 * false if the html element contains other features that require the
19363 * @property stopPropagation
19367 stopPropagation: true,
19370 * Internal flag that is set to true when drag and drop has been
19372 * @property initialized
19379 * All drag and drop can be disabled.
19387 * Called the first time an element is registered.
19393 this.initialized = true;
19397 * In point mode, drag and drop interaction is defined by the
19398 * location of the cursor during the drag/drop
19406 * In intersect mode, drag and drop interactio nis defined by the
19407 * overlap of two or more drag and drop objects.
19408 * @property INTERSECT
19415 * The current drag and drop mode. Default: POINT
19423 * Runs method on all drag and drop objects
19424 * @method _execOnAll
19428 _execOnAll: function(sMethod, args) {
19429 for (var i in this.ids) {
19430 for (var j in this.ids[i]) {
19431 var oDD = this.ids[i][j];
19432 if (! this.isTypeOfDD(oDD)) {
19435 oDD[sMethod].apply(oDD, args);
19441 * Drag and drop initialization. Sets up the global event handlers
19446 _onLoad: function() {
19450 if (!Roo.isTouch) {
19451 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19452 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19454 Event.on(document, "touchend", this.handleMouseUp, this, true);
19455 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19457 Event.on(window, "unload", this._onUnload, this, true);
19458 Event.on(window, "resize", this._onResize, this, true);
19459 // Event.on(window, "mouseout", this._test);
19464 * Reset constraints on all drag and drop objs
19465 * @method _onResize
19469 _onResize: function(e) {
19470 this._execOnAll("resetConstraints", []);
19474 * Lock all drag and drop functionality
19478 lock: function() { this.locked = true; },
19481 * Unlock all drag and drop functionality
19485 unlock: function() { this.locked = false; },
19488 * Is drag and drop locked?
19490 * @return {boolean} True if drag and drop is locked, false otherwise.
19493 isLocked: function() { return this.locked; },
19496 * Location cache that is set for all drag drop objects when a drag is
19497 * initiated, cleared when the drag is finished.
19498 * @property locationCache
19505 * Set useCache to false if you want to force object the lookup of each
19506 * drag and drop linked element constantly during a drag.
19507 * @property useCache
19514 * The number of pixels that the mouse needs to move after the
19515 * mousedown before the drag is initiated. Default=3;
19516 * @property clickPixelThresh
19520 clickPixelThresh: 3,
19523 * The number of milliseconds after the mousedown event to initiate the
19524 * drag if we don't get a mouseup event. Default=1000
19525 * @property clickTimeThresh
19529 clickTimeThresh: 350,
19532 * Flag that indicates that either the drag pixel threshold or the
19533 * mousdown time threshold has been met
19534 * @property dragThreshMet
19539 dragThreshMet: false,
19542 * Timeout used for the click time threshold
19543 * @property clickTimeout
19548 clickTimeout: null,
19551 * The X position of the mousedown event stored for later use when a
19552 * drag threshold is met.
19561 * The Y position of the mousedown event stored for later use when a
19562 * drag threshold is met.
19571 * Each DragDrop instance must be registered with the DragDropMgr.
19572 * This is executed in DragDrop.init()
19573 * @method regDragDrop
19574 * @param {DragDrop} oDD the DragDrop object to register
19575 * @param {String} sGroup the name of the group this element belongs to
19578 regDragDrop: function(oDD, sGroup) {
19579 if (!this.initialized) { this.init(); }
19581 if (!this.ids[sGroup]) {
19582 this.ids[sGroup] = {};
19584 this.ids[sGroup][oDD.id] = oDD;
19588 * Removes the supplied dd instance from the supplied group. Executed
19589 * by DragDrop.removeFromGroup, so don't call this function directly.
19590 * @method removeDDFromGroup
19594 removeDDFromGroup: function(oDD, sGroup) {
19595 if (!this.ids[sGroup]) {
19596 this.ids[sGroup] = {};
19599 var obj = this.ids[sGroup];
19600 if (obj && obj[oDD.id]) {
19601 delete obj[oDD.id];
19606 * Unregisters a drag and drop item. This is executed in
19607 * DragDrop.unreg, use that method instead of calling this directly.
19612 _remove: function(oDD) {
19613 for (var g in oDD.groups) {
19614 if (g && this.ids[g][oDD.id]) {
19615 delete this.ids[g][oDD.id];
19618 delete this.handleIds[oDD.id];
19622 * Each DragDrop handle element must be registered. This is done
19623 * automatically when executing DragDrop.setHandleElId()
19624 * @method regHandle
19625 * @param {String} sDDId the DragDrop id this element is a handle for
19626 * @param {String} sHandleId the id of the element that is the drag
19630 regHandle: function(sDDId, sHandleId) {
19631 if (!this.handleIds[sDDId]) {
19632 this.handleIds[sDDId] = {};
19634 this.handleIds[sDDId][sHandleId] = sHandleId;
19638 * Utility function to determine if a given element has been
19639 * registered as a drag drop item.
19640 * @method isDragDrop
19641 * @param {String} id the element id to check
19642 * @return {boolean} true if this element is a DragDrop item,
19646 isDragDrop: function(id) {
19647 return ( this.getDDById(id) ) ? true : false;
19651 * Returns the drag and drop instances that are in all groups the
19652 * passed in instance belongs to.
19653 * @method getRelated
19654 * @param {DragDrop} p_oDD the obj to get related data for
19655 * @param {boolean} bTargetsOnly if true, only return targetable objs
19656 * @return {DragDrop[]} the related instances
19659 getRelated: function(p_oDD, bTargetsOnly) {
19661 for (var i in p_oDD.groups) {
19662 for (j in this.ids[i]) {
19663 var dd = this.ids[i][j];
19664 if (! this.isTypeOfDD(dd)) {
19667 if (!bTargetsOnly || dd.isTarget) {
19668 oDDs[oDDs.length] = dd;
19677 * Returns true if the specified dd target is a legal target for
19678 * the specifice drag obj
19679 * @method isLegalTarget
19680 * @param {DragDrop} the drag obj
19681 * @param {DragDrop} the target
19682 * @return {boolean} true if the target is a legal target for the
19686 isLegalTarget: function (oDD, oTargetDD) {
19687 var targets = this.getRelated(oDD, true);
19688 for (var i=0, len=targets.length;i<len;++i) {
19689 if (targets[i].id == oTargetDD.id) {
19698 * My goal is to be able to transparently determine if an object is
19699 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19700 * returns "object", oDD.constructor.toString() always returns
19701 * "DragDrop" and not the name of the subclass. So for now it just
19702 * evaluates a well-known variable in DragDrop.
19703 * @method isTypeOfDD
19704 * @param {Object} the object to evaluate
19705 * @return {boolean} true if typeof oDD = DragDrop
19708 isTypeOfDD: function (oDD) {
19709 return (oDD && oDD.__ygDragDrop);
19713 * Utility function to determine if a given element has been
19714 * registered as a drag drop handle for the given Drag Drop object.
19716 * @param {String} id the element id to check
19717 * @return {boolean} true if this element is a DragDrop handle, false
19721 isHandle: function(sDDId, sHandleId) {
19722 return ( this.handleIds[sDDId] &&
19723 this.handleIds[sDDId][sHandleId] );
19727 * Returns the DragDrop instance for a given id
19728 * @method getDDById
19729 * @param {String} id the id of the DragDrop object
19730 * @return {DragDrop} the drag drop object, null if it is not found
19733 getDDById: function(id) {
19734 for (var i in this.ids) {
19735 if (this.ids[i][id]) {
19736 return this.ids[i][id];
19743 * Fired after a registered DragDrop object gets the mousedown event.
19744 * Sets up the events required to track the object being dragged
19745 * @method handleMouseDown
19746 * @param {Event} e the event
19747 * @param oDD the DragDrop object being dragged
19751 handleMouseDown: function(e, oDD) {
19753 Roo.QuickTips.disable();
19755 this.currentTarget = e.getTarget();
19757 this.dragCurrent = oDD;
19759 var el = oDD.getEl();
19761 // track start position
19762 this.startX = e.getPageX();
19763 this.startY = e.getPageY();
19765 this.deltaX = this.startX - el.offsetLeft;
19766 this.deltaY = this.startY - el.offsetTop;
19768 this.dragThreshMet = false;
19770 this.clickTimeout = setTimeout(
19772 var DDM = Roo.dd.DDM;
19773 DDM.startDrag(DDM.startX, DDM.startY);
19775 this.clickTimeThresh );
19779 * Fired when either the drag pixel threshol or the mousedown hold
19780 * time threshold has been met.
19781 * @method startDrag
19782 * @param x {int} the X position of the original mousedown
19783 * @param y {int} the Y position of the original mousedown
19786 startDrag: function(x, y) {
19787 clearTimeout(this.clickTimeout);
19788 if (this.dragCurrent) {
19789 this.dragCurrent.b4StartDrag(x, y);
19790 this.dragCurrent.startDrag(x, y);
19792 this.dragThreshMet = true;
19796 * Internal function to handle the mouseup event. Will be invoked
19797 * from the context of the document.
19798 * @method handleMouseUp
19799 * @param {Event} e the event
19803 handleMouseUp: function(e) {
19806 Roo.QuickTips.enable();
19808 if (! this.dragCurrent) {
19812 clearTimeout(this.clickTimeout);
19814 if (this.dragThreshMet) {
19815 this.fireEvents(e, true);
19825 * Utility to stop event propagation and event default, if these
19826 * features are turned on.
19827 * @method stopEvent
19828 * @param {Event} e the event as returned by this.getEvent()
19831 stopEvent: function(e){
19832 if(this.stopPropagation) {
19833 e.stopPropagation();
19836 if (this.preventDefault) {
19837 e.preventDefault();
19842 * Internal function to clean up event handlers after the drag
19843 * operation is complete
19845 * @param {Event} e the event
19849 stopDrag: function(e) {
19850 // Fire the drag end event for the item that was dragged
19851 if (this.dragCurrent) {
19852 if (this.dragThreshMet) {
19853 this.dragCurrent.b4EndDrag(e);
19854 this.dragCurrent.endDrag(e);
19857 this.dragCurrent.onMouseUp(e);
19860 this.dragCurrent = null;
19861 this.dragOvers = {};
19865 * Internal function to handle the mousemove event. Will be invoked
19866 * from the context of the html element.
19868 * @TODO figure out what we can do about mouse events lost when the
19869 * user drags objects beyond the window boundary. Currently we can
19870 * detect this in internet explorer by verifying that the mouse is
19871 * down during the mousemove event. Firefox doesn't give us the
19872 * button state on the mousemove event.
19873 * @method handleMouseMove
19874 * @param {Event} e the event
19878 handleMouseMove: function(e) {
19879 if (! this.dragCurrent) {
19883 // var button = e.which || e.button;
19885 // check for IE mouseup outside of page boundary
19886 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19888 return this.handleMouseUp(e);
19891 if (!this.dragThreshMet) {
19892 var diffX = Math.abs(this.startX - e.getPageX());
19893 var diffY = Math.abs(this.startY - e.getPageY());
19894 if (diffX > this.clickPixelThresh ||
19895 diffY > this.clickPixelThresh) {
19896 this.startDrag(this.startX, this.startY);
19900 if (this.dragThreshMet) {
19901 this.dragCurrent.b4Drag(e);
19902 this.dragCurrent.onDrag(e);
19903 if(!this.dragCurrent.moveOnly){
19904 this.fireEvents(e, false);
19914 * Iterates over all of the DragDrop elements to find ones we are
19915 * hovering over or dropping on
19916 * @method fireEvents
19917 * @param {Event} e the event
19918 * @param {boolean} isDrop is this a drop op or a mouseover op?
19922 fireEvents: function(e, isDrop) {
19923 var dc = this.dragCurrent;
19925 // If the user did the mouse up outside of the window, we could
19926 // get here even though we have ended the drag.
19927 if (!dc || dc.isLocked()) {
19931 var pt = e.getPoint();
19933 // cache the previous dragOver array
19939 var enterEvts = [];
19941 // Check to see if the object(s) we were hovering over is no longer
19942 // being hovered over so we can fire the onDragOut event
19943 for (var i in this.dragOvers) {
19945 var ddo = this.dragOvers[i];
19947 if (! this.isTypeOfDD(ddo)) {
19951 if (! this.isOverTarget(pt, ddo, this.mode)) {
19952 outEvts.push( ddo );
19955 oldOvers[i] = true;
19956 delete this.dragOvers[i];
19959 for (var sGroup in dc.groups) {
19961 if ("string" != typeof sGroup) {
19965 for (i in this.ids[sGroup]) {
19966 var oDD = this.ids[sGroup][i];
19967 if (! this.isTypeOfDD(oDD)) {
19971 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19972 if (this.isOverTarget(pt, oDD, this.mode)) {
19973 // look for drop interactions
19975 dropEvts.push( oDD );
19976 // look for drag enter and drag over interactions
19979 // initial drag over: dragEnter fires
19980 if (!oldOvers[oDD.id]) {
19981 enterEvts.push( oDD );
19982 // subsequent drag overs: dragOver fires
19984 overEvts.push( oDD );
19987 this.dragOvers[oDD.id] = oDD;
19995 if (outEvts.length) {
19996 dc.b4DragOut(e, outEvts);
19997 dc.onDragOut(e, outEvts);
20000 if (enterEvts.length) {
20001 dc.onDragEnter(e, enterEvts);
20004 if (overEvts.length) {
20005 dc.b4DragOver(e, overEvts);
20006 dc.onDragOver(e, overEvts);
20009 if (dropEvts.length) {
20010 dc.b4DragDrop(e, dropEvts);
20011 dc.onDragDrop(e, dropEvts);
20015 // fire dragout events
20017 for (i=0, len=outEvts.length; i<len; ++i) {
20018 dc.b4DragOut(e, outEvts[i].id);
20019 dc.onDragOut(e, outEvts[i].id);
20022 // fire enter events
20023 for (i=0,len=enterEvts.length; i<len; ++i) {
20024 // dc.b4DragEnter(e, oDD.id);
20025 dc.onDragEnter(e, enterEvts[i].id);
20028 // fire over events
20029 for (i=0,len=overEvts.length; i<len; ++i) {
20030 dc.b4DragOver(e, overEvts[i].id);
20031 dc.onDragOver(e, overEvts[i].id);
20034 // fire drop events
20035 for (i=0, len=dropEvts.length; i<len; ++i) {
20036 dc.b4DragDrop(e, dropEvts[i].id);
20037 dc.onDragDrop(e, dropEvts[i].id);
20042 // notify about a drop that did not find a target
20043 if (isDrop && !dropEvts.length) {
20044 dc.onInvalidDrop(e);
20050 * Helper function for getting the best match from the list of drag
20051 * and drop objects returned by the drag and drop events when we are
20052 * in INTERSECT mode. It returns either the first object that the
20053 * cursor is over, or the object that has the greatest overlap with
20054 * the dragged element.
20055 * @method getBestMatch
20056 * @param {DragDrop[]} dds The array of drag and drop objects
20058 * @return {DragDrop} The best single match
20061 getBestMatch: function(dds) {
20063 // Return null if the input is not what we expect
20064 //if (!dds || !dds.length || dds.length == 0) {
20066 // If there is only one item, it wins
20067 //} else if (dds.length == 1) {
20069 var len = dds.length;
20074 // Loop through the targeted items
20075 for (var i=0; i<len; ++i) {
20077 // If the cursor is over the object, it wins. If the
20078 // cursor is over multiple matches, the first one we come
20080 if (dd.cursorIsOver) {
20083 // Otherwise the object with the most overlap wins
20086 winner.overlap.getArea() < dd.overlap.getArea()) {
20097 * Refreshes the cache of the top-left and bottom-right points of the
20098 * drag and drop objects in the specified group(s). This is in the
20099 * format that is stored in the drag and drop instance, so typical
20102 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20106 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20108 * @TODO this really should be an indexed array. Alternatively this
20109 * method could accept both.
20110 * @method refreshCache
20111 * @param {Object} groups an associative array of groups to refresh
20114 refreshCache: function(groups) {
20115 for (var sGroup in groups) {
20116 if ("string" != typeof sGroup) {
20119 for (var i in this.ids[sGroup]) {
20120 var oDD = this.ids[sGroup][i];
20122 if (this.isTypeOfDD(oDD)) {
20123 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20124 var loc = this.getLocation(oDD);
20126 this.locationCache[oDD.id] = loc;
20128 delete this.locationCache[oDD.id];
20129 // this will unregister the drag and drop object if
20130 // the element is not in a usable state
20139 * This checks to make sure an element exists and is in the DOM. The
20140 * main purpose is to handle cases where innerHTML is used to remove
20141 * drag and drop objects from the DOM. IE provides an 'unspecified
20142 * error' when trying to access the offsetParent of such an element
20144 * @param {HTMLElement} el the element to check
20145 * @return {boolean} true if the element looks usable
20148 verifyEl: function(el) {
20153 parent = el.offsetParent;
20156 parent = el.offsetParent;
20167 * Returns a Region object containing the drag and drop element's position
20168 * and size, including the padding configured for it
20169 * @method getLocation
20170 * @param {DragDrop} oDD the drag and drop object to get the
20172 * @return {Roo.lib.Region} a Region object representing the total area
20173 * the element occupies, including any padding
20174 * the instance is configured for.
20177 getLocation: function(oDD) {
20178 if (! this.isTypeOfDD(oDD)) {
20182 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20185 pos= Roo.lib.Dom.getXY(el);
20193 x2 = x1 + el.offsetWidth;
20195 y2 = y1 + el.offsetHeight;
20197 t = y1 - oDD.padding[0];
20198 r = x2 + oDD.padding[1];
20199 b = y2 + oDD.padding[2];
20200 l = x1 - oDD.padding[3];
20202 return new Roo.lib.Region( t, r, b, l );
20206 * Checks the cursor location to see if it over the target
20207 * @method isOverTarget
20208 * @param {Roo.lib.Point} pt The point to evaluate
20209 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20210 * @return {boolean} true if the mouse is over the target
20214 isOverTarget: function(pt, oTarget, intersect) {
20215 // use cache if available
20216 var loc = this.locationCache[oTarget.id];
20217 if (!loc || !this.useCache) {
20218 loc = this.getLocation(oTarget);
20219 this.locationCache[oTarget.id] = loc;
20227 oTarget.cursorIsOver = loc.contains( pt );
20229 // DragDrop is using this as a sanity check for the initial mousedown
20230 // in this case we are done. In POINT mode, if the drag obj has no
20231 // contraints, we are also done. Otherwise we need to evaluate the
20232 // location of the target as related to the actual location of the
20233 // dragged element.
20234 var dc = this.dragCurrent;
20235 if (!dc || !dc.getTargetCoord ||
20236 (!intersect && !dc.constrainX && !dc.constrainY)) {
20237 return oTarget.cursorIsOver;
20240 oTarget.overlap = null;
20242 // Get the current location of the drag element, this is the
20243 // location of the mouse event less the delta that represents
20244 // where the original mousedown happened on the element. We
20245 // need to consider constraints and ticks as well.
20246 var pos = dc.getTargetCoord(pt.x, pt.y);
20248 var el = dc.getDragEl();
20249 var curRegion = new Roo.lib.Region( pos.y,
20250 pos.x + el.offsetWidth,
20251 pos.y + el.offsetHeight,
20254 var overlap = curRegion.intersect(loc);
20257 oTarget.overlap = overlap;
20258 return (intersect) ? true : oTarget.cursorIsOver;
20265 * unload event handler
20266 * @method _onUnload
20270 _onUnload: function(e, me) {
20271 Roo.dd.DragDropMgr.unregAll();
20275 * Cleans up the drag and drop events and objects.
20280 unregAll: function() {
20282 if (this.dragCurrent) {
20284 this.dragCurrent = null;
20287 this._execOnAll("unreg", []);
20289 for (i in this.elementCache) {
20290 delete this.elementCache[i];
20293 this.elementCache = {};
20298 * A cache of DOM elements
20299 * @property elementCache
20306 * Get the wrapper for the DOM element specified
20307 * @method getElWrapper
20308 * @param {String} id the id of the element to get
20309 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20311 * @deprecated This wrapper isn't that useful
20314 getElWrapper: function(id) {
20315 var oWrapper = this.elementCache[id];
20316 if (!oWrapper || !oWrapper.el) {
20317 oWrapper = this.elementCache[id] =
20318 new this.ElementWrapper(Roo.getDom(id));
20324 * Returns the actual DOM element
20325 * @method getElement
20326 * @param {String} id the id of the elment to get
20327 * @return {Object} The element
20328 * @deprecated use Roo.getDom instead
20331 getElement: function(id) {
20332 return Roo.getDom(id);
20336 * Returns the style property for the DOM element (i.e.,
20337 * document.getElById(id).style)
20339 * @param {String} id the id of the elment to get
20340 * @return {Object} The style property of the element
20341 * @deprecated use Roo.getDom instead
20344 getCss: function(id) {
20345 var el = Roo.getDom(id);
20346 return (el) ? el.style : null;
20350 * Inner class for cached elements
20351 * @class DragDropMgr.ElementWrapper
20356 ElementWrapper: function(el) {
20361 this.el = el || null;
20366 this.id = this.el && el.id;
20368 * A reference to the style property
20371 this.css = this.el && el.style;
20375 * Returns the X position of an html element
20377 * @param el the element for which to get the position
20378 * @return {int} the X coordinate
20380 * @deprecated use Roo.lib.Dom.getX instead
20383 getPosX: function(el) {
20384 return Roo.lib.Dom.getX(el);
20388 * Returns the Y position of an html element
20390 * @param el the element for which to get the position
20391 * @return {int} the Y coordinate
20392 * @deprecated use Roo.lib.Dom.getY instead
20395 getPosY: function(el) {
20396 return Roo.lib.Dom.getY(el);
20400 * Swap two nodes. In IE, we use the native method, for others we
20401 * emulate the IE behavior
20403 * @param n1 the first node to swap
20404 * @param n2 the other node to swap
20407 swapNode: function(n1, n2) {
20411 var p = n2.parentNode;
20412 var s = n2.nextSibling;
20415 p.insertBefore(n1, n2);
20416 } else if (n2 == n1.nextSibling) {
20417 p.insertBefore(n2, n1);
20419 n1.parentNode.replaceChild(n2, n1);
20420 p.insertBefore(n1, s);
20426 * Returns the current scroll position
20427 * @method getScroll
20431 getScroll: function () {
20432 var t, l, dde=document.documentElement, db=document.body;
20433 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20435 l = dde.scrollLeft;
20442 return { top: t, left: l };
20446 * Returns the specified element style property
20448 * @param {HTMLElement} el the element
20449 * @param {string} styleProp the style property
20450 * @return {string} The value of the style property
20451 * @deprecated use Roo.lib.Dom.getStyle
20454 getStyle: function(el, styleProp) {
20455 return Roo.fly(el).getStyle(styleProp);
20459 * Gets the scrollTop
20460 * @method getScrollTop
20461 * @return {int} the document's scrollTop
20464 getScrollTop: function () { return this.getScroll().top; },
20467 * Gets the scrollLeft
20468 * @method getScrollLeft
20469 * @return {int} the document's scrollTop
20472 getScrollLeft: function () { return this.getScroll().left; },
20475 * Sets the x/y position of an element to the location of the
20478 * @param {HTMLElement} moveEl The element to move
20479 * @param {HTMLElement} targetEl The position reference element
20482 moveToEl: function (moveEl, targetEl) {
20483 var aCoord = Roo.lib.Dom.getXY(targetEl);
20484 Roo.lib.Dom.setXY(moveEl, aCoord);
20488 * Numeric array sort function
20489 * @method numericSort
20492 numericSort: function(a, b) { return (a - b); },
20496 * @property _timeoutCount
20503 * Trying to make the load order less important. Without this we get
20504 * an error if this file is loaded before the Event Utility.
20505 * @method _addListeners
20509 _addListeners: function() {
20510 var DDM = Roo.dd.DDM;
20511 if ( Roo.lib.Event && document ) {
20514 if (DDM._timeoutCount > 2000) {
20516 setTimeout(DDM._addListeners, 10);
20517 if (document && document.body) {
20518 DDM._timeoutCount += 1;
20525 * Recursively searches the immediate parent and all child nodes for
20526 * the handle element in order to determine wheter or not it was
20528 * @method handleWasClicked
20529 * @param node the html element to inspect
20532 handleWasClicked: function(node, id) {
20533 if (this.isHandle(id, node.id)) {
20536 // check to see if this is a text node child of the one we want
20537 var p = node.parentNode;
20540 if (this.isHandle(id, p.id)) {
20555 // shorter alias, save a few bytes
20556 Roo.dd.DDM = Roo.dd.DragDropMgr;
20557 Roo.dd.DDM._addListeners();
20561 * Ext JS Library 1.1.1
20562 * Copyright(c) 2006-2007, Ext JS, LLC.
20564 * Originally Released Under LGPL - original licence link has changed is not relivant.
20567 * <script type="text/javascript">
20572 * A DragDrop implementation where the linked element follows the
20573 * mouse cursor during a drag.
20574 * @extends Roo.dd.DragDrop
20576 * @param {String} id the id of the linked element
20577 * @param {String} sGroup the group of related DragDrop items
20578 * @param {object} config an object containing configurable attributes
20579 * Valid properties for DD:
20582 Roo.dd.DD = function(id, sGroup, config) {
20584 this.init(id, sGroup, config);
20588 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20591 * When set to true, the utility automatically tries to scroll the browser
20592 * window wehn a drag and drop element is dragged near the viewport boundary.
20593 * Defaults to true.
20600 * Sets the pointer offset to the distance between the linked element's top
20601 * left corner and the location the element was clicked
20602 * @method autoOffset
20603 * @param {int} iPageX the X coordinate of the click
20604 * @param {int} iPageY the Y coordinate of the click
20606 autoOffset: function(iPageX, iPageY) {
20607 var x = iPageX - this.startPageX;
20608 var y = iPageY - this.startPageY;
20609 this.setDelta(x, y);
20613 * Sets the pointer offset. You can call this directly to force the
20614 * offset to be in a particular location (e.g., pass in 0,0 to set it
20615 * to the center of the object)
20617 * @param {int} iDeltaX the distance from the left
20618 * @param {int} iDeltaY the distance from the top
20620 setDelta: function(iDeltaX, iDeltaY) {
20621 this.deltaX = iDeltaX;
20622 this.deltaY = iDeltaY;
20626 * Sets the drag element to the location of the mousedown or click event,
20627 * maintaining the cursor location relative to the location on the element
20628 * that was clicked. Override this if you want to place the element in a
20629 * location other than where the cursor is.
20630 * @method setDragElPos
20631 * @param {int} iPageX the X coordinate of the mousedown or drag event
20632 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20634 setDragElPos: function(iPageX, iPageY) {
20635 // the first time we do this, we are going to check to make sure
20636 // the element has css positioning
20638 var el = this.getDragEl();
20639 this.alignElWithMouse(el, iPageX, iPageY);
20643 * Sets the element to the location of the mousedown or click event,
20644 * maintaining the cursor location relative to the location on the element
20645 * that was clicked. Override this if you want to place the element in a
20646 * location other than where the cursor is.
20647 * @method alignElWithMouse
20648 * @param {HTMLElement} el the element to move
20649 * @param {int} iPageX the X coordinate of the mousedown or drag event
20650 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20652 alignElWithMouse: function(el, iPageX, iPageY) {
20653 var oCoord = this.getTargetCoord(iPageX, iPageY);
20654 var fly = el.dom ? el : Roo.fly(el);
20655 if (!this.deltaSetXY) {
20656 var aCoord = [oCoord.x, oCoord.y];
20658 var newLeft = fly.getLeft(true);
20659 var newTop = fly.getTop(true);
20660 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20662 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20665 this.cachePosition(oCoord.x, oCoord.y);
20666 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20671 * Saves the most recent position so that we can reset the constraints and
20672 * tick marks on-demand. We need to know this so that we can calculate the
20673 * number of pixels the element is offset from its original position.
20674 * @method cachePosition
20675 * @param iPageX the current x position (optional, this just makes it so we
20676 * don't have to look it up again)
20677 * @param iPageY the current y position (optional, this just makes it so we
20678 * don't have to look it up again)
20680 cachePosition: function(iPageX, iPageY) {
20682 this.lastPageX = iPageX;
20683 this.lastPageY = iPageY;
20685 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20686 this.lastPageX = aCoord[0];
20687 this.lastPageY = aCoord[1];
20692 * Auto-scroll the window if the dragged object has been moved beyond the
20693 * visible window boundary.
20694 * @method autoScroll
20695 * @param {int} x the drag element's x position
20696 * @param {int} y the drag element's y position
20697 * @param {int} h the height of the drag element
20698 * @param {int} w the width of the drag element
20701 autoScroll: function(x, y, h, w) {
20704 // The client height
20705 var clientH = Roo.lib.Dom.getViewWidth();
20707 // The client width
20708 var clientW = Roo.lib.Dom.getViewHeight();
20710 // The amt scrolled down
20711 var st = this.DDM.getScrollTop();
20713 // The amt scrolled right
20714 var sl = this.DDM.getScrollLeft();
20716 // Location of the bottom of the element
20719 // Location of the right of the element
20722 // The distance from the cursor to the bottom of the visible area,
20723 // adjusted so that we don't scroll if the cursor is beyond the
20724 // element drag constraints
20725 var toBot = (clientH + st - y - this.deltaY);
20727 // The distance from the cursor to the right of the visible area
20728 var toRight = (clientW + sl - x - this.deltaX);
20731 // How close to the edge the cursor must be before we scroll
20732 // var thresh = (document.all) ? 100 : 40;
20735 // How many pixels to scroll per autoscroll op. This helps to reduce
20736 // clunky scrolling. IE is more sensitive about this ... it needs this
20737 // value to be higher.
20738 var scrAmt = (document.all) ? 80 : 30;
20740 // Scroll down if we are near the bottom of the visible page and the
20741 // obj extends below the crease
20742 if ( bot > clientH && toBot < thresh ) {
20743 window.scrollTo(sl, st + scrAmt);
20746 // Scroll up if the window is scrolled down and the top of the object
20747 // goes above the top border
20748 if ( y < st && st > 0 && y - st < thresh ) {
20749 window.scrollTo(sl, st - scrAmt);
20752 // Scroll right if the obj is beyond the right border and the cursor is
20753 // near the border.
20754 if ( right > clientW && toRight < thresh ) {
20755 window.scrollTo(sl + scrAmt, st);
20758 // Scroll left if the window has been scrolled to the right and the obj
20759 // extends past the left border
20760 if ( x < sl && sl > 0 && x - sl < thresh ) {
20761 window.scrollTo(sl - scrAmt, st);
20767 * Finds the location the element should be placed if we want to move
20768 * it to where the mouse location less the click offset would place us.
20769 * @method getTargetCoord
20770 * @param {int} iPageX the X coordinate of the click
20771 * @param {int} iPageY the Y coordinate of the click
20772 * @return an object that contains the coordinates (Object.x and Object.y)
20775 getTargetCoord: function(iPageX, iPageY) {
20778 var x = iPageX - this.deltaX;
20779 var y = iPageY - this.deltaY;
20781 if (this.constrainX) {
20782 if (x < this.minX) { x = this.minX; }
20783 if (x > this.maxX) { x = this.maxX; }
20786 if (this.constrainY) {
20787 if (y < this.minY) { y = this.minY; }
20788 if (y > this.maxY) { y = this.maxY; }
20791 x = this.getTick(x, this.xTicks);
20792 y = this.getTick(y, this.yTicks);
20799 * Sets up config options specific to this class. Overrides
20800 * Roo.dd.DragDrop, but all versions of this method through the
20801 * inheritance chain are called
20803 applyConfig: function() {
20804 Roo.dd.DD.superclass.applyConfig.call(this);
20805 this.scroll = (this.config.scroll !== false);
20809 * Event that fires prior to the onMouseDown event. Overrides
20812 b4MouseDown: function(e) {
20813 // this.resetConstraints();
20814 this.autoOffset(e.getPageX(),
20819 * Event that fires prior to the onDrag event. Overrides
20822 b4Drag: function(e) {
20823 this.setDragElPos(e.getPageX(),
20827 toString: function() {
20828 return ("DD " + this.id);
20831 //////////////////////////////////////////////////////////////////////////
20832 // Debugging ygDragDrop events that can be overridden
20833 //////////////////////////////////////////////////////////////////////////
20835 startDrag: function(x, y) {
20838 onDrag: function(e) {
20841 onDragEnter: function(e, id) {
20844 onDragOver: function(e, id) {
20847 onDragOut: function(e, id) {
20850 onDragDrop: function(e, id) {
20853 endDrag: function(e) {
20860 * Ext JS Library 1.1.1
20861 * Copyright(c) 2006-2007, Ext JS, LLC.
20863 * Originally Released Under LGPL - original licence link has changed is not relivant.
20866 * <script type="text/javascript">
20870 * @class Roo.dd.DDProxy
20871 * A DragDrop implementation that inserts an empty, bordered div into
20872 * the document that follows the cursor during drag operations. At the time of
20873 * the click, the frame div is resized to the dimensions of the linked html
20874 * element, and moved to the exact location of the linked element.
20876 * References to the "frame" element refer to the single proxy element that
20877 * was created to be dragged in place of all DDProxy elements on the
20880 * @extends Roo.dd.DD
20882 * @param {String} id the id of the linked html element
20883 * @param {String} sGroup the group of related DragDrop objects
20884 * @param {object} config an object containing configurable attributes
20885 * Valid properties for DDProxy in addition to those in DragDrop:
20886 * resizeFrame, centerFrame, dragElId
20888 Roo.dd.DDProxy = function(id, sGroup, config) {
20890 this.init(id, sGroup, config);
20896 * The default drag frame div id
20897 * @property Roo.dd.DDProxy.dragElId
20901 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20903 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20906 * By default we resize the drag frame to be the same size as the element
20907 * we want to drag (this is to get the frame effect). We can turn it off
20908 * if we want a different behavior.
20909 * @property resizeFrame
20915 * By default the frame is positioned exactly where the drag element is, so
20916 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20917 * you do not have constraints on the obj is to have the drag frame centered
20918 * around the cursor. Set centerFrame to true for this effect.
20919 * @property centerFrame
20922 centerFrame: false,
20925 * Creates the proxy element if it does not yet exist
20926 * @method createFrame
20928 createFrame: function() {
20930 var body = document.body;
20932 if (!body || !body.firstChild) {
20933 setTimeout( function() { self.createFrame(); }, 50 );
20937 var div = this.getDragEl();
20940 div = document.createElement("div");
20941 div.id = this.dragElId;
20944 s.position = "absolute";
20945 s.visibility = "hidden";
20947 s.border = "2px solid #aaa";
20950 // appendChild can blow up IE if invoked prior to the window load event
20951 // while rendering a table. It is possible there are other scenarios
20952 // that would cause this to happen as well.
20953 body.insertBefore(div, body.firstChild);
20958 * Initialization for the drag frame element. Must be called in the
20959 * constructor of all subclasses
20960 * @method initFrame
20962 initFrame: function() {
20963 this.createFrame();
20966 applyConfig: function() {
20967 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20969 this.resizeFrame = (this.config.resizeFrame !== false);
20970 this.centerFrame = (this.config.centerFrame);
20971 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20975 * Resizes the drag frame to the dimensions of the clicked object, positions
20976 * it over the object, and finally displays it
20977 * @method showFrame
20978 * @param {int} iPageX X click position
20979 * @param {int} iPageY Y click position
20982 showFrame: function(iPageX, iPageY) {
20983 var el = this.getEl();
20984 var dragEl = this.getDragEl();
20985 var s = dragEl.style;
20987 this._resizeProxy();
20989 if (this.centerFrame) {
20990 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20991 Math.round(parseInt(s.height, 10)/2) );
20994 this.setDragElPos(iPageX, iPageY);
20996 Roo.fly(dragEl).show();
21000 * The proxy is automatically resized to the dimensions of the linked
21001 * element when a drag is initiated, unless resizeFrame is set to false
21002 * @method _resizeProxy
21005 _resizeProxy: function() {
21006 if (this.resizeFrame) {
21007 var el = this.getEl();
21008 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21012 // overrides Roo.dd.DragDrop
21013 b4MouseDown: function(e) {
21014 var x = e.getPageX();
21015 var y = e.getPageY();
21016 this.autoOffset(x, y);
21017 this.setDragElPos(x, y);
21020 // overrides Roo.dd.DragDrop
21021 b4StartDrag: function(x, y) {
21022 // show the drag frame
21023 this.showFrame(x, y);
21026 // overrides Roo.dd.DragDrop
21027 b4EndDrag: function(e) {
21028 Roo.fly(this.getDragEl()).hide();
21031 // overrides Roo.dd.DragDrop
21032 // By default we try to move the element to the last location of the frame.
21033 // This is so that the default behavior mirrors that of Roo.dd.DD.
21034 endDrag: function(e) {
21036 var lel = this.getEl();
21037 var del = this.getDragEl();
21039 // Show the drag frame briefly so we can get its position
21040 del.style.visibility = "";
21043 // Hide the linked element before the move to get around a Safari
21045 lel.style.visibility = "hidden";
21046 Roo.dd.DDM.moveToEl(lel, del);
21047 del.style.visibility = "hidden";
21048 lel.style.visibility = "";
21053 beforeMove : function(){
21057 afterDrag : function(){
21061 toString: function() {
21062 return ("DDProxy " + this.id);
21068 * Ext JS Library 1.1.1
21069 * Copyright(c) 2006-2007, Ext JS, LLC.
21071 * Originally Released Under LGPL - original licence link has changed is not relivant.
21074 * <script type="text/javascript">
21078 * @class Roo.dd.DDTarget
21079 * A DragDrop implementation that does not move, but can be a drop
21080 * target. You would get the same result by simply omitting implementation
21081 * for the event callbacks, but this way we reduce the processing cost of the
21082 * event listener and the callbacks.
21083 * @extends Roo.dd.DragDrop
21085 * @param {String} id the id of the element that is a drop target
21086 * @param {String} sGroup the group of related DragDrop objects
21087 * @param {object} config an object containing configurable attributes
21088 * Valid properties for DDTarget in addition to those in
21092 Roo.dd.DDTarget = function(id, sGroup, config) {
21094 this.initTarget(id, sGroup, config);
21096 if (config.listeners || config.events) {
21097 Roo.dd.DragDrop.superclass.constructor.call(this, {
21098 listeners : config.listeners || {},
21099 events : config.events || {}
21104 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21105 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21106 toString: function() {
21107 return ("DDTarget " + this.id);
21112 * Ext JS Library 1.1.1
21113 * Copyright(c) 2006-2007, Ext JS, LLC.
21115 * Originally Released Under LGPL - original licence link has changed is not relivant.
21118 * <script type="text/javascript">
21123 * @class Roo.dd.ScrollManager
21124 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21125 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21128 Roo.dd.ScrollManager = function(){
21129 var ddm = Roo.dd.DragDropMgr;
21136 var onStop = function(e){
21141 var triggerRefresh = function(){
21142 if(ddm.dragCurrent){
21143 ddm.refreshCache(ddm.dragCurrent.groups);
21147 var doScroll = function(){
21148 if(ddm.dragCurrent){
21149 var dds = Roo.dd.ScrollManager;
21151 if(proc.el.scroll(proc.dir, dds.increment)){
21155 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21160 var clearProc = function(){
21162 clearInterval(proc.id);
21169 var startProc = function(el, dir){
21170 Roo.log('scroll startproc');
21174 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21177 var onFire = function(e, isDrop){
21179 if(isDrop || !ddm.dragCurrent){ return; }
21180 var dds = Roo.dd.ScrollManager;
21181 if(!dragEl || dragEl != ddm.dragCurrent){
21182 dragEl = ddm.dragCurrent;
21183 // refresh regions on drag start
21184 dds.refreshCache();
21187 var xy = Roo.lib.Event.getXY(e);
21188 var pt = new Roo.lib.Point(xy[0], xy[1]);
21189 for(var id in els){
21190 var el = els[id], r = el._region;
21191 if(r && r.contains(pt) && el.isScrollable()){
21192 if(r.bottom - pt.y <= dds.thresh){
21194 startProc(el, "down");
21197 }else if(r.right - pt.x <= dds.thresh){
21199 startProc(el, "left");
21202 }else if(pt.y - r.top <= dds.thresh){
21204 startProc(el, "up");
21207 }else if(pt.x - r.left <= dds.thresh){
21209 startProc(el, "right");
21218 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21219 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21223 * Registers new overflow element(s) to auto scroll
21224 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21226 register : function(el){
21227 if(el instanceof Array){
21228 for(var i = 0, len = el.length; i < len; i++) {
21229 this.register(el[i]);
21235 Roo.dd.ScrollManager.els = els;
21239 * Unregisters overflow element(s) so they are no longer scrolled
21240 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21242 unregister : function(el){
21243 if(el instanceof Array){
21244 for(var i = 0, len = el.length; i < len; i++) {
21245 this.unregister(el[i]);
21254 * The number of pixels from the edge of a container the pointer needs to be to
21255 * trigger scrolling (defaults to 25)
21261 * The number of pixels to scroll in each scroll increment (defaults to 50)
21267 * The frequency of scrolls in milliseconds (defaults to 500)
21273 * True to animate the scroll (defaults to true)
21279 * The animation duration in seconds -
21280 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21286 * Manually trigger a cache refresh.
21288 refreshCache : function(){
21289 for(var id in els){
21290 if(typeof els[id] == 'object'){ // for people extending the object prototype
21291 els[id]._region = els[id].getRegion();
21298 * Ext JS Library 1.1.1
21299 * Copyright(c) 2006-2007, Ext JS, LLC.
21301 * Originally Released Under LGPL - original licence link has changed is not relivant.
21304 * <script type="text/javascript">
21309 * @class Roo.dd.Registry
21310 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21311 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21314 Roo.dd.Registry = function(){
21317 var autoIdSeed = 0;
21319 var getId = function(el, autogen){
21320 if(typeof el == "string"){
21324 if(!id && autogen !== false){
21325 id = "roodd-" + (++autoIdSeed);
21333 * Register a drag drop element
21334 * @param {String|HTMLElement} element The id or DOM node to register
21335 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21336 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21337 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21338 * populated in the data object (if applicable):
21340 Value Description<br />
21341 --------- ------------------------------------------<br />
21342 handles Array of DOM nodes that trigger dragging<br />
21343 for the element being registered<br />
21344 isHandle True if the element passed in triggers<br />
21345 dragging itself, else false
21348 register : function(el, data){
21350 if(typeof el == "string"){
21351 el = document.getElementById(el);
21354 elements[getId(el)] = data;
21355 if(data.isHandle !== false){
21356 handles[data.ddel.id] = data;
21359 var hs = data.handles;
21360 for(var i = 0, len = hs.length; i < len; i++){
21361 handles[getId(hs[i])] = data;
21367 * Unregister a drag drop element
21368 * @param {String|HTMLElement} element The id or DOM node to unregister
21370 unregister : function(el){
21371 var id = getId(el, false);
21372 var data = elements[id];
21374 delete elements[id];
21376 var hs = data.handles;
21377 for(var i = 0, len = hs.length; i < len; i++){
21378 delete handles[getId(hs[i], false)];
21385 * Returns the handle registered for a DOM Node by id
21386 * @param {String|HTMLElement} id The DOM node or id to look up
21387 * @return {Object} handle The custom handle data
21389 getHandle : function(id){
21390 if(typeof id != "string"){ // must be element?
21393 return handles[id];
21397 * Returns the handle that is registered for the DOM node that is the target of the event
21398 * @param {Event} e The event
21399 * @return {Object} handle The custom handle data
21401 getHandleFromEvent : function(e){
21402 var t = Roo.lib.Event.getTarget(e);
21403 return t ? handles[t.id] : null;
21407 * Returns a custom data object that is registered for a DOM node by id
21408 * @param {String|HTMLElement} id The DOM node or id to look up
21409 * @return {Object} data The custom data
21411 getTarget : function(id){
21412 if(typeof id != "string"){ // must be element?
21415 return elements[id];
21419 * Returns a custom data object that is registered for the DOM node that is the target of the event
21420 * @param {Event} e The event
21421 * @return {Object} data The custom data
21423 getTargetFromEvent : function(e){
21424 var t = Roo.lib.Event.getTarget(e);
21425 return t ? elements[t.id] || handles[t.id] : null;
21430 * Ext JS Library 1.1.1
21431 * Copyright(c) 2006-2007, Ext JS, LLC.
21433 * Originally Released Under LGPL - original licence link has changed is not relivant.
21436 * <script type="text/javascript">
21441 * @class Roo.dd.StatusProxy
21442 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21443 * default drag proxy used by all Roo.dd components.
21445 * @param {Object} config
21447 Roo.dd.StatusProxy = function(config){
21448 Roo.apply(this, config);
21449 this.id = this.id || Roo.id();
21450 this.el = new Roo.Layer({
21452 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21453 {tag: "div", cls: "x-dd-drop-icon"},
21454 {tag: "div", cls: "x-dd-drag-ghost"}
21457 shadow: !config || config.shadow !== false
21459 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21460 this.dropStatus = this.dropNotAllowed;
21463 Roo.dd.StatusProxy.prototype = {
21465 * @cfg {String} dropAllowed
21466 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21468 dropAllowed : "x-dd-drop-ok",
21470 * @cfg {String} dropNotAllowed
21471 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21473 dropNotAllowed : "x-dd-drop-nodrop",
21476 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21477 * over the current target element.
21478 * @param {String} cssClass The css class for the new drop status indicator image
21480 setStatus : function(cssClass){
21481 cssClass = cssClass || this.dropNotAllowed;
21482 if(this.dropStatus != cssClass){
21483 this.el.replaceClass(this.dropStatus, cssClass);
21484 this.dropStatus = cssClass;
21489 * Resets the status indicator to the default dropNotAllowed value
21490 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21492 reset : function(clearGhost){
21493 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21494 this.dropStatus = this.dropNotAllowed;
21496 this.ghost.update("");
21501 * Updates the contents of the ghost element
21502 * @param {String} html The html that will replace the current innerHTML of the ghost element
21504 update : function(html){
21505 if(typeof html == "string"){
21506 this.ghost.update(html);
21508 this.ghost.update("");
21509 html.style.margin = "0";
21510 this.ghost.dom.appendChild(html);
21512 // ensure float = none set?? cant remember why though.
21513 var el = this.ghost.dom.firstChild;
21515 Roo.fly(el).setStyle('float', 'none');
21520 * Returns the underlying proxy {@link Roo.Layer}
21521 * @return {Roo.Layer} el
21523 getEl : function(){
21528 * Returns the ghost element
21529 * @return {Roo.Element} el
21531 getGhost : function(){
21537 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21539 hide : function(clear){
21547 * Stops the repair animation if it's currently running
21550 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21556 * Displays this proxy
21563 * Force the Layer to sync its shadow and shim positions to the element
21570 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21571 * invalid drop operation by the item being dragged.
21572 * @param {Array} xy The XY position of the element ([x, y])
21573 * @param {Function} callback The function to call after the repair is complete
21574 * @param {Object} scope The scope in which to execute the callback
21576 repair : function(xy, callback, scope){
21577 this.callback = callback;
21578 this.scope = scope;
21579 if(xy && this.animRepair !== false){
21580 this.el.addClass("x-dd-drag-repair");
21581 this.el.hideUnders(true);
21582 this.anim = this.el.shift({
21583 duration: this.repairDuration || .5,
21587 callback: this.afterRepair,
21591 this.afterRepair();
21596 afterRepair : function(){
21598 if(typeof this.callback == "function"){
21599 this.callback.call(this.scope || this);
21601 this.callback = null;
21606 * Ext JS Library 1.1.1
21607 * Copyright(c) 2006-2007, Ext JS, LLC.
21609 * Originally Released Under LGPL - original licence link has changed is not relivant.
21612 * <script type="text/javascript">
21616 * @class Roo.dd.DragSource
21617 * @extends Roo.dd.DDProxy
21618 * A simple class that provides the basic implementation needed to make any element draggable.
21620 * @param {String/HTMLElement/Element} el The container element
21621 * @param {Object} config
21623 Roo.dd.DragSource = function(el, config){
21624 this.el = Roo.get(el);
21625 this.dragData = {};
21627 Roo.apply(this, config);
21630 this.proxy = new Roo.dd.StatusProxy();
21633 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21634 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21636 this.dragging = false;
21639 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21641 * @cfg {String} dropAllowed
21642 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21644 dropAllowed : "x-dd-drop-ok",
21646 * @cfg {String} dropNotAllowed
21647 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21649 dropNotAllowed : "x-dd-drop-nodrop",
21652 * Returns the data object associated with this drag source
21653 * @return {Object} data An object containing arbitrary data
21655 getDragData : function(e){
21656 return this.dragData;
21660 onDragEnter : function(e, id){
21661 var target = Roo.dd.DragDropMgr.getDDById(id);
21662 this.cachedTarget = target;
21663 if(this.beforeDragEnter(target, e, id) !== false){
21664 if(target.isNotifyTarget){
21665 var status = target.notifyEnter(this, e, this.dragData);
21666 this.proxy.setStatus(status);
21668 this.proxy.setStatus(this.dropAllowed);
21671 if(this.afterDragEnter){
21673 * An empty function by default, but provided so that you can perform a custom action
21674 * when the dragged item enters the drop target by providing an implementation.
21675 * @param {Roo.dd.DragDrop} target The drop target
21676 * @param {Event} e The event object
21677 * @param {String} id The id of the dragged element
21678 * @method afterDragEnter
21680 this.afterDragEnter(target, e, id);
21686 * An empty function by default, but provided so that you can perform a custom action
21687 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21688 * @param {Roo.dd.DragDrop} target The drop target
21689 * @param {Event} e The event object
21690 * @param {String} id The id of the dragged element
21691 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21693 beforeDragEnter : function(target, e, id){
21698 alignElWithMouse: function() {
21699 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21704 onDragOver : function(e, id){
21705 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21706 if(this.beforeDragOver(target, e, id) !== false){
21707 if(target.isNotifyTarget){
21708 var status = target.notifyOver(this, e, this.dragData);
21709 this.proxy.setStatus(status);
21712 if(this.afterDragOver){
21714 * An empty function by default, but provided so that you can perform a custom action
21715 * while the dragged item is over the drop target by providing an implementation.
21716 * @param {Roo.dd.DragDrop} target The drop target
21717 * @param {Event} e The event object
21718 * @param {String} id The id of the dragged element
21719 * @method afterDragOver
21721 this.afterDragOver(target, e, id);
21727 * An empty function by default, but provided so that you can perform a custom action
21728 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21729 * @param {Roo.dd.DragDrop} target The drop target
21730 * @param {Event} e The event object
21731 * @param {String} id The id of the dragged element
21732 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21734 beforeDragOver : function(target, e, id){
21739 onDragOut : function(e, id){
21740 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21741 if(this.beforeDragOut(target, e, id) !== false){
21742 if(target.isNotifyTarget){
21743 target.notifyOut(this, e, this.dragData);
21745 this.proxy.reset();
21746 if(this.afterDragOut){
21748 * An empty function by default, but provided so that you can perform a custom action
21749 * after the dragged item is dragged out of the target without dropping.
21750 * @param {Roo.dd.DragDrop} target The drop target
21751 * @param {Event} e The event object
21752 * @param {String} id The id of the dragged element
21753 * @method afterDragOut
21755 this.afterDragOut(target, e, id);
21758 this.cachedTarget = null;
21762 * An empty function by default, but provided so that you can perform a custom action before the dragged
21763 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21764 * @param {Roo.dd.DragDrop} target The drop target
21765 * @param {Event} e The event object
21766 * @param {String} id The id of the dragged element
21767 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21769 beforeDragOut : function(target, e, id){
21774 onDragDrop : function(e, id){
21775 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21776 if(this.beforeDragDrop(target, e, id) !== false){
21777 if(target.isNotifyTarget){
21778 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21779 this.onValidDrop(target, e, id);
21781 this.onInvalidDrop(target, e, id);
21784 this.onValidDrop(target, e, id);
21787 if(this.afterDragDrop){
21789 * An empty function by default, but provided so that you can perform a custom action
21790 * after a valid drag drop has occurred by providing an implementation.
21791 * @param {Roo.dd.DragDrop} target The drop target
21792 * @param {Event} e The event object
21793 * @param {String} id The id of the dropped element
21794 * @method afterDragDrop
21796 this.afterDragDrop(target, e, id);
21799 delete this.cachedTarget;
21803 * An empty function by default, but provided so that you can perform a custom action before the dragged
21804 * item is dropped onto the target and optionally cancel the onDragDrop.
21805 * @param {Roo.dd.DragDrop} target The drop target
21806 * @param {Event} e The event object
21807 * @param {String} id The id of the dragged element
21808 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21810 beforeDragDrop : function(target, e, id){
21815 onValidDrop : function(target, e, id){
21817 if(this.afterValidDrop){
21819 * An empty function by default, but provided so that you can perform a custom action
21820 * after a valid drop has occurred by providing an implementation.
21821 * @param {Object} target The target DD
21822 * @param {Event} e The event object
21823 * @param {String} id The id of the dropped element
21824 * @method afterInvalidDrop
21826 this.afterValidDrop(target, e, id);
21831 getRepairXY : function(e, data){
21832 return this.el.getXY();
21836 onInvalidDrop : function(target, e, id){
21837 this.beforeInvalidDrop(target, e, id);
21838 if(this.cachedTarget){
21839 if(this.cachedTarget.isNotifyTarget){
21840 this.cachedTarget.notifyOut(this, e, this.dragData);
21842 this.cacheTarget = null;
21844 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21846 if(this.afterInvalidDrop){
21848 * An empty function by default, but provided so that you can perform a custom action
21849 * after an invalid drop has occurred by providing an implementation.
21850 * @param {Event} e The event object
21851 * @param {String} id The id of the dropped element
21852 * @method afterInvalidDrop
21854 this.afterInvalidDrop(e, id);
21859 afterRepair : function(){
21861 this.el.highlight(this.hlColor || "c3daf9");
21863 this.dragging = false;
21867 * An empty function by default, but provided so that you can perform a custom action after an invalid
21868 * drop has occurred.
21869 * @param {Roo.dd.DragDrop} target The drop target
21870 * @param {Event} e The event object
21871 * @param {String} id The id of the dragged element
21872 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21874 beforeInvalidDrop : function(target, e, id){
21879 handleMouseDown : function(e){
21880 if(this.dragging) {
21883 var data = this.getDragData(e);
21884 if(data && this.onBeforeDrag(data, e) !== false){
21885 this.dragData = data;
21887 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21892 * An empty function by default, but provided so that you can perform a custom action before the initial
21893 * drag event begins and optionally cancel it.
21894 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21895 * @param {Event} e The event object
21896 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21898 onBeforeDrag : function(data, e){
21903 * An empty function by default, but provided so that you can perform a custom action once the initial
21904 * drag event has begun. The drag cannot be canceled from this function.
21905 * @param {Number} x The x position of the click on the dragged object
21906 * @param {Number} y The y position of the click on the dragged object
21908 onStartDrag : Roo.emptyFn,
21910 // private - YUI override
21911 startDrag : function(x, y){
21912 this.proxy.reset();
21913 this.dragging = true;
21914 this.proxy.update("");
21915 this.onInitDrag(x, y);
21920 onInitDrag : function(x, y){
21921 var clone = this.el.dom.cloneNode(true);
21922 clone.id = Roo.id(); // prevent duplicate ids
21923 this.proxy.update(clone);
21924 this.onStartDrag(x, y);
21929 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21930 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21932 getProxy : function(){
21937 * Hides the drag source's {@link Roo.dd.StatusProxy}
21939 hideProxy : function(){
21941 this.proxy.reset(true);
21942 this.dragging = false;
21946 triggerCacheRefresh : function(){
21947 Roo.dd.DDM.refreshCache(this.groups);
21950 // private - override to prevent hiding
21951 b4EndDrag: function(e) {
21954 // private - override to prevent moving
21955 endDrag : function(e){
21956 this.onEndDrag(this.dragData, e);
21960 onEndDrag : function(data, e){
21963 // private - pin to cursor
21964 autoOffset : function(x, y) {
21965 this.setDelta(-12, -20);
21969 * Ext JS Library 1.1.1
21970 * Copyright(c) 2006-2007, Ext JS, LLC.
21972 * Originally Released Under LGPL - original licence link has changed is not relivant.
21975 * <script type="text/javascript">
21980 * @class Roo.dd.DropTarget
21981 * @extends Roo.dd.DDTarget
21982 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21983 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21985 * @param {String/HTMLElement/Element} el The container element
21986 * @param {Object} config
21988 Roo.dd.DropTarget = function(el, config){
21989 this.el = Roo.get(el);
21991 var listeners = false; ;
21992 if (config && config.listeners) {
21993 listeners= config.listeners;
21994 delete config.listeners;
21996 Roo.apply(this, config);
21998 if(this.containerScroll){
21999 Roo.dd.ScrollManager.register(this.el);
22003 * @scope Roo.dd.DropTarget
22008 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22009 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22010 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22012 * IMPORTANT : it should set this.overClass and this.dropAllowed
22014 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22015 * @param {Event} e The event
22016 * @param {Object} data An object containing arbitrary data supplied by the drag source
22022 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22023 * This method will be called on every mouse movement while the drag source is over the drop target.
22024 * This default implementation simply returns the dropAllowed config value.
22026 * IMPORTANT : it should set this.dropAllowed
22028 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22029 * @param {Event} e The event
22030 * @param {Object} data An object containing arbitrary data supplied by the drag source
22036 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22037 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22038 * overClass (if any) from the drop element.
22040 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22041 * @param {Event} e The event
22042 * @param {Object} data An object containing arbitrary data supplied by the drag source
22048 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22049 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22050 * implementation that does something to process the drop event and returns true so that the drag source's
22051 * repair action does not run.
22053 * IMPORTANT : it should set this.success
22055 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22056 * @param {Event} e The event
22057 * @param {Object} data An object containing arbitrary data supplied by the drag source
22063 Roo.dd.DropTarget.superclass.constructor.call( this,
22065 this.ddGroup || this.group,
22068 listeners : listeners || {}
22076 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22078 * @cfg {String} overClass
22079 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22082 * @cfg {String} ddGroup
22083 * The drag drop group to handle drop events for
22087 * @cfg {String} dropAllowed
22088 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22090 dropAllowed : "x-dd-drop-ok",
22092 * @cfg {String} dropNotAllowed
22093 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22095 dropNotAllowed : "x-dd-drop-nodrop",
22097 * @cfg {boolean} success
22098 * set this after drop listener..
22102 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22103 * if the drop point is valid for over/enter..
22110 isNotifyTarget : true,
22115 notifyEnter : function(dd, e, data)
22118 this.fireEvent('enter', dd, e, data);
22119 if(this.overClass){
22120 this.el.addClass(this.overClass);
22122 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22123 this.valid ? this.dropAllowed : this.dropNotAllowed
22130 notifyOver : function(dd, e, data)
22133 this.fireEvent('over', dd, e, data);
22134 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22135 this.valid ? this.dropAllowed : this.dropNotAllowed
22142 notifyOut : function(dd, e, data)
22144 this.fireEvent('out', dd, e, data);
22145 if(this.overClass){
22146 this.el.removeClass(this.overClass);
22153 notifyDrop : function(dd, e, data)
22155 this.success = false;
22156 this.fireEvent('drop', dd, e, data);
22157 return this.success;
22161 * Ext JS Library 1.1.1
22162 * Copyright(c) 2006-2007, Ext JS, LLC.
22164 * Originally Released Under LGPL - original licence link has changed is not relivant.
22167 * <script type="text/javascript">
22172 * @class Roo.dd.DragZone
22173 * @extends Roo.dd.DragSource
22174 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22175 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22177 * @param {String/HTMLElement/Element} el The container element
22178 * @param {Object} config
22180 Roo.dd.DragZone = function(el, config){
22181 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22182 if(this.containerScroll){
22183 Roo.dd.ScrollManager.register(this.el);
22187 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22189 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22190 * for auto scrolling during drag operations.
22193 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22194 * method after a failed drop (defaults to "c3daf9" - light blue)
22198 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22199 * for a valid target to drag based on the mouse down. Override this method
22200 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22201 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22202 * @param {EventObject} e The mouse down event
22203 * @return {Object} The dragData
22205 getDragData : function(e){
22206 return Roo.dd.Registry.getHandleFromEvent(e);
22210 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22211 * this.dragData.ddel
22212 * @param {Number} x The x position of the click on the dragged object
22213 * @param {Number} y The y position of the click on the dragged object
22214 * @return {Boolean} true to continue the drag, false to cancel
22216 onInitDrag : function(x, y){
22217 this.proxy.update(this.dragData.ddel.cloneNode(true));
22218 this.onStartDrag(x, y);
22223 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22225 afterRepair : function(){
22227 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22229 this.dragging = false;
22233 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22234 * the XY of this.dragData.ddel
22235 * @param {EventObject} e The mouse up event
22236 * @return {Array} The xy location (e.g. [100, 200])
22238 getRepairXY : function(e){
22239 return Roo.Element.fly(this.dragData.ddel).getXY();
22243 * Ext JS Library 1.1.1
22244 * Copyright(c) 2006-2007, Ext JS, LLC.
22246 * Originally Released Under LGPL - original licence link has changed is not relivant.
22249 * <script type="text/javascript">
22252 * @class Roo.dd.DropZone
22253 * @extends Roo.dd.DropTarget
22254 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22255 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22257 * @param {String/HTMLElement/Element} el The container element
22258 * @param {Object} config
22260 Roo.dd.DropZone = function(el, config){
22261 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22264 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22266 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22267 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22268 * provide your own custom lookup.
22269 * @param {Event} e The event
22270 * @return {Object} data The custom data
22272 getTargetFromEvent : function(e){
22273 return Roo.dd.Registry.getTargetFromEvent(e);
22277 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22278 * that it has registered. This method has no default implementation and should be overridden to provide
22279 * node-specific processing if necessary.
22280 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22281 * {@link #getTargetFromEvent} for this node)
22282 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22283 * @param {Event} e The event
22284 * @param {Object} data An object containing arbitrary data supplied by the drag source
22286 onNodeEnter : function(n, dd, e, data){
22291 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22292 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22293 * overridden to provide the proper feedback.
22294 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22295 * {@link #getTargetFromEvent} for this node)
22296 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22297 * @param {Event} e The event
22298 * @param {Object} data An object containing arbitrary data supplied by the drag source
22299 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22300 * underlying {@link Roo.dd.StatusProxy} can be updated
22302 onNodeOver : function(n, dd, e, data){
22303 return this.dropAllowed;
22307 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22308 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22309 * node-specific processing if necessary.
22310 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22311 * {@link #getTargetFromEvent} for this node)
22312 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22313 * @param {Event} e The event
22314 * @param {Object} data An object containing arbitrary data supplied by the drag source
22316 onNodeOut : function(n, dd, e, data){
22321 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22322 * the drop node. The default implementation returns false, so it should be overridden to provide the
22323 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22324 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22325 * {@link #getTargetFromEvent} for this node)
22326 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22327 * @param {Event} e The event
22328 * @param {Object} data An object containing arbitrary data supplied by the drag source
22329 * @return {Boolean} True if the drop was valid, else false
22331 onNodeDrop : function(n, dd, e, data){
22336 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22337 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22338 * it should be overridden to provide the proper feedback if necessary.
22339 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22340 * @param {Event} e The event
22341 * @param {Object} data An object containing arbitrary data supplied by the drag source
22342 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22343 * underlying {@link Roo.dd.StatusProxy} can be updated
22345 onContainerOver : function(dd, e, data){
22346 return this.dropNotAllowed;
22350 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22351 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22352 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22353 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22354 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22355 * @param {Event} e The event
22356 * @param {Object} data An object containing arbitrary data supplied by the drag source
22357 * @return {Boolean} True if the drop was valid, else false
22359 onContainerDrop : function(dd, e, data){
22364 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22365 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22366 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22367 * you should override this method and provide a custom implementation.
22368 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22369 * @param {Event} e The event
22370 * @param {Object} data An object containing arbitrary data supplied by the drag source
22371 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22372 * underlying {@link Roo.dd.StatusProxy} can be updated
22374 notifyEnter : function(dd, e, data){
22375 return this.dropNotAllowed;
22379 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22380 * This method will be called on every mouse movement while the drag source is over the drop zone.
22381 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22382 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22383 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22384 * registered node, it will call {@link #onContainerOver}.
22385 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22386 * @param {Event} e The event
22387 * @param {Object} data An object containing arbitrary data supplied by the drag source
22388 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22389 * underlying {@link Roo.dd.StatusProxy} can be updated
22391 notifyOver : function(dd, e, data){
22392 var n = this.getTargetFromEvent(e);
22393 if(!n){ // not over valid drop target
22394 if(this.lastOverNode){
22395 this.onNodeOut(this.lastOverNode, dd, e, data);
22396 this.lastOverNode = null;
22398 return this.onContainerOver(dd, e, data);
22400 if(this.lastOverNode != n){
22401 if(this.lastOverNode){
22402 this.onNodeOut(this.lastOverNode, dd, e, data);
22404 this.onNodeEnter(n, dd, e, data);
22405 this.lastOverNode = n;
22407 return this.onNodeOver(n, dd, e, data);
22411 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22412 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22413 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22415 * @param {Event} e The event
22416 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22418 notifyOut : function(dd, e, data){
22419 if(this.lastOverNode){
22420 this.onNodeOut(this.lastOverNode, dd, e, data);
22421 this.lastOverNode = null;
22426 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22427 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22428 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22429 * otherwise it will call {@link #onContainerDrop}.
22430 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22431 * @param {Event} e The event
22432 * @param {Object} data An object containing arbitrary data supplied by the drag source
22433 * @return {Boolean} True if the drop was valid, else false
22435 notifyDrop : function(dd, e, data){
22436 if(this.lastOverNode){
22437 this.onNodeOut(this.lastOverNode, dd, e, data);
22438 this.lastOverNode = null;
22440 var n = this.getTargetFromEvent(e);
22442 this.onNodeDrop(n, dd, e, data) :
22443 this.onContainerDrop(dd, e, data);
22447 triggerCacheRefresh : function(){
22448 Roo.dd.DDM.refreshCache(this.groups);
22452 * Ext JS Library 1.1.1
22453 * Copyright(c) 2006-2007, Ext JS, LLC.
22455 * Originally Released Under LGPL - original licence link has changed is not relivant.
22458 * <script type="text/javascript">
22463 * @class Roo.data.SortTypes
22465 * Defines the default sorting (casting?) comparison functions used when sorting data.
22467 Roo.data.SortTypes = {
22469 * Default sort that does nothing
22470 * @param {Mixed} s The value being converted
22471 * @return {Mixed} The comparison value
22473 none : function(s){
22478 * The regular expression used to strip tags
22482 stripTagsRE : /<\/?[^>]+>/gi,
22485 * Strips all HTML tags to sort on text only
22486 * @param {Mixed} s The value being converted
22487 * @return {String} The comparison value
22489 asText : function(s){
22490 return String(s).replace(this.stripTagsRE, "");
22494 * Strips all HTML tags to sort on text only - Case insensitive
22495 * @param {Mixed} s The value being converted
22496 * @return {String} The comparison value
22498 asUCText : function(s){
22499 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22503 * Case insensitive string
22504 * @param {Mixed} s The value being converted
22505 * @return {String} The comparison value
22507 asUCString : function(s) {
22508 return String(s).toUpperCase();
22513 * @param {Mixed} s The value being converted
22514 * @return {Number} The comparison value
22516 asDate : function(s) {
22520 if(s instanceof Date){
22521 return s.getTime();
22523 return Date.parse(String(s));
22528 * @param {Mixed} s The value being converted
22529 * @return {Float} The comparison value
22531 asFloat : function(s) {
22532 var val = parseFloat(String(s).replace(/,/g, ""));
22541 * @param {Mixed} s The value being converted
22542 * @return {Number} The comparison value
22544 asInt : function(s) {
22545 var val = parseInt(String(s).replace(/,/g, ""));
22553 * Ext JS Library 1.1.1
22554 * Copyright(c) 2006-2007, Ext JS, LLC.
22556 * Originally Released Under LGPL - original licence link has changed is not relivant.
22559 * <script type="text/javascript">
22563 * @class Roo.data.Record
22564 * Instances of this class encapsulate both record <em>definition</em> information, and record
22565 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22566 * to access Records cached in an {@link Roo.data.Store} object.<br>
22568 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22569 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22572 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22574 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22575 * {@link #create}. The parameters are the same.
22576 * @param {Array} data An associative Array of data values keyed by the field name.
22577 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22578 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22579 * not specified an integer id is generated.
22581 Roo.data.Record = function(data, id){
22582 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22587 * Generate a constructor for a specific record layout.
22588 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22589 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22590 * Each field definition object may contain the following properties: <ul>
22591 * <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,
22592 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22593 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22594 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22595 * is being used, then this is a string containing the javascript expression to reference the data relative to
22596 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22597 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22598 * this may be omitted.</p></li>
22599 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22600 * <ul><li>auto (Default, implies no conversion)</li>
22605 * <li>date</li></ul></p></li>
22606 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22607 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22608 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22609 * by the Reader into an object that will be stored in the Record. It is passed the
22610 * following parameters:<ul>
22611 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22613 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22615 * <br>usage:<br><pre><code>
22616 var TopicRecord = Roo.data.Record.create(
22617 {name: 'title', mapping: 'topic_title'},
22618 {name: 'author', mapping: 'username'},
22619 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22620 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22621 {name: 'lastPoster', mapping: 'user2'},
22622 {name: 'excerpt', mapping: 'post_text'}
22625 var myNewRecord = new TopicRecord({
22626 title: 'Do my job please',
22629 lastPost: new Date(),
22630 lastPoster: 'Animal',
22631 excerpt: 'No way dude!'
22633 myStore.add(myNewRecord);
22638 Roo.data.Record.create = function(o){
22639 var f = function(){
22640 f.superclass.constructor.apply(this, arguments);
22642 Roo.extend(f, Roo.data.Record);
22643 var p = f.prototype;
22644 p.fields = new Roo.util.MixedCollection(false, function(field){
22647 for(var i = 0, len = o.length; i < len; i++){
22648 p.fields.add(new Roo.data.Field(o[i]));
22650 f.getField = function(name){
22651 return p.fields.get(name);
22656 Roo.data.Record.AUTO_ID = 1000;
22657 Roo.data.Record.EDIT = 'edit';
22658 Roo.data.Record.REJECT = 'reject';
22659 Roo.data.Record.COMMIT = 'commit';
22661 Roo.data.Record.prototype = {
22663 * Readonly flag - true if this record has been modified.
22672 join : function(store){
22673 this.store = store;
22677 * Set the named field to the specified value.
22678 * @param {String} name The name of the field to set.
22679 * @param {Object} value The value to set the field to.
22681 set : function(name, value){
22682 if(this.data[name] == value){
22686 if(!this.modified){
22687 this.modified = {};
22689 if(typeof this.modified[name] == 'undefined'){
22690 this.modified[name] = this.data[name];
22692 this.data[name] = value;
22693 if(!this.editing && this.store){
22694 this.store.afterEdit(this);
22699 * Get the value of the named field.
22700 * @param {String} name The name of the field to get the value of.
22701 * @return {Object} The value of the field.
22703 get : function(name){
22704 return this.data[name];
22708 beginEdit : function(){
22709 this.editing = true;
22710 this.modified = {};
22714 cancelEdit : function(){
22715 this.editing = false;
22716 delete this.modified;
22720 endEdit : function(){
22721 this.editing = false;
22722 if(this.dirty && this.store){
22723 this.store.afterEdit(this);
22728 * Usually called by the {@link Roo.data.Store} which owns the Record.
22729 * Rejects all changes made to the Record since either creation, or the last commit operation.
22730 * Modified fields are reverted to their original values.
22732 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22733 * of reject operations.
22735 reject : function(){
22736 var m = this.modified;
22738 if(typeof m[n] != "function"){
22739 this.data[n] = m[n];
22742 this.dirty = false;
22743 delete this.modified;
22744 this.editing = false;
22746 this.store.afterReject(this);
22751 * Usually called by the {@link Roo.data.Store} which owns the Record.
22752 * Commits all changes made to the Record since either creation, or the last commit operation.
22754 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22755 * of commit operations.
22757 commit : function(){
22758 this.dirty = false;
22759 delete this.modified;
22760 this.editing = false;
22762 this.store.afterCommit(this);
22767 hasError : function(){
22768 return this.error != null;
22772 clearError : function(){
22777 * Creates a copy of this record.
22778 * @param {String} id (optional) A new record id if you don't want to use this record's id
22781 copy : function(newId) {
22782 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22786 * Ext JS Library 1.1.1
22787 * Copyright(c) 2006-2007, Ext JS, LLC.
22789 * Originally Released Under LGPL - original licence link has changed is not relivant.
22792 * <script type="text/javascript">
22798 * @class Roo.data.Store
22799 * @extends Roo.util.Observable
22800 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22801 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22803 * 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
22804 * has no knowledge of the format of the data returned by the Proxy.<br>
22806 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22807 * instances from the data object. These records are cached and made available through accessor functions.
22809 * Creates a new Store.
22810 * @param {Object} config A config object containing the objects needed for the Store to access data,
22811 * and read the data into Records.
22813 Roo.data.Store = function(config){
22814 this.data = new Roo.util.MixedCollection(false);
22815 this.data.getKey = function(o){
22818 this.baseParams = {};
22820 this.paramNames = {
22825 "multisort" : "_multisort"
22828 if(config && config.data){
22829 this.inlineData = config.data;
22830 delete config.data;
22833 Roo.apply(this, config);
22835 if(this.reader){ // reader passed
22836 this.reader = Roo.factory(this.reader, Roo.data);
22837 this.reader.xmodule = this.xmodule || false;
22838 if(!this.recordType){
22839 this.recordType = this.reader.recordType;
22841 if(this.reader.onMetaChange){
22842 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22846 if(this.recordType){
22847 this.fields = this.recordType.prototype.fields;
22849 this.modified = [];
22853 * @event datachanged
22854 * Fires when the data cache has changed, and a widget which is using this Store
22855 * as a Record cache should refresh its view.
22856 * @param {Store} this
22858 datachanged : true,
22860 * @event metachange
22861 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22862 * @param {Store} this
22863 * @param {Object} meta The JSON metadata
22868 * Fires when Records have been added to the Store
22869 * @param {Store} this
22870 * @param {Roo.data.Record[]} records The array of Records added
22871 * @param {Number} index The index at which the record(s) were added
22876 * Fires when a Record has been removed from the Store
22877 * @param {Store} this
22878 * @param {Roo.data.Record} record The Record that was removed
22879 * @param {Number} index The index at which the record was removed
22884 * Fires when a Record has been updated
22885 * @param {Store} this
22886 * @param {Roo.data.Record} record The Record that was updated
22887 * @param {String} operation The update operation being performed. Value may be one of:
22889 Roo.data.Record.EDIT
22890 Roo.data.Record.REJECT
22891 Roo.data.Record.COMMIT
22897 * Fires when the data cache has been cleared.
22898 * @param {Store} this
22902 * @event beforeload
22903 * Fires before a request is made for a new data object. If the beforeload handler returns false
22904 * the load action will be canceled.
22905 * @param {Store} this
22906 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22910 * @event beforeloadadd
22911 * Fires after a new set of Records has been loaded.
22912 * @param {Store} this
22913 * @param {Roo.data.Record[]} records The Records that were loaded
22914 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22916 beforeloadadd : true,
22919 * Fires after a new set of Records has been loaded, before they are added to the store.
22920 * @param {Store} this
22921 * @param {Roo.data.Record[]} records The Records that were loaded
22922 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22923 * @params {Object} return from reader
22927 * @event loadexception
22928 * Fires if an exception occurs in the Proxy during loading.
22929 * Called with the signature of the Proxy's "loadexception" event.
22930 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22933 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22934 * @param {Object} load options
22935 * @param {Object} jsonData from your request (normally this contains the Exception)
22937 loadexception : true
22941 this.proxy = Roo.factory(this.proxy, Roo.data);
22942 this.proxy.xmodule = this.xmodule || false;
22943 this.relayEvents(this.proxy, ["loadexception"]);
22945 this.sortToggle = {};
22946 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22948 Roo.data.Store.superclass.constructor.call(this);
22950 if(this.inlineData){
22951 this.loadData(this.inlineData);
22952 delete this.inlineData;
22956 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22958 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22959 * without a remote query - used by combo/forms at present.
22963 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22966 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22969 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22970 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22973 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22974 * on any HTTP request
22977 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22980 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22984 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22985 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22987 remoteSort : false,
22990 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22991 * loaded or when a record is removed. (defaults to false).
22993 pruneModifiedRecords : false,
22996 lastOptions : null,
22999 * Add Records to the Store and fires the add event.
23000 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23002 add : function(records){
23003 records = [].concat(records);
23004 for(var i = 0, len = records.length; i < len; i++){
23005 records[i].join(this);
23007 var index = this.data.length;
23008 this.data.addAll(records);
23009 this.fireEvent("add", this, records, index);
23013 * Remove a Record from the Store and fires the remove event.
23014 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23016 remove : function(record){
23017 var index = this.data.indexOf(record);
23018 this.data.removeAt(index);
23020 if(this.pruneModifiedRecords){
23021 this.modified.remove(record);
23023 this.fireEvent("remove", this, record, index);
23027 * Remove all Records from the Store and fires the clear event.
23029 removeAll : function(){
23031 if(this.pruneModifiedRecords){
23032 this.modified = [];
23034 this.fireEvent("clear", this);
23038 * Inserts Records to the Store at the given index and fires the add event.
23039 * @param {Number} index The start index at which to insert the passed Records.
23040 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23042 insert : function(index, records){
23043 records = [].concat(records);
23044 for(var i = 0, len = records.length; i < len; i++){
23045 this.data.insert(index, records[i]);
23046 records[i].join(this);
23048 this.fireEvent("add", this, records, index);
23052 * Get the index within the cache of the passed Record.
23053 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23054 * @return {Number} The index of the passed Record. Returns -1 if not found.
23056 indexOf : function(record){
23057 return this.data.indexOf(record);
23061 * Get the index within the cache of the Record with the passed id.
23062 * @param {String} id The id of the Record to find.
23063 * @return {Number} The index of the Record. Returns -1 if not found.
23065 indexOfId : function(id){
23066 return this.data.indexOfKey(id);
23070 * Get the Record with the specified id.
23071 * @param {String} id The id of the Record to find.
23072 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23074 getById : function(id){
23075 return this.data.key(id);
23079 * Get the Record at the specified index.
23080 * @param {Number} index The index of the Record to find.
23081 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23083 getAt : function(index){
23084 return this.data.itemAt(index);
23088 * Returns a range of Records between specified indices.
23089 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23090 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23091 * @return {Roo.data.Record[]} An array of Records
23093 getRange : function(start, end){
23094 return this.data.getRange(start, end);
23098 storeOptions : function(o){
23099 o = Roo.apply({}, o);
23102 this.lastOptions = o;
23106 * Loads the Record cache from the configured Proxy using the configured Reader.
23108 * If using remote paging, then the first load call must specify the <em>start</em>
23109 * and <em>limit</em> properties in the options.params property to establish the initial
23110 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23112 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23113 * and this call will return before the new data has been loaded. Perform any post-processing
23114 * in a callback function, or in a "load" event handler.</strong>
23116 * @param {Object} options An object containing properties which control loading options:<ul>
23117 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23118 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23119 * passed the following arguments:<ul>
23120 * <li>r : Roo.data.Record[]</li>
23121 * <li>options: Options object from the load call</li>
23122 * <li>success: Boolean success indicator</li></ul></li>
23123 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23124 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23127 load : function(options){
23128 options = options || {};
23129 if(this.fireEvent("beforeload", this, options) !== false){
23130 this.storeOptions(options);
23131 var p = Roo.apply(options.params || {}, this.baseParams);
23132 // if meta was not loaded from remote source.. try requesting it.
23133 if (!this.reader.metaFromRemote) {
23134 p._requestMeta = 1;
23136 if(this.sortInfo && this.remoteSort){
23137 var pn = this.paramNames;
23138 p[pn["sort"]] = this.sortInfo.field;
23139 p[pn["dir"]] = this.sortInfo.direction;
23141 if (this.multiSort) {
23142 var pn = this.paramNames;
23143 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23146 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23151 * Reloads the Record cache from the configured Proxy using the configured Reader and
23152 * the options from the last load operation performed.
23153 * @param {Object} options (optional) An object containing properties which may override the options
23154 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23155 * the most recently used options are reused).
23157 reload : function(options){
23158 this.load(Roo.applyIf(options||{}, this.lastOptions));
23162 // Called as a callback by the Reader during a load operation.
23163 loadRecords : function(o, options, success){
23164 if(!o || success === false){
23165 if(success !== false){
23166 this.fireEvent("load", this, [], options, o);
23168 if(options.callback){
23169 options.callback.call(options.scope || this, [], options, false);
23173 // if data returned failure - throw an exception.
23174 if (o.success === false) {
23175 // show a message if no listener is registered.
23176 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23177 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23179 // loadmask wil be hooked into this..
23180 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23183 var r = o.records, t = o.totalRecords || r.length;
23185 this.fireEvent("beforeloadadd", this, r, options, o);
23187 if(!options || options.add !== true){
23188 if(this.pruneModifiedRecords){
23189 this.modified = [];
23191 for(var i = 0, len = r.length; i < len; i++){
23195 this.data = this.snapshot;
23196 delete this.snapshot;
23199 this.data.addAll(r);
23200 this.totalLength = t;
23202 this.fireEvent("datachanged", this);
23204 this.totalLength = Math.max(t, this.data.length+r.length);
23208 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23210 var e = new Roo.data.Record({});
23212 e.set(this.parent.displayField, this.parent.emptyTitle);
23213 e.set(this.parent.valueField, '');
23218 this.fireEvent("load", this, r, options, o);
23219 if(options.callback){
23220 options.callback.call(options.scope || this, r, options, true);
23226 * Loads data from a passed data block. A Reader which understands the format of the data
23227 * must have been configured in the constructor.
23228 * @param {Object} data The data block from which to read the Records. The format of the data expected
23229 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23230 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23232 loadData : function(o, append){
23233 var r = this.reader.readRecords(o);
23234 this.loadRecords(r, {add: append}, true);
23238 * Gets the number of cached records.
23240 * <em>If using paging, this may not be the total size of the dataset. If the data object
23241 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23242 * the data set size</em>
23244 getCount : function(){
23245 return this.data.length || 0;
23249 * Gets the total number of records in the dataset as returned by the server.
23251 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23252 * the dataset size</em>
23254 getTotalCount : function(){
23255 return this.totalLength || 0;
23259 * Returns the sort state of the Store as an object with two properties:
23261 field {String} The name of the field by which the Records are sorted
23262 direction {String} The sort order, "ASC" or "DESC"
23265 getSortState : function(){
23266 return this.sortInfo;
23270 applySort : function(){
23271 if(this.sortInfo && !this.remoteSort){
23272 var s = this.sortInfo, f = s.field;
23273 var st = this.fields.get(f).sortType;
23274 var fn = function(r1, r2){
23275 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23276 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23278 this.data.sort(s.direction, fn);
23279 if(this.snapshot && this.snapshot != this.data){
23280 this.snapshot.sort(s.direction, fn);
23286 * Sets the default sort column and order to be used by the next load operation.
23287 * @param {String} fieldName The name of the field to sort by.
23288 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23290 setDefaultSort : function(field, dir){
23291 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23295 * Sort the Records.
23296 * If remote sorting is used, the sort is performed on the server, and the cache is
23297 * reloaded. If local sorting is used, the cache is sorted internally.
23298 * @param {String} fieldName The name of the field to sort by.
23299 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23301 sort : function(fieldName, dir){
23302 var f = this.fields.get(fieldName);
23304 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23306 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23307 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23312 this.sortToggle[f.name] = dir;
23313 this.sortInfo = {field: f.name, direction: dir};
23314 if(!this.remoteSort){
23316 this.fireEvent("datachanged", this);
23318 this.load(this.lastOptions);
23323 * Calls the specified function for each of the Records in the cache.
23324 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23325 * Returning <em>false</em> aborts and exits the iteration.
23326 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23328 each : function(fn, scope){
23329 this.data.each(fn, scope);
23333 * Gets all records modified since the last commit. Modified records are persisted across load operations
23334 * (e.g., during paging).
23335 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23337 getModifiedRecords : function(){
23338 return this.modified;
23342 createFilterFn : function(property, value, anyMatch){
23343 if(!value.exec){ // not a regex
23344 value = String(value);
23345 if(value.length == 0){
23348 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23350 return function(r){
23351 return value.test(r.data[property]);
23356 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23357 * @param {String} property A field on your records
23358 * @param {Number} start The record index to start at (defaults to 0)
23359 * @param {Number} end The last record index to include (defaults to length - 1)
23360 * @return {Number} The sum
23362 sum : function(property, start, end){
23363 var rs = this.data.items, v = 0;
23364 start = start || 0;
23365 end = (end || end === 0) ? end : rs.length-1;
23367 for(var i = start; i <= end; i++){
23368 v += (rs[i].data[property] || 0);
23374 * Filter the records by a specified property.
23375 * @param {String} field A field on your records
23376 * @param {String/RegExp} value Either a string that the field
23377 * should start with or a RegExp to test against the field
23378 * @param {Boolean} anyMatch True to match any part not just the beginning
23380 filter : function(property, value, anyMatch){
23381 var fn = this.createFilterFn(property, value, anyMatch);
23382 return fn ? this.filterBy(fn) : this.clearFilter();
23386 * Filter by a function. The specified function will be called with each
23387 * record in this data source. If the function returns true the record is included,
23388 * otherwise it is filtered.
23389 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23390 * @param {Object} scope (optional) The scope of the function (defaults to this)
23392 filterBy : function(fn, scope){
23393 this.snapshot = this.snapshot || this.data;
23394 this.data = this.queryBy(fn, scope||this);
23395 this.fireEvent("datachanged", this);
23399 * Query the records by a specified property.
23400 * @param {String} field A field on your records
23401 * @param {String/RegExp} value Either a string that the field
23402 * should start with or a RegExp to test against the field
23403 * @param {Boolean} anyMatch True to match any part not just the beginning
23404 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23406 query : function(property, value, anyMatch){
23407 var fn = this.createFilterFn(property, value, anyMatch);
23408 return fn ? this.queryBy(fn) : this.data.clone();
23412 * Query by a function. The specified function will be called with each
23413 * record in this data source. If the function returns true the record is included
23415 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23416 * @param {Object} scope (optional) The scope of the function (defaults to this)
23417 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23419 queryBy : function(fn, scope){
23420 var data = this.snapshot || this.data;
23421 return data.filterBy(fn, scope||this);
23425 * Collects unique values for a particular dataIndex from this store.
23426 * @param {String} dataIndex The property to collect
23427 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23428 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23429 * @return {Array} An array of the unique values
23431 collect : function(dataIndex, allowNull, bypassFilter){
23432 var d = (bypassFilter === true && this.snapshot) ?
23433 this.snapshot.items : this.data.items;
23434 var v, sv, r = [], l = {};
23435 for(var i = 0, len = d.length; i < len; i++){
23436 v = d[i].data[dataIndex];
23438 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23447 * Revert to a view of the Record cache with no filtering applied.
23448 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23450 clearFilter : function(suppressEvent){
23451 if(this.snapshot && this.snapshot != this.data){
23452 this.data = this.snapshot;
23453 delete this.snapshot;
23454 if(suppressEvent !== true){
23455 this.fireEvent("datachanged", this);
23461 afterEdit : function(record){
23462 if(this.modified.indexOf(record) == -1){
23463 this.modified.push(record);
23465 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23469 afterReject : function(record){
23470 this.modified.remove(record);
23471 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23475 afterCommit : function(record){
23476 this.modified.remove(record);
23477 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23481 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23482 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23484 commitChanges : function(){
23485 var m = this.modified.slice(0);
23486 this.modified = [];
23487 for(var i = 0, len = m.length; i < len; i++){
23493 * Cancel outstanding changes on all changed records.
23495 rejectChanges : function(){
23496 var m = this.modified.slice(0);
23497 this.modified = [];
23498 for(var i = 0, len = m.length; i < len; i++){
23503 onMetaChange : function(meta, rtype, o){
23504 this.recordType = rtype;
23505 this.fields = rtype.prototype.fields;
23506 delete this.snapshot;
23507 this.sortInfo = meta.sortInfo || this.sortInfo;
23508 this.modified = [];
23509 this.fireEvent('metachange', this, this.reader.meta);
23512 moveIndex : function(data, type)
23514 var index = this.indexOf(data);
23516 var newIndex = index + type;
23520 this.insert(newIndex, data);
23525 * Ext JS Library 1.1.1
23526 * Copyright(c) 2006-2007, Ext JS, LLC.
23528 * Originally Released Under LGPL - original licence link has changed is not relivant.
23531 * <script type="text/javascript">
23535 * @class Roo.data.SimpleStore
23536 * @extends Roo.data.Store
23537 * Small helper class to make creating Stores from Array data easier.
23538 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23539 * @cfg {Array} fields An array of field definition objects, or field name strings.
23540 * @cfg {Array} data The multi-dimensional array of data
23542 * @param {Object} config
23544 Roo.data.SimpleStore = function(config){
23545 Roo.data.SimpleStore.superclass.constructor.call(this, {
23547 reader: new Roo.data.ArrayReader({
23550 Roo.data.Record.create(config.fields)
23552 proxy : new Roo.data.MemoryProxy(config.data)
23556 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23558 * Ext JS Library 1.1.1
23559 * Copyright(c) 2006-2007, Ext JS, LLC.
23561 * Originally Released Under LGPL - original licence link has changed is not relivant.
23564 * <script type="text/javascript">
23569 * @extends Roo.data.Store
23570 * @class Roo.data.JsonStore
23571 * Small helper class to make creating Stores for JSON data easier. <br/>
23573 var store = new Roo.data.JsonStore({
23574 url: 'get-images.php',
23576 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23579 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23580 * JsonReader and HttpProxy (unless inline data is provided).</b>
23581 * @cfg {Array} fields An array of field definition objects, or field name strings.
23583 * @param {Object} config
23585 Roo.data.JsonStore = function(c){
23586 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23587 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23588 reader: new Roo.data.JsonReader(c, c.fields)
23591 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23593 * Ext JS Library 1.1.1
23594 * Copyright(c) 2006-2007, Ext JS, LLC.
23596 * Originally Released Under LGPL - original licence link has changed is not relivant.
23599 * <script type="text/javascript">
23603 Roo.data.Field = function(config){
23604 if(typeof config == "string"){
23605 config = {name: config};
23607 Roo.apply(this, config);
23610 this.type = "auto";
23613 var st = Roo.data.SortTypes;
23614 // named sortTypes are supported, here we look them up
23615 if(typeof this.sortType == "string"){
23616 this.sortType = st[this.sortType];
23619 // set default sortType for strings and dates
23620 if(!this.sortType){
23623 this.sortType = st.asUCString;
23626 this.sortType = st.asDate;
23629 this.sortType = st.none;
23634 var stripRe = /[\$,%]/g;
23636 // prebuilt conversion function for this field, instead of
23637 // switching every time we're reading a value
23639 var cv, dateFormat = this.dateFormat;
23644 cv = function(v){ return v; };
23647 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23651 return v !== undefined && v !== null && v !== '' ?
23652 parseInt(String(v).replace(stripRe, ""), 10) : '';
23657 return v !== undefined && v !== null && v !== '' ?
23658 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23663 cv = function(v){ return v === true || v === "true" || v == 1; };
23670 if(v instanceof Date){
23674 if(dateFormat == "timestamp"){
23675 return new Date(v*1000);
23677 return Date.parseDate(v, dateFormat);
23679 var parsed = Date.parse(v);
23680 return parsed ? new Date(parsed) : null;
23689 Roo.data.Field.prototype = {
23697 * Ext JS Library 1.1.1
23698 * Copyright(c) 2006-2007, Ext JS, LLC.
23700 * Originally Released Under LGPL - original licence link has changed is not relivant.
23703 * <script type="text/javascript">
23706 // Base class for reading structured data from a data source. This class is intended to be
23707 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23710 * @class Roo.data.DataReader
23711 * Base class for reading structured data from a data source. This class is intended to be
23712 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23715 Roo.data.DataReader = function(meta, recordType){
23719 this.recordType = recordType instanceof Array ?
23720 Roo.data.Record.create(recordType) : recordType;
23723 Roo.data.DataReader.prototype = {
23725 * Create an empty record
23726 * @param {Object} data (optional) - overlay some values
23727 * @return {Roo.data.Record} record created.
23729 newRow : function(d) {
23731 this.recordType.prototype.fields.each(function(c) {
23733 case 'int' : da[c.name] = 0; break;
23734 case 'date' : da[c.name] = new Date(); break;
23735 case 'float' : da[c.name] = 0.0; break;
23736 case 'boolean' : da[c.name] = false; break;
23737 default : da[c.name] = ""; break;
23741 return new this.recordType(Roo.apply(da, d));
23746 * Ext JS Library 1.1.1
23747 * Copyright(c) 2006-2007, Ext JS, LLC.
23749 * Originally Released Under LGPL - original licence link has changed is not relivant.
23752 * <script type="text/javascript">
23756 * @class Roo.data.DataProxy
23757 * @extends Roo.data.Observable
23758 * This class is an abstract base class for implementations which provide retrieval of
23759 * unformatted data objects.<br>
23761 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23762 * (of the appropriate type which knows how to parse the data object) to provide a block of
23763 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23765 * Custom implementations must implement the load method as described in
23766 * {@link Roo.data.HttpProxy#load}.
23768 Roo.data.DataProxy = function(){
23771 * @event beforeload
23772 * Fires before a network request is made to retrieve a data object.
23773 * @param {Object} This DataProxy object.
23774 * @param {Object} params The params parameter to the load function.
23779 * Fires before the load method's callback is called.
23780 * @param {Object} This DataProxy object.
23781 * @param {Object} o The data object.
23782 * @param {Object} arg The callback argument object passed to the load function.
23786 * @event loadexception
23787 * Fires if an Exception occurs during data retrieval.
23788 * @param {Object} This DataProxy object.
23789 * @param {Object} o The data object.
23790 * @param {Object} arg The callback argument object passed to the load function.
23791 * @param {Object} e The Exception.
23793 loadexception : true
23795 Roo.data.DataProxy.superclass.constructor.call(this);
23798 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23801 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23805 * Ext JS Library 1.1.1
23806 * Copyright(c) 2006-2007, Ext JS, LLC.
23808 * Originally Released Under LGPL - original licence link has changed is not relivant.
23811 * <script type="text/javascript">
23814 * @class Roo.data.MemoryProxy
23815 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23816 * to the Reader when its load method is called.
23818 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23820 Roo.data.MemoryProxy = function(data){
23824 Roo.data.MemoryProxy.superclass.constructor.call(this);
23828 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23831 * Load data from the requested source (in this case an in-memory
23832 * data object passed to the constructor), read the data object into
23833 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23834 * process that block using the passed callback.
23835 * @param {Object} params This parameter is not used by the MemoryProxy class.
23836 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23837 * object into a block of Roo.data.Records.
23838 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23839 * The function must be passed <ul>
23840 * <li>The Record block object</li>
23841 * <li>The "arg" argument from the load function</li>
23842 * <li>A boolean success indicator</li>
23844 * @param {Object} scope The scope in which to call the callback
23845 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23847 load : function(params, reader, callback, scope, arg){
23848 params = params || {};
23851 result = reader.readRecords(this.data);
23853 this.fireEvent("loadexception", this, arg, null, e);
23854 callback.call(scope, null, arg, false);
23857 callback.call(scope, result, arg, true);
23861 update : function(params, records){
23866 * Ext JS Library 1.1.1
23867 * Copyright(c) 2006-2007, Ext JS, LLC.
23869 * Originally Released Under LGPL - original licence link has changed is not relivant.
23872 * <script type="text/javascript">
23875 * @class Roo.data.HttpProxy
23876 * @extends Roo.data.DataProxy
23877 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23878 * configured to reference a certain URL.<br><br>
23880 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23881 * from which the running page was served.<br><br>
23883 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23885 * Be aware that to enable the browser to parse an XML document, the server must set
23886 * the Content-Type header in the HTTP response to "text/xml".
23888 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23889 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23890 * will be used to make the request.
23892 Roo.data.HttpProxy = function(conn){
23893 Roo.data.HttpProxy.superclass.constructor.call(this);
23894 // is conn a conn config or a real conn?
23896 this.useAjax = !conn || !conn.events;
23900 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23901 // thse are take from connection...
23904 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23907 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23908 * extra parameters to each request made by this object. (defaults to undefined)
23911 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23912 * to each request made by this object. (defaults to undefined)
23915 * @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)
23918 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23921 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23927 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23931 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23932 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23933 * a finer-grained basis than the DataProxy events.
23935 getConnection : function(){
23936 return this.useAjax ? Roo.Ajax : this.conn;
23940 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23941 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23942 * process that block using the passed callback.
23943 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23944 * for the request to the remote server.
23945 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23946 * object into a block of Roo.data.Records.
23947 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23948 * The function must be passed <ul>
23949 * <li>The Record block object</li>
23950 * <li>The "arg" argument from the load function</li>
23951 * <li>A boolean success indicator</li>
23953 * @param {Object} scope The scope in which to call the callback
23954 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23956 load : function(params, reader, callback, scope, arg){
23957 if(this.fireEvent("beforeload", this, params) !== false){
23959 params : params || {},
23961 callback : callback,
23966 callback : this.loadResponse,
23970 Roo.applyIf(o, this.conn);
23971 if(this.activeRequest){
23972 Roo.Ajax.abort(this.activeRequest);
23974 this.activeRequest = Roo.Ajax.request(o);
23976 this.conn.request(o);
23979 callback.call(scope||this, null, arg, false);
23984 loadResponse : function(o, success, response){
23985 delete this.activeRequest;
23987 this.fireEvent("loadexception", this, o, response);
23988 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23993 result = o.reader.read(response);
23995 this.fireEvent("loadexception", this, o, response, e);
23996 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24000 this.fireEvent("load", this, o, o.request.arg);
24001 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24005 update : function(dataSet){
24010 updateResponse : function(dataSet){
24015 * Ext JS Library 1.1.1
24016 * Copyright(c) 2006-2007, Ext JS, LLC.
24018 * Originally Released Under LGPL - original licence link has changed is not relivant.
24021 * <script type="text/javascript">
24025 * @class Roo.data.ScriptTagProxy
24026 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24027 * other than the originating domain of the running page.<br><br>
24029 * <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
24030 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24032 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24033 * source code that is used as the source inside a <script> tag.<br><br>
24035 * In order for the browser to process the returned data, the server must wrap the data object
24036 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24037 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24038 * depending on whether the callback name was passed:
24041 boolean scriptTag = false;
24042 String cb = request.getParameter("callback");
24045 response.setContentType("text/javascript");
24047 response.setContentType("application/x-json");
24049 Writer out = response.getWriter();
24051 out.write(cb + "(");
24053 out.print(dataBlock.toJsonString());
24060 * @param {Object} config A configuration object.
24062 Roo.data.ScriptTagProxy = function(config){
24063 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24064 Roo.apply(this, config);
24065 this.head = document.getElementsByTagName("head")[0];
24068 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24070 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24072 * @cfg {String} url The URL from which to request the data object.
24075 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24079 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24080 * the server the name of the callback function set up by the load call to process the returned data object.
24081 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24082 * javascript output which calls this named function passing the data object as its only parameter.
24084 callbackParam : "callback",
24086 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24087 * name to the request.
24092 * Load data from the configured URL, read the data object into
24093 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24094 * process that block using the passed callback.
24095 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24096 * for the request to the remote server.
24097 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24098 * object into a block of Roo.data.Records.
24099 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24100 * The function must be passed <ul>
24101 * <li>The Record block object</li>
24102 * <li>The "arg" argument from the load function</li>
24103 * <li>A boolean success indicator</li>
24105 * @param {Object} scope The scope in which to call the callback
24106 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24108 load : function(params, reader, callback, scope, arg){
24109 if(this.fireEvent("beforeload", this, params) !== false){
24111 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24113 var url = this.url;
24114 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24116 url += "&_dc=" + (new Date().getTime());
24118 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24121 cb : "stcCallback"+transId,
24122 scriptId : "stcScript"+transId,
24126 callback : callback,
24132 window[trans.cb] = function(o){
24133 conn.handleResponse(o, trans);
24136 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24138 if(this.autoAbort !== false){
24142 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24144 var script = document.createElement("script");
24145 script.setAttribute("src", url);
24146 script.setAttribute("type", "text/javascript");
24147 script.setAttribute("id", trans.scriptId);
24148 this.head.appendChild(script);
24150 this.trans = trans;
24152 callback.call(scope||this, null, arg, false);
24157 isLoading : function(){
24158 return this.trans ? true : false;
24162 * Abort the current server request.
24164 abort : function(){
24165 if(this.isLoading()){
24166 this.destroyTrans(this.trans);
24171 destroyTrans : function(trans, isLoaded){
24172 this.head.removeChild(document.getElementById(trans.scriptId));
24173 clearTimeout(trans.timeoutId);
24175 window[trans.cb] = undefined;
24177 delete window[trans.cb];
24180 // if hasn't been loaded, wait for load to remove it to prevent script error
24181 window[trans.cb] = function(){
24182 window[trans.cb] = undefined;
24184 delete window[trans.cb];
24191 handleResponse : function(o, trans){
24192 this.trans = false;
24193 this.destroyTrans(trans, true);
24196 result = trans.reader.readRecords(o);
24198 this.fireEvent("loadexception", this, o, trans.arg, e);
24199 trans.callback.call(trans.scope||window, null, trans.arg, false);
24202 this.fireEvent("load", this, o, trans.arg);
24203 trans.callback.call(trans.scope||window, result, trans.arg, true);
24207 handleFailure : function(trans){
24208 this.trans = false;
24209 this.destroyTrans(trans, false);
24210 this.fireEvent("loadexception", this, null, trans.arg);
24211 trans.callback.call(trans.scope||window, null, trans.arg, false);
24215 * Ext JS Library 1.1.1
24216 * Copyright(c) 2006-2007, Ext JS, LLC.
24218 * Originally Released Under LGPL - original licence link has changed is not relivant.
24221 * <script type="text/javascript">
24225 * @class Roo.data.JsonReader
24226 * @extends Roo.data.DataReader
24227 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24228 * based on mappings in a provided Roo.data.Record constructor.
24230 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24231 * in the reply previously.
24236 var RecordDef = Roo.data.Record.create([
24237 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24238 {name: 'occupation'} // This field will use "occupation" as the mapping.
24240 var myReader = new Roo.data.JsonReader({
24241 totalProperty: "results", // The property which contains the total dataset size (optional)
24242 root: "rows", // The property which contains an Array of row objects
24243 id: "id" // The property within each row object that provides an ID for the record (optional)
24247 * This would consume a JSON file like this:
24249 { 'results': 2, 'rows': [
24250 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24251 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24254 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24255 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24256 * paged from the remote server.
24257 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24258 * @cfg {String} root name of the property which contains the Array of row objects.
24259 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24260 * @cfg {Array} fields Array of field definition objects
24262 * Create a new JsonReader
24263 * @param {Object} meta Metadata configuration options
24264 * @param {Object} recordType Either an Array of field definition objects,
24265 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24267 Roo.data.JsonReader = function(meta, recordType){
24270 // set some defaults:
24271 Roo.applyIf(meta, {
24272 totalProperty: 'total',
24273 successProperty : 'success',
24278 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24280 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24283 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24284 * Used by Store query builder to append _requestMeta to params.
24287 metaFromRemote : false,
24289 * This method is only used by a DataProxy which has retrieved data from a remote server.
24290 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24291 * @return {Object} data A data block which is used by an Roo.data.Store object as
24292 * a cache of Roo.data.Records.
24294 read : function(response){
24295 var json = response.responseText;
24297 var o = /* eval:var:o */ eval("("+json+")");
24299 throw {message: "JsonReader.read: Json object not found"};
24305 this.metaFromRemote = true;
24306 this.meta = o.metaData;
24307 this.recordType = Roo.data.Record.create(o.metaData.fields);
24308 this.onMetaChange(this.meta, this.recordType, o);
24310 return this.readRecords(o);
24313 // private function a store will implement
24314 onMetaChange : function(meta, recordType, o){
24321 simpleAccess: function(obj, subsc) {
24328 getJsonAccessor: function(){
24330 return function(expr) {
24332 return(re.test(expr))
24333 ? new Function("obj", "return obj." + expr)
24338 return Roo.emptyFn;
24343 * Create a data block containing Roo.data.Records from an XML document.
24344 * @param {Object} o An object which contains an Array of row objects in the property specified
24345 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24346 * which contains the total size of the dataset.
24347 * @return {Object} data A data block which is used by an Roo.data.Store object as
24348 * a cache of Roo.data.Records.
24350 readRecords : function(o){
24352 * After any data loads, the raw JSON data is available for further custom processing.
24356 var s = this.meta, Record = this.recordType,
24357 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24359 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24361 if(s.totalProperty) {
24362 this.getTotal = this.getJsonAccessor(s.totalProperty);
24364 if(s.successProperty) {
24365 this.getSuccess = this.getJsonAccessor(s.successProperty);
24367 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24369 var g = this.getJsonAccessor(s.id);
24370 this.getId = function(rec) {
24372 return (r === undefined || r === "") ? null : r;
24375 this.getId = function(){return null;};
24378 for(var jj = 0; jj < fl; jj++){
24380 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24381 this.ef[jj] = this.getJsonAccessor(map);
24385 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24386 if(s.totalProperty){
24387 var vt = parseInt(this.getTotal(o), 10);
24392 if(s.successProperty){
24393 var vs = this.getSuccess(o);
24394 if(vs === false || vs === 'false'){
24399 for(var i = 0; i < c; i++){
24402 var id = this.getId(n);
24403 for(var j = 0; j < fl; j++){
24405 var v = this.ef[j](n);
24407 Roo.log('missing convert for ' + f.name);
24411 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24413 var record = new Record(values, id);
24415 records[i] = record;
24421 totalRecords : totalRecords
24426 * Ext JS Library 1.1.1
24427 * Copyright(c) 2006-2007, Ext JS, LLC.
24429 * Originally Released Under LGPL - original licence link has changed is not relivant.
24432 * <script type="text/javascript">
24436 * @class Roo.data.XmlReader
24437 * @extends Roo.data.DataReader
24438 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24439 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24441 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24442 * header in the HTTP response must be set to "text/xml".</em>
24446 var RecordDef = Roo.data.Record.create([
24447 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24448 {name: 'occupation'} // This field will use "occupation" as the mapping.
24450 var myReader = new Roo.data.XmlReader({
24451 totalRecords: "results", // The element which contains the total dataset size (optional)
24452 record: "row", // The repeated element which contains row information
24453 id: "id" // The element within the row that provides an ID for the record (optional)
24457 * This would consume an XML file like this:
24461 <results>2</results>
24464 <name>Bill</name>
24465 <occupation>Gardener</occupation>
24469 <name>Ben</name>
24470 <occupation>Horticulturalist</occupation>
24474 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24475 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24476 * paged from the remote server.
24477 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24478 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24479 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24480 * a record identifier value.
24482 * Create a new XmlReader
24483 * @param {Object} meta Metadata configuration options
24484 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24485 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24486 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24488 Roo.data.XmlReader = function(meta, recordType){
24490 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24492 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24494 * This method is only used by a DataProxy which has retrieved data from a remote server.
24495 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24496 * to contain a method called 'responseXML' that returns an XML document object.
24497 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24498 * a cache of Roo.data.Records.
24500 read : function(response){
24501 var doc = response.responseXML;
24503 throw {message: "XmlReader.read: XML Document not available"};
24505 return this.readRecords(doc);
24509 * Create a data block containing Roo.data.Records from an XML document.
24510 * @param {Object} doc A parsed XML document.
24511 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24512 * a cache of Roo.data.Records.
24514 readRecords : function(doc){
24516 * After any data loads/reads, the raw XML Document is available for further custom processing.
24517 * @type XMLDocument
24519 this.xmlData = doc;
24520 var root = doc.documentElement || doc;
24521 var q = Roo.DomQuery;
24522 var recordType = this.recordType, fields = recordType.prototype.fields;
24523 var sid = this.meta.id;
24524 var totalRecords = 0, success = true;
24525 if(this.meta.totalRecords){
24526 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24529 if(this.meta.success){
24530 var sv = q.selectValue(this.meta.success, root, true);
24531 success = sv !== false && sv !== 'false';
24534 var ns = q.select(this.meta.record, root);
24535 for(var i = 0, len = ns.length; i < len; i++) {
24538 var id = sid ? q.selectValue(sid, n) : undefined;
24539 for(var j = 0, jlen = fields.length; j < jlen; j++){
24540 var f = fields.items[j];
24541 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24543 values[f.name] = v;
24545 var record = new recordType(values, id);
24547 records[records.length] = record;
24553 totalRecords : totalRecords || records.length
24558 * Ext JS Library 1.1.1
24559 * Copyright(c) 2006-2007, Ext JS, LLC.
24561 * Originally Released Under LGPL - original licence link has changed is not relivant.
24564 * <script type="text/javascript">
24568 * @class Roo.data.ArrayReader
24569 * @extends Roo.data.DataReader
24570 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24571 * Each element of that Array represents a row of data fields. The
24572 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24573 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24577 var RecordDef = Roo.data.Record.create([
24578 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24579 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24581 var myReader = new Roo.data.ArrayReader({
24582 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24586 * This would consume an Array like this:
24588 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24590 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24592 * Create a new JsonReader
24593 * @param {Object} meta Metadata configuration options.
24594 * @param {Object} recordType Either an Array of field definition objects
24595 * as specified to {@link Roo.data.Record#create},
24596 * or an {@link Roo.data.Record} object
24597 * created using {@link Roo.data.Record#create}.
24599 Roo.data.ArrayReader = function(meta, recordType){
24600 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24603 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24605 * Create a data block containing Roo.data.Records from an XML document.
24606 * @param {Object} o An Array of row objects which represents the dataset.
24607 * @return {Object} data A data block which is used by an Roo.data.Store object as
24608 * a cache of Roo.data.Records.
24610 readRecords : function(o){
24611 var sid = this.meta ? this.meta.id : null;
24612 var recordType = this.recordType, fields = recordType.prototype.fields;
24615 for(var i = 0; i < root.length; i++){
24618 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24619 for(var j = 0, jlen = fields.length; j < jlen; j++){
24620 var f = fields.items[j];
24621 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24622 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24624 values[f.name] = v;
24626 var record = new recordType(values, id);
24628 records[records.length] = record;
24632 totalRecords : records.length
24637 * Ext JS Library 1.1.1
24638 * Copyright(c) 2006-2007, Ext JS, LLC.
24640 * Originally Released Under LGPL - original licence link has changed is not relivant.
24643 * <script type="text/javascript">
24648 * @class Roo.data.Tree
24649 * @extends Roo.util.Observable
24650 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24651 * in the tree have most standard DOM functionality.
24653 * @param {Node} root (optional) The root node
24655 Roo.data.Tree = function(root){
24656 this.nodeHash = {};
24658 * The root node for this tree
24663 this.setRootNode(root);
24668 * Fires when a new child node is appended to a node in this tree.
24669 * @param {Tree} tree The owner tree
24670 * @param {Node} parent The parent node
24671 * @param {Node} node The newly appended node
24672 * @param {Number} index The index of the newly appended node
24677 * Fires when a child node is removed from a node in this tree.
24678 * @param {Tree} tree The owner tree
24679 * @param {Node} parent The parent node
24680 * @param {Node} node The child node removed
24685 * Fires when a node is moved to a new location in the tree
24686 * @param {Tree} tree The owner tree
24687 * @param {Node} node The node moved
24688 * @param {Node} oldParent The old parent of this node
24689 * @param {Node} newParent The new parent of this node
24690 * @param {Number} index The index it was moved to
24695 * Fires when a new child node is inserted in a node in this tree.
24696 * @param {Tree} tree The owner tree
24697 * @param {Node} parent The parent node
24698 * @param {Node} node The child node inserted
24699 * @param {Node} refNode The child node the node was inserted before
24703 * @event beforeappend
24704 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24705 * @param {Tree} tree The owner tree
24706 * @param {Node} parent The parent node
24707 * @param {Node} node The child node to be appended
24709 "beforeappend" : true,
24711 * @event beforeremove
24712 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24713 * @param {Tree} tree The owner tree
24714 * @param {Node} parent The parent node
24715 * @param {Node} node The child node to be removed
24717 "beforeremove" : true,
24719 * @event beforemove
24720 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24721 * @param {Tree} tree The owner tree
24722 * @param {Node} node The node being moved
24723 * @param {Node} oldParent The parent of the node
24724 * @param {Node} newParent The new parent the node is moving to
24725 * @param {Number} index The index it is being moved to
24727 "beforemove" : true,
24729 * @event beforeinsert
24730 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24731 * @param {Tree} tree The owner tree
24732 * @param {Node} parent The parent node
24733 * @param {Node} node The child node to be inserted
24734 * @param {Node} refNode The child node the node is being inserted before
24736 "beforeinsert" : true
24739 Roo.data.Tree.superclass.constructor.call(this);
24742 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24743 pathSeparator: "/",
24745 proxyNodeEvent : function(){
24746 return this.fireEvent.apply(this, arguments);
24750 * Returns the root node for this tree.
24753 getRootNode : function(){
24758 * Sets the root node for this tree.
24759 * @param {Node} node
24762 setRootNode : function(node){
24764 node.ownerTree = this;
24765 node.isRoot = true;
24766 this.registerNode(node);
24771 * Gets a node in this tree by its id.
24772 * @param {String} id
24775 getNodeById : function(id){
24776 return this.nodeHash[id];
24779 registerNode : function(node){
24780 this.nodeHash[node.id] = node;
24783 unregisterNode : function(node){
24784 delete this.nodeHash[node.id];
24787 toString : function(){
24788 return "[Tree"+(this.id?" "+this.id:"")+"]";
24793 * @class Roo.data.Node
24794 * @extends Roo.util.Observable
24795 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24796 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24798 * @param {Object} attributes The attributes/config for the node
24800 Roo.data.Node = function(attributes){
24802 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24805 this.attributes = attributes || {};
24806 this.leaf = this.attributes.leaf;
24808 * The node id. @type String
24810 this.id = this.attributes.id;
24812 this.id = Roo.id(null, "ynode-");
24813 this.attributes.id = this.id;
24818 * All child nodes of this node. @type Array
24820 this.childNodes = [];
24821 if(!this.childNodes.indexOf){ // indexOf is a must
24822 this.childNodes.indexOf = function(o){
24823 for(var i = 0, len = this.length; i < len; i++){
24832 * The parent node for this node. @type Node
24834 this.parentNode = null;
24836 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24838 this.firstChild = null;
24840 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24842 this.lastChild = null;
24844 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24846 this.previousSibling = null;
24848 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24850 this.nextSibling = null;
24855 * Fires when a new child node is appended
24856 * @param {Tree} tree The owner tree
24857 * @param {Node} this This node
24858 * @param {Node} node The newly appended node
24859 * @param {Number} index The index of the newly appended node
24864 * Fires when a child node is removed
24865 * @param {Tree} tree The owner tree
24866 * @param {Node} this This node
24867 * @param {Node} node The removed node
24872 * Fires when this node is moved to a new location in the tree
24873 * @param {Tree} tree The owner tree
24874 * @param {Node} this This node
24875 * @param {Node} oldParent The old parent of this node
24876 * @param {Node} newParent The new parent of this node
24877 * @param {Number} index The index it was moved to
24882 * Fires when a new child node is inserted.
24883 * @param {Tree} tree The owner tree
24884 * @param {Node} this This node
24885 * @param {Node} node The child node inserted
24886 * @param {Node} refNode The child node the node was inserted before
24890 * @event beforeappend
24891 * Fires before a new child is appended, return false to cancel the append.
24892 * @param {Tree} tree The owner tree
24893 * @param {Node} this This node
24894 * @param {Node} node The child node to be appended
24896 "beforeappend" : true,
24898 * @event beforeremove
24899 * Fires before a child is removed, return false to cancel the remove.
24900 * @param {Tree} tree The owner tree
24901 * @param {Node} this This node
24902 * @param {Node} node The child node to be removed
24904 "beforeremove" : true,
24906 * @event beforemove
24907 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24908 * @param {Tree} tree The owner tree
24909 * @param {Node} this This node
24910 * @param {Node} oldParent The parent of this node
24911 * @param {Node} newParent The new parent this node is moving to
24912 * @param {Number} index The index it is being moved to
24914 "beforemove" : true,
24916 * @event beforeinsert
24917 * Fires before a new child is inserted, return false to cancel the insert.
24918 * @param {Tree} tree The owner tree
24919 * @param {Node} this This node
24920 * @param {Node} node The child node to be inserted
24921 * @param {Node} refNode The child node the node is being inserted before
24923 "beforeinsert" : true
24925 this.listeners = this.attributes.listeners;
24926 Roo.data.Node.superclass.constructor.call(this);
24929 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24930 fireEvent : function(evtName){
24931 // first do standard event for this node
24932 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24935 // then bubble it up to the tree if the event wasn't cancelled
24936 var ot = this.getOwnerTree();
24938 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24946 * Returns true if this node is a leaf
24947 * @return {Boolean}
24949 isLeaf : function(){
24950 return this.leaf === true;
24954 setFirstChild : function(node){
24955 this.firstChild = node;
24959 setLastChild : function(node){
24960 this.lastChild = node;
24965 * Returns true if this node is the last child of its parent
24966 * @return {Boolean}
24968 isLast : function(){
24969 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24973 * Returns true if this node is the first child of its parent
24974 * @return {Boolean}
24976 isFirst : function(){
24977 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24980 hasChildNodes : function(){
24981 return !this.isLeaf() && this.childNodes.length > 0;
24985 * Insert node(s) as the last child node of this node.
24986 * @param {Node/Array} node The node or Array of nodes to append
24987 * @return {Node} The appended node if single append, or null if an array was passed
24989 appendChild : function(node){
24991 if(node instanceof Array){
24993 }else if(arguments.length > 1){
24996 // if passed an array or multiple args do them one by one
24998 for(var i = 0, len = multi.length; i < len; i++) {
24999 this.appendChild(multi[i]);
25002 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25005 var index = this.childNodes.length;
25006 var oldParent = node.parentNode;
25007 // it's a move, make sure we move it cleanly
25009 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25012 oldParent.removeChild(node);
25014 index = this.childNodes.length;
25016 this.setFirstChild(node);
25018 this.childNodes.push(node);
25019 node.parentNode = this;
25020 var ps = this.childNodes[index-1];
25022 node.previousSibling = ps;
25023 ps.nextSibling = node;
25025 node.previousSibling = null;
25027 node.nextSibling = null;
25028 this.setLastChild(node);
25029 node.setOwnerTree(this.getOwnerTree());
25030 this.fireEvent("append", this.ownerTree, this, node, index);
25032 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25039 * Removes a child node from this node.
25040 * @param {Node} node The node to remove
25041 * @return {Node} The removed node
25043 removeChild : function(node){
25044 var index = this.childNodes.indexOf(node);
25048 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25052 // remove it from childNodes collection
25053 this.childNodes.splice(index, 1);
25056 if(node.previousSibling){
25057 node.previousSibling.nextSibling = node.nextSibling;
25059 if(node.nextSibling){
25060 node.nextSibling.previousSibling = node.previousSibling;
25063 // update child refs
25064 if(this.firstChild == node){
25065 this.setFirstChild(node.nextSibling);
25067 if(this.lastChild == node){
25068 this.setLastChild(node.previousSibling);
25071 node.setOwnerTree(null);
25072 // clear any references from the node
25073 node.parentNode = null;
25074 node.previousSibling = null;
25075 node.nextSibling = null;
25076 this.fireEvent("remove", this.ownerTree, this, node);
25081 * Inserts the first node before the second node in this nodes childNodes collection.
25082 * @param {Node} node The node to insert
25083 * @param {Node} refNode The node to insert before (if null the node is appended)
25084 * @return {Node} The inserted node
25086 insertBefore : function(node, refNode){
25087 if(!refNode){ // like standard Dom, refNode can be null for append
25088 return this.appendChild(node);
25091 if(node == refNode){
25095 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25098 var index = this.childNodes.indexOf(refNode);
25099 var oldParent = node.parentNode;
25100 var refIndex = index;
25102 // when moving internally, indexes will change after remove
25103 if(oldParent == this && this.childNodes.indexOf(node) < index){
25107 // it's a move, make sure we move it cleanly
25109 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25112 oldParent.removeChild(node);
25115 this.setFirstChild(node);
25117 this.childNodes.splice(refIndex, 0, node);
25118 node.parentNode = this;
25119 var ps = this.childNodes[refIndex-1];
25121 node.previousSibling = ps;
25122 ps.nextSibling = node;
25124 node.previousSibling = null;
25126 node.nextSibling = refNode;
25127 refNode.previousSibling = node;
25128 node.setOwnerTree(this.getOwnerTree());
25129 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25131 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25137 * Returns the child node at the specified index.
25138 * @param {Number} index
25141 item : function(index){
25142 return this.childNodes[index];
25146 * Replaces one child node in this node with another.
25147 * @param {Node} newChild The replacement node
25148 * @param {Node} oldChild The node to replace
25149 * @return {Node} The replaced node
25151 replaceChild : function(newChild, oldChild){
25152 this.insertBefore(newChild, oldChild);
25153 this.removeChild(oldChild);
25158 * Returns the index of a child node
25159 * @param {Node} node
25160 * @return {Number} The index of the node or -1 if it was not found
25162 indexOf : function(child){
25163 return this.childNodes.indexOf(child);
25167 * Returns the tree this node is in.
25170 getOwnerTree : function(){
25171 // if it doesn't have one, look for one
25172 if(!this.ownerTree){
25176 this.ownerTree = p.ownerTree;
25182 return this.ownerTree;
25186 * Returns depth of this node (the root node has a depth of 0)
25189 getDepth : function(){
25192 while(p.parentNode){
25200 setOwnerTree : function(tree){
25201 // if it's move, we need to update everyone
25202 if(tree != this.ownerTree){
25203 if(this.ownerTree){
25204 this.ownerTree.unregisterNode(this);
25206 this.ownerTree = tree;
25207 var cs = this.childNodes;
25208 for(var i = 0, len = cs.length; i < len; i++) {
25209 cs[i].setOwnerTree(tree);
25212 tree.registerNode(this);
25218 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25219 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25220 * @return {String} The path
25222 getPath : function(attr){
25223 attr = attr || "id";
25224 var p = this.parentNode;
25225 var b = [this.attributes[attr]];
25227 b.unshift(p.attributes[attr]);
25230 var sep = this.getOwnerTree().pathSeparator;
25231 return sep + b.join(sep);
25235 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25236 * function call will be the scope provided or the current node. The arguments to the function
25237 * will be the args provided or the current node. If the function returns false at any point,
25238 * the bubble is stopped.
25239 * @param {Function} fn The function to call
25240 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25241 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25243 bubble : function(fn, scope, args){
25246 if(fn.call(scope || p, args || p) === false){
25254 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25255 * function call will be the scope provided or the current node. The arguments to the function
25256 * will be the args provided or the current node. If the function returns false at any point,
25257 * the cascade is stopped on that branch.
25258 * @param {Function} fn The function to call
25259 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25260 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25262 cascade : function(fn, scope, args){
25263 if(fn.call(scope || this, args || this) !== false){
25264 var cs = this.childNodes;
25265 for(var i = 0, len = cs.length; i < len; i++) {
25266 cs[i].cascade(fn, scope, args);
25272 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25273 * function call will be the scope provided or the current node. The arguments to the function
25274 * will be the args provided or the current node. If the function returns false at any point,
25275 * the iteration stops.
25276 * @param {Function} fn The function to call
25277 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25278 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25280 eachChild : function(fn, scope, args){
25281 var cs = this.childNodes;
25282 for(var i = 0, len = cs.length; i < len; i++) {
25283 if(fn.call(scope || this, args || cs[i]) === false){
25290 * Finds the first child that has the attribute with the specified value.
25291 * @param {String} attribute The attribute name
25292 * @param {Mixed} value The value to search for
25293 * @return {Node} The found child or null if none was found
25295 findChild : function(attribute, value){
25296 var cs = this.childNodes;
25297 for(var i = 0, len = cs.length; i < len; i++) {
25298 if(cs[i].attributes[attribute] == value){
25306 * Finds the first child by a custom function. The child matches if the function passed
25308 * @param {Function} fn
25309 * @param {Object} scope (optional)
25310 * @return {Node} The found child or null if none was found
25312 findChildBy : function(fn, scope){
25313 var cs = this.childNodes;
25314 for(var i = 0, len = cs.length; i < len; i++) {
25315 if(fn.call(scope||cs[i], cs[i]) === true){
25323 * Sorts this nodes children using the supplied sort function
25324 * @param {Function} fn
25325 * @param {Object} scope (optional)
25327 sort : function(fn, scope){
25328 var cs = this.childNodes;
25329 var len = cs.length;
25331 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25333 for(var i = 0; i < len; i++){
25335 n.previousSibling = cs[i-1];
25336 n.nextSibling = cs[i+1];
25338 this.setFirstChild(n);
25341 this.setLastChild(n);
25348 * Returns true if this node is an ancestor (at any point) of the passed node.
25349 * @param {Node} node
25350 * @return {Boolean}
25352 contains : function(node){
25353 return node.isAncestor(this);
25357 * Returns true if the passed node is an ancestor (at any point) of this node.
25358 * @param {Node} node
25359 * @return {Boolean}
25361 isAncestor : function(node){
25362 var p = this.parentNode;
25372 toString : function(){
25373 return "[Node"+(this.id?" "+this.id:"")+"]";
25377 * Ext JS Library 1.1.1
25378 * Copyright(c) 2006-2007, Ext JS, LLC.
25380 * Originally Released Under LGPL - original licence link has changed is not relivant.
25383 * <script type="text/javascript">
25388 * @extends Roo.Element
25389 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25390 * automatic maintaining of shadow/shim positions.
25391 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25392 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25393 * you can pass a string with a CSS class name. False turns off the shadow.
25394 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25395 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25396 * @cfg {String} cls CSS class to add to the element
25397 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25398 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25400 * @param {Object} config An object with config options.
25401 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25404 Roo.Layer = function(config, existingEl){
25405 config = config || {};
25406 var dh = Roo.DomHelper;
25407 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25409 this.dom = Roo.getDom(existingEl);
25412 var o = config.dh || {tag: "div", cls: "x-layer"};
25413 this.dom = dh.append(pel, o);
25416 this.addClass(config.cls);
25418 this.constrain = config.constrain !== false;
25419 this.visibilityMode = Roo.Element.VISIBILITY;
25421 this.id = this.dom.id = config.id;
25423 this.id = Roo.id(this.dom);
25425 this.zindex = config.zindex || this.getZIndex();
25426 this.position("absolute", this.zindex);
25428 this.shadowOffset = config.shadowOffset || 4;
25429 this.shadow = new Roo.Shadow({
25430 offset : this.shadowOffset,
25431 mode : config.shadow
25434 this.shadowOffset = 0;
25436 this.useShim = config.shim !== false && Roo.useShims;
25437 this.useDisplay = config.useDisplay;
25441 var supr = Roo.Element.prototype;
25443 // shims are shared among layer to keep from having 100 iframes
25446 Roo.extend(Roo.Layer, Roo.Element, {
25448 getZIndex : function(){
25449 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25452 getShim : function(){
25459 var shim = shims.shift();
25461 shim = this.createShim();
25462 shim.enableDisplayMode('block');
25463 shim.dom.style.display = 'none';
25464 shim.dom.style.visibility = 'visible';
25466 var pn = this.dom.parentNode;
25467 if(shim.dom.parentNode != pn){
25468 pn.insertBefore(shim.dom, this.dom);
25470 shim.setStyle('z-index', this.getZIndex()-2);
25475 hideShim : function(){
25477 this.shim.setDisplayed(false);
25478 shims.push(this.shim);
25483 disableShadow : function(){
25485 this.shadowDisabled = true;
25486 this.shadow.hide();
25487 this.lastShadowOffset = this.shadowOffset;
25488 this.shadowOffset = 0;
25492 enableShadow : function(show){
25494 this.shadowDisabled = false;
25495 this.shadowOffset = this.lastShadowOffset;
25496 delete this.lastShadowOffset;
25504 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25505 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25506 sync : function(doShow){
25507 var sw = this.shadow;
25508 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25509 var sh = this.getShim();
25511 var w = this.getWidth(),
25512 h = this.getHeight();
25514 var l = this.getLeft(true),
25515 t = this.getTop(true);
25517 if(sw && !this.shadowDisabled){
25518 if(doShow && !sw.isVisible()){
25521 sw.realign(l, t, w, h);
25527 // fit the shim behind the shadow, so it is shimmed too
25528 var a = sw.adjusts, s = sh.dom.style;
25529 s.left = (Math.min(l, l+a.l))+"px";
25530 s.top = (Math.min(t, t+a.t))+"px";
25531 s.width = (w+a.w)+"px";
25532 s.height = (h+a.h)+"px";
25539 sh.setLeftTop(l, t);
25546 destroy : function(){
25549 this.shadow.hide();
25551 this.removeAllListeners();
25552 var pn = this.dom.parentNode;
25554 pn.removeChild(this.dom);
25556 Roo.Element.uncache(this.id);
25559 remove : function(){
25564 beginUpdate : function(){
25565 this.updating = true;
25569 endUpdate : function(){
25570 this.updating = false;
25575 hideUnders : function(negOffset){
25577 this.shadow.hide();
25583 constrainXY : function(){
25584 if(this.constrain){
25585 var vw = Roo.lib.Dom.getViewWidth(),
25586 vh = Roo.lib.Dom.getViewHeight();
25587 var s = Roo.get(document).getScroll();
25589 var xy = this.getXY();
25590 var x = xy[0], y = xy[1];
25591 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25592 // only move it if it needs it
25594 // first validate right/bottom
25595 if((x + w) > vw+s.left){
25596 x = vw - w - this.shadowOffset;
25599 if((y + h) > vh+s.top){
25600 y = vh - h - this.shadowOffset;
25603 // then make sure top/left isn't negative
25614 var ay = this.avoidY;
25615 if(y <= ay && (y+h) >= ay){
25621 supr.setXY.call(this, xy);
25627 isVisible : function(){
25628 return this.visible;
25632 showAction : function(){
25633 this.visible = true; // track visibility to prevent getStyle calls
25634 if(this.useDisplay === true){
25635 this.setDisplayed("");
25636 }else if(this.lastXY){
25637 supr.setXY.call(this, this.lastXY);
25638 }else if(this.lastLT){
25639 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25644 hideAction : function(){
25645 this.visible = false;
25646 if(this.useDisplay === true){
25647 this.setDisplayed(false);
25649 this.setLeftTop(-10000,-10000);
25653 // overridden Element method
25654 setVisible : function(v, a, d, c, e){
25659 var cb = function(){
25664 }.createDelegate(this);
25665 supr.setVisible.call(this, true, true, d, cb, e);
25668 this.hideUnders(true);
25677 }.createDelegate(this);
25679 supr.setVisible.call(this, v, a, d, cb, e);
25688 storeXY : function(xy){
25689 delete this.lastLT;
25693 storeLeftTop : function(left, top){
25694 delete this.lastXY;
25695 this.lastLT = [left, top];
25699 beforeFx : function(){
25700 this.beforeAction();
25701 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25705 afterFx : function(){
25706 Roo.Layer.superclass.afterFx.apply(this, arguments);
25707 this.sync(this.isVisible());
25711 beforeAction : function(){
25712 if(!this.updating && this.shadow){
25713 this.shadow.hide();
25717 // overridden Element method
25718 setLeft : function(left){
25719 this.storeLeftTop(left, this.getTop(true));
25720 supr.setLeft.apply(this, arguments);
25724 setTop : function(top){
25725 this.storeLeftTop(this.getLeft(true), top);
25726 supr.setTop.apply(this, arguments);
25730 setLeftTop : function(left, top){
25731 this.storeLeftTop(left, top);
25732 supr.setLeftTop.apply(this, arguments);
25736 setXY : function(xy, a, d, c, e){
25738 this.beforeAction();
25740 var cb = this.createCB(c);
25741 supr.setXY.call(this, xy, a, d, cb, e);
25748 createCB : function(c){
25759 // overridden Element method
25760 setX : function(x, a, d, c, e){
25761 this.setXY([x, this.getY()], a, d, c, e);
25764 // overridden Element method
25765 setY : function(y, a, d, c, e){
25766 this.setXY([this.getX(), y], a, d, c, e);
25769 // overridden Element method
25770 setSize : function(w, h, a, d, c, e){
25771 this.beforeAction();
25772 var cb = this.createCB(c);
25773 supr.setSize.call(this, w, h, a, d, cb, e);
25779 // overridden Element method
25780 setWidth : function(w, a, d, c, e){
25781 this.beforeAction();
25782 var cb = this.createCB(c);
25783 supr.setWidth.call(this, w, a, d, cb, e);
25789 // overridden Element method
25790 setHeight : function(h, a, d, c, e){
25791 this.beforeAction();
25792 var cb = this.createCB(c);
25793 supr.setHeight.call(this, h, a, d, cb, e);
25799 // overridden Element method
25800 setBounds : function(x, y, w, h, a, d, c, e){
25801 this.beforeAction();
25802 var cb = this.createCB(c);
25804 this.storeXY([x, y]);
25805 supr.setXY.call(this, [x, y]);
25806 supr.setSize.call(this, w, h, a, d, cb, e);
25809 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25815 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25816 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25817 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25818 * @param {Number} zindex The new z-index to set
25819 * @return {this} The Layer
25821 setZIndex : function(zindex){
25822 this.zindex = zindex;
25823 this.setStyle("z-index", zindex + 2);
25825 this.shadow.setZIndex(zindex + 1);
25828 this.shim.setStyle("z-index", zindex);
25834 * Ext JS Library 1.1.1
25835 * Copyright(c) 2006-2007, Ext JS, LLC.
25837 * Originally Released Under LGPL - original licence link has changed is not relivant.
25840 * <script type="text/javascript">
25845 * @class Roo.Shadow
25846 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25847 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25848 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25850 * Create a new Shadow
25851 * @param {Object} config The config object
25853 Roo.Shadow = function(config){
25854 Roo.apply(this, config);
25855 if(typeof this.mode != "string"){
25856 this.mode = this.defaultMode;
25858 var o = this.offset, a = {h: 0};
25859 var rad = Math.floor(this.offset/2);
25860 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25866 a.l -= this.offset + rad;
25867 a.t -= this.offset + rad;
25878 a.l -= (this.offset - rad);
25879 a.t -= this.offset + rad;
25881 a.w -= (this.offset - rad)*2;
25892 a.l -= (this.offset - rad);
25893 a.t -= (this.offset - rad);
25895 a.w -= (this.offset + rad + 1);
25896 a.h -= (this.offset + rad);
25905 Roo.Shadow.prototype = {
25907 * @cfg {String} mode
25908 * The shadow display mode. Supports the following options:<br />
25909 * sides: Shadow displays on both sides and bottom only<br />
25910 * frame: Shadow displays equally on all four sides<br />
25911 * drop: Traditional bottom-right drop shadow (default)
25914 * @cfg {String} offset
25915 * The number of pixels to offset the shadow from the element (defaults to 4)
25920 defaultMode: "drop",
25923 * Displays the shadow under the target element
25924 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25926 show : function(target){
25927 target = Roo.get(target);
25929 this.el = Roo.Shadow.Pool.pull();
25930 if(this.el.dom.nextSibling != target.dom){
25931 this.el.insertBefore(target);
25934 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25936 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25939 target.getLeft(true),
25940 target.getTop(true),
25944 this.el.dom.style.display = "block";
25948 * Returns true if the shadow is visible, else false
25950 isVisible : function(){
25951 return this.el ? true : false;
25955 * Direct alignment when values are already available. Show must be called at least once before
25956 * calling this method to ensure it is initialized.
25957 * @param {Number} left The target element left position
25958 * @param {Number} top The target element top position
25959 * @param {Number} width The target element width
25960 * @param {Number} height The target element height
25962 realign : function(l, t, w, h){
25966 var a = this.adjusts, d = this.el.dom, s = d.style;
25968 s.left = (l+a.l)+"px";
25969 s.top = (t+a.t)+"px";
25970 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25972 if(s.width != sws || s.height != shs){
25976 var cn = d.childNodes;
25977 var sww = Math.max(0, (sw-12))+"px";
25978 cn[0].childNodes[1].style.width = sww;
25979 cn[1].childNodes[1].style.width = sww;
25980 cn[2].childNodes[1].style.width = sww;
25981 cn[1].style.height = Math.max(0, (sh-12))+"px";
25987 * Hides this shadow
25991 this.el.dom.style.display = "none";
25992 Roo.Shadow.Pool.push(this.el);
25998 * Adjust the z-index of this shadow
25999 * @param {Number} zindex The new z-index
26001 setZIndex : function(z){
26004 this.el.setStyle("z-index", z);
26009 // Private utility class that manages the internal Shadow cache
26010 Roo.Shadow.Pool = function(){
26012 var markup = Roo.isIE ?
26013 '<div class="x-ie-shadow"></div>' :
26014 '<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>';
26017 var sh = p.shift();
26019 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26020 sh.autoBoxAdjust = false;
26025 push : function(sh){
26031 * Ext JS Library 1.1.1
26032 * Copyright(c) 2006-2007, Ext JS, LLC.
26034 * Originally Released Under LGPL - original licence link has changed is not relivant.
26037 * <script type="text/javascript">
26042 * @class Roo.SplitBar
26043 * @extends Roo.util.Observable
26044 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26048 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26049 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26050 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26051 split.minSize = 100;
26052 split.maxSize = 600;
26053 split.animate = true;
26054 split.on('moved', splitterMoved);
26057 * Create a new SplitBar
26058 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26059 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26060 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26061 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26062 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26063 position of the SplitBar).
26065 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26068 this.el = Roo.get(dragElement, true);
26069 this.el.dom.unselectable = "on";
26071 this.resizingEl = Roo.get(resizingElement, true);
26075 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26076 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26079 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26082 * The minimum size of the resizing element. (Defaults to 0)
26088 * The maximum size of the resizing element. (Defaults to 2000)
26091 this.maxSize = 2000;
26094 * Whether to animate the transition to the new size
26097 this.animate = false;
26100 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26103 this.useShim = false;
26108 if(!existingProxy){
26110 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26112 this.proxy = Roo.get(existingProxy).dom;
26115 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26118 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26121 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26124 this.dragSpecs = {};
26127 * @private The adapter to use to positon and resize elements
26129 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26130 this.adapter.init(this);
26132 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26134 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26135 this.el.addClass("x-splitbar-h");
26138 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26139 this.el.addClass("x-splitbar-v");
26145 * Fires when the splitter is moved (alias for {@link #event-moved})
26146 * @param {Roo.SplitBar} this
26147 * @param {Number} newSize the new width or height
26152 * Fires when the splitter is moved
26153 * @param {Roo.SplitBar} this
26154 * @param {Number} newSize the new width or height
26158 * @event beforeresize
26159 * Fires before the splitter is dragged
26160 * @param {Roo.SplitBar} this
26162 "beforeresize" : true,
26164 "beforeapply" : true
26167 Roo.util.Observable.call(this);
26170 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26171 onStartProxyDrag : function(x, y){
26172 this.fireEvent("beforeresize", this);
26174 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26176 o.enableDisplayMode("block");
26177 // all splitbars share the same overlay
26178 Roo.SplitBar.prototype.overlay = o;
26180 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26181 this.overlay.show();
26182 Roo.get(this.proxy).setDisplayed("block");
26183 var size = this.adapter.getElementSize(this);
26184 this.activeMinSize = this.getMinimumSize();;
26185 this.activeMaxSize = this.getMaximumSize();;
26186 var c1 = size - this.activeMinSize;
26187 var c2 = Math.max(this.activeMaxSize - size, 0);
26188 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26189 this.dd.resetConstraints();
26190 this.dd.setXConstraint(
26191 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26192 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26194 this.dd.setYConstraint(0, 0);
26196 this.dd.resetConstraints();
26197 this.dd.setXConstraint(0, 0);
26198 this.dd.setYConstraint(
26199 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26200 this.placement == Roo.SplitBar.TOP ? c2 : c1
26203 this.dragSpecs.startSize = size;
26204 this.dragSpecs.startPoint = [x, y];
26205 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26209 * @private Called after the drag operation by the DDProxy
26211 onEndProxyDrag : function(e){
26212 Roo.get(this.proxy).setDisplayed(false);
26213 var endPoint = Roo.lib.Event.getXY(e);
26215 this.overlay.hide();
26218 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26219 newSize = this.dragSpecs.startSize +
26220 (this.placement == Roo.SplitBar.LEFT ?
26221 endPoint[0] - this.dragSpecs.startPoint[0] :
26222 this.dragSpecs.startPoint[0] - endPoint[0]
26225 newSize = this.dragSpecs.startSize +
26226 (this.placement == Roo.SplitBar.TOP ?
26227 endPoint[1] - this.dragSpecs.startPoint[1] :
26228 this.dragSpecs.startPoint[1] - endPoint[1]
26231 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26232 if(newSize != this.dragSpecs.startSize){
26233 if(this.fireEvent('beforeapply', this, newSize) !== false){
26234 this.adapter.setElementSize(this, newSize);
26235 this.fireEvent("moved", this, newSize);
26236 this.fireEvent("resize", this, newSize);
26242 * Get the adapter this SplitBar uses
26243 * @return The adapter object
26245 getAdapter : function(){
26246 return this.adapter;
26250 * Set the adapter this SplitBar uses
26251 * @param {Object} adapter A SplitBar adapter object
26253 setAdapter : function(adapter){
26254 this.adapter = adapter;
26255 this.adapter.init(this);
26259 * Gets the minimum size for the resizing element
26260 * @return {Number} The minimum size
26262 getMinimumSize : function(){
26263 return this.minSize;
26267 * Sets the minimum size for the resizing element
26268 * @param {Number} minSize The minimum size
26270 setMinimumSize : function(minSize){
26271 this.minSize = minSize;
26275 * Gets the maximum size for the resizing element
26276 * @return {Number} The maximum size
26278 getMaximumSize : function(){
26279 return this.maxSize;
26283 * Sets the maximum size for the resizing element
26284 * @param {Number} maxSize The maximum size
26286 setMaximumSize : function(maxSize){
26287 this.maxSize = maxSize;
26291 * Sets the initialize size for the resizing element
26292 * @param {Number} size The initial size
26294 setCurrentSize : function(size){
26295 var oldAnimate = this.animate;
26296 this.animate = false;
26297 this.adapter.setElementSize(this, size);
26298 this.animate = oldAnimate;
26302 * Destroy this splitbar.
26303 * @param {Boolean} removeEl True to remove the element
26305 destroy : function(removeEl){
26307 this.shim.remove();
26310 this.proxy.parentNode.removeChild(this.proxy);
26318 * @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.
26320 Roo.SplitBar.createProxy = function(dir){
26321 var proxy = new Roo.Element(document.createElement("div"));
26322 proxy.unselectable();
26323 var cls = 'x-splitbar-proxy';
26324 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26325 document.body.appendChild(proxy.dom);
26330 * @class Roo.SplitBar.BasicLayoutAdapter
26331 * Default Adapter. It assumes the splitter and resizing element are not positioned
26332 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26334 Roo.SplitBar.BasicLayoutAdapter = function(){
26337 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26338 // do nothing for now
26339 init : function(s){
26343 * Called before drag operations to get the current size of the resizing element.
26344 * @param {Roo.SplitBar} s The SplitBar using this adapter
26346 getElementSize : function(s){
26347 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26348 return s.resizingEl.getWidth();
26350 return s.resizingEl.getHeight();
26355 * Called after drag operations to set the size of the resizing element.
26356 * @param {Roo.SplitBar} s The SplitBar using this adapter
26357 * @param {Number} newSize The new size to set
26358 * @param {Function} onComplete A function to be invoked when resizing is complete
26360 setElementSize : function(s, newSize, onComplete){
26361 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26363 s.resizingEl.setWidth(newSize);
26365 onComplete(s, newSize);
26368 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26373 s.resizingEl.setHeight(newSize);
26375 onComplete(s, newSize);
26378 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26385 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26386 * @extends Roo.SplitBar.BasicLayoutAdapter
26387 * Adapter that moves the splitter element to align with the resized sizing element.
26388 * Used with an absolute positioned SplitBar.
26389 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26390 * document.body, make sure you assign an id to the body element.
26392 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26393 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26394 this.container = Roo.get(container);
26397 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26398 init : function(s){
26399 this.basic.init(s);
26402 getElementSize : function(s){
26403 return this.basic.getElementSize(s);
26406 setElementSize : function(s, newSize, onComplete){
26407 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26410 moveSplitter : function(s){
26411 var yes = Roo.SplitBar;
26412 switch(s.placement){
26414 s.el.setX(s.resizingEl.getRight());
26417 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26420 s.el.setY(s.resizingEl.getBottom());
26423 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26430 * Orientation constant - Create a vertical SplitBar
26434 Roo.SplitBar.VERTICAL = 1;
26437 * Orientation constant - Create a horizontal SplitBar
26441 Roo.SplitBar.HORIZONTAL = 2;
26444 * Placement constant - The resizing element is to the left of the splitter element
26448 Roo.SplitBar.LEFT = 1;
26451 * Placement constant - The resizing element is to the right of the splitter element
26455 Roo.SplitBar.RIGHT = 2;
26458 * Placement constant - The resizing element is positioned above the splitter element
26462 Roo.SplitBar.TOP = 3;
26465 * Placement constant - The resizing element is positioned under splitter element
26469 Roo.SplitBar.BOTTOM = 4;
26472 * Ext JS Library 1.1.1
26473 * Copyright(c) 2006-2007, Ext JS, LLC.
26475 * Originally Released Under LGPL - original licence link has changed is not relivant.
26478 * <script type="text/javascript">
26483 * @extends Roo.util.Observable
26484 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26485 * This class also supports single and multi selection modes. <br>
26486 * Create a data model bound view:
26488 var store = new Roo.data.Store(...);
26490 var view = new Roo.View({
26492 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26494 singleSelect: true,
26495 selectedClass: "ydataview-selected",
26499 // listen for node click?
26500 view.on("click", function(vw, index, node, e){
26501 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26505 dataModel.load("foobar.xml");
26507 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26509 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26510 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26512 * Note: old style constructor is still suported (container, template, config)
26515 * Create a new View
26516 * @param {Object} config The config object
26519 Roo.View = function(config, depreciated_tpl, depreciated_config){
26521 this.parent = false;
26523 if (typeof(depreciated_tpl) == 'undefined') {
26524 // new way.. - universal constructor.
26525 Roo.apply(this, config);
26526 this.el = Roo.get(this.el);
26529 this.el = Roo.get(config);
26530 this.tpl = depreciated_tpl;
26531 Roo.apply(this, depreciated_config);
26533 this.wrapEl = this.el.wrap().wrap();
26534 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26537 if(typeof(this.tpl) == "string"){
26538 this.tpl = new Roo.Template(this.tpl);
26540 // support xtype ctors..
26541 this.tpl = new Roo.factory(this.tpl, Roo);
26545 this.tpl.compile();
26550 * @event beforeclick
26551 * Fires before a click is processed. Returns false to cancel the default action.
26552 * @param {Roo.View} this
26553 * @param {Number} index The index of the target node
26554 * @param {HTMLElement} node The target node
26555 * @param {Roo.EventObject} e The raw event object
26557 "beforeclick" : true,
26560 * Fires when a template node is clicked.
26561 * @param {Roo.View} this
26562 * @param {Number} index The index of the target node
26563 * @param {HTMLElement} node The target node
26564 * @param {Roo.EventObject} e The raw event object
26569 * Fires when a template node is double clicked.
26570 * @param {Roo.View} this
26571 * @param {Number} index The index of the target node
26572 * @param {HTMLElement} node The target node
26573 * @param {Roo.EventObject} e The raw event object
26577 * @event contextmenu
26578 * Fires when a template node is right clicked.
26579 * @param {Roo.View} this
26580 * @param {Number} index The index of the target node
26581 * @param {HTMLElement} node The target node
26582 * @param {Roo.EventObject} e The raw event object
26584 "contextmenu" : true,
26586 * @event selectionchange
26587 * Fires when the selected nodes change.
26588 * @param {Roo.View} this
26589 * @param {Array} selections Array of the selected nodes
26591 "selectionchange" : true,
26594 * @event beforeselect
26595 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26596 * @param {Roo.View} this
26597 * @param {HTMLElement} node The node to be selected
26598 * @param {Array} selections Array of currently selected nodes
26600 "beforeselect" : true,
26602 * @event preparedata
26603 * Fires on every row to render, to allow you to change the data.
26604 * @param {Roo.View} this
26605 * @param {Object} data to be rendered (change this)
26607 "preparedata" : true
26615 "click": this.onClick,
26616 "dblclick": this.onDblClick,
26617 "contextmenu": this.onContextMenu,
26621 this.selections = [];
26623 this.cmp = new Roo.CompositeElementLite([]);
26625 this.store = Roo.factory(this.store, Roo.data);
26626 this.setStore(this.store, true);
26629 if ( this.footer && this.footer.xtype) {
26631 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26633 this.footer.dataSource = this.store;
26634 this.footer.container = fctr;
26635 this.footer = Roo.factory(this.footer, Roo);
26636 fctr.insertFirst(this.el);
26638 // this is a bit insane - as the paging toolbar seems to detach the el..
26639 // dom.parentNode.parentNode.parentNode
26640 // they get detached?
26644 Roo.View.superclass.constructor.call(this);
26649 Roo.extend(Roo.View, Roo.util.Observable, {
26652 * @cfg {Roo.data.Store} store Data store to load data from.
26657 * @cfg {String|Roo.Element} el The container element.
26662 * @cfg {String|Roo.Template} tpl The template used by this View
26666 * @cfg {String} dataName the named area of the template to use as the data area
26667 * Works with domtemplates roo-name="name"
26671 * @cfg {String} selectedClass The css class to add to selected nodes
26673 selectedClass : "x-view-selected",
26675 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26680 * @cfg {String} text to display on mask (default Loading)
26684 * @cfg {Boolean} multiSelect Allow multiple selection
26686 multiSelect : false,
26688 * @cfg {Boolean} singleSelect Allow single selection
26690 singleSelect: false,
26693 * @cfg {Boolean} toggleSelect - selecting
26695 toggleSelect : false,
26698 * @cfg {Boolean} tickable - selecting
26703 * Returns the element this view is bound to.
26704 * @return {Roo.Element}
26706 getEl : function(){
26707 return this.wrapEl;
26713 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26715 refresh : function(){
26716 //Roo.log('refresh');
26719 // if we are using something like 'domtemplate', then
26720 // the what gets used is:
26721 // t.applySubtemplate(NAME, data, wrapping data..)
26722 // the outer template then get' applied with
26723 // the store 'extra data'
26724 // and the body get's added to the
26725 // roo-name="data" node?
26726 // <span class='roo-tpl-{name}'></span> ?????
26730 this.clearSelections();
26731 this.el.update("");
26733 var records = this.store.getRange();
26734 if(records.length < 1) {
26736 // is this valid?? = should it render a template??
26738 this.el.update(this.emptyText);
26742 if (this.dataName) {
26743 this.el.update(t.apply(this.store.meta)); //????
26744 el = this.el.child('.roo-tpl-' + this.dataName);
26747 for(var i = 0, len = records.length; i < len; i++){
26748 var data = this.prepareData(records[i].data, i, records[i]);
26749 this.fireEvent("preparedata", this, data, i, records[i]);
26751 var d = Roo.apply({}, data);
26754 Roo.apply(d, {'roo-id' : Roo.id()});
26758 Roo.each(this.parent.item, function(item){
26759 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26762 Roo.apply(d, {'roo-data-checked' : 'checked'});
26766 html[html.length] = Roo.util.Format.trim(
26768 t.applySubtemplate(this.dataName, d, this.store.meta) :
26775 el.update(html.join(""));
26776 this.nodes = el.dom.childNodes;
26777 this.updateIndexes(0);
26782 * Function to override to reformat the data that is sent to
26783 * the template for each node.
26784 * DEPRICATED - use the preparedata event handler.
26785 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26786 * a JSON object for an UpdateManager bound view).
26788 prepareData : function(data, index, record)
26790 this.fireEvent("preparedata", this, data, index, record);
26794 onUpdate : function(ds, record){
26795 // Roo.log('on update');
26796 this.clearSelections();
26797 var index = this.store.indexOf(record);
26798 var n = this.nodes[index];
26799 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26800 n.parentNode.removeChild(n);
26801 this.updateIndexes(index, index);
26807 onAdd : function(ds, records, index)
26809 //Roo.log(['on Add', ds, records, index] );
26810 this.clearSelections();
26811 if(this.nodes.length == 0){
26815 var n = this.nodes[index];
26816 for(var i = 0, len = records.length; i < len; i++){
26817 var d = this.prepareData(records[i].data, i, records[i]);
26819 this.tpl.insertBefore(n, d);
26822 this.tpl.append(this.el, d);
26825 this.updateIndexes(index);
26828 onRemove : function(ds, record, index){
26829 // Roo.log('onRemove');
26830 this.clearSelections();
26831 var el = this.dataName ?
26832 this.el.child('.roo-tpl-' + this.dataName) :
26835 el.dom.removeChild(this.nodes[index]);
26836 this.updateIndexes(index);
26840 * Refresh an individual node.
26841 * @param {Number} index
26843 refreshNode : function(index){
26844 this.onUpdate(this.store, this.store.getAt(index));
26847 updateIndexes : function(startIndex, endIndex){
26848 var ns = this.nodes;
26849 startIndex = startIndex || 0;
26850 endIndex = endIndex || ns.length - 1;
26851 for(var i = startIndex; i <= endIndex; i++){
26852 ns[i].nodeIndex = i;
26857 * Changes the data store this view uses and refresh the view.
26858 * @param {Store} store
26860 setStore : function(store, initial){
26861 if(!initial && this.store){
26862 this.store.un("datachanged", this.refresh);
26863 this.store.un("add", this.onAdd);
26864 this.store.un("remove", this.onRemove);
26865 this.store.un("update", this.onUpdate);
26866 this.store.un("clear", this.refresh);
26867 this.store.un("beforeload", this.onBeforeLoad);
26868 this.store.un("load", this.onLoad);
26869 this.store.un("loadexception", this.onLoad);
26873 store.on("datachanged", this.refresh, this);
26874 store.on("add", this.onAdd, this);
26875 store.on("remove", this.onRemove, this);
26876 store.on("update", this.onUpdate, this);
26877 store.on("clear", this.refresh, this);
26878 store.on("beforeload", this.onBeforeLoad, this);
26879 store.on("load", this.onLoad, this);
26880 store.on("loadexception", this.onLoad, this);
26888 * onbeforeLoad - masks the loading area.
26891 onBeforeLoad : function(store,opts)
26893 //Roo.log('onBeforeLoad');
26895 this.el.update("");
26897 this.el.mask(this.mask ? this.mask : "Loading" );
26899 onLoad : function ()
26906 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26907 * @param {HTMLElement} node
26908 * @return {HTMLElement} The template node
26910 findItemFromChild : function(node){
26911 var el = this.dataName ?
26912 this.el.child('.roo-tpl-' + this.dataName,true) :
26915 if(!node || node.parentNode == el){
26918 var p = node.parentNode;
26919 while(p && p != el){
26920 if(p.parentNode == el){
26929 onClick : function(e){
26930 var item = this.findItemFromChild(e.getTarget());
26932 var index = this.indexOf(item);
26933 if(this.onItemClick(item, index, e) !== false){
26934 this.fireEvent("click", this, index, item, e);
26937 this.clearSelections();
26942 onContextMenu : function(e){
26943 var item = this.findItemFromChild(e.getTarget());
26945 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26950 onDblClick : function(e){
26951 var item = this.findItemFromChild(e.getTarget());
26953 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26957 onItemClick : function(item, index, e)
26959 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26962 if (this.toggleSelect) {
26963 var m = this.isSelected(item) ? 'unselect' : 'select';
26966 _t[m](item, true, false);
26969 if(this.multiSelect || this.singleSelect){
26970 if(this.multiSelect && e.shiftKey && this.lastSelection){
26971 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26973 this.select(item, this.multiSelect && e.ctrlKey);
26974 this.lastSelection = item;
26977 if(!this.tickable){
26978 e.preventDefault();
26986 * Get the number of selected nodes.
26989 getSelectionCount : function(){
26990 return this.selections.length;
26994 * Get the currently selected nodes.
26995 * @return {Array} An array of HTMLElements
26997 getSelectedNodes : function(){
26998 return this.selections;
27002 * Get the indexes of the selected nodes.
27005 getSelectedIndexes : function(){
27006 var indexes = [], s = this.selections;
27007 for(var i = 0, len = s.length; i < len; i++){
27008 indexes.push(s[i].nodeIndex);
27014 * Clear all selections
27015 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27017 clearSelections : function(suppressEvent){
27018 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27019 this.cmp.elements = this.selections;
27020 this.cmp.removeClass(this.selectedClass);
27021 this.selections = [];
27022 if(!suppressEvent){
27023 this.fireEvent("selectionchange", this, this.selections);
27029 * Returns true if the passed node is selected
27030 * @param {HTMLElement/Number} node The node or node index
27031 * @return {Boolean}
27033 isSelected : function(node){
27034 var s = this.selections;
27038 node = this.getNode(node);
27039 return s.indexOf(node) !== -1;
27044 * @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
27045 * @param {Boolean} keepExisting (optional) true to keep existing selections
27046 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27048 select : function(nodeInfo, keepExisting, suppressEvent){
27049 if(nodeInfo instanceof Array){
27051 this.clearSelections(true);
27053 for(var i = 0, len = nodeInfo.length; i < len; i++){
27054 this.select(nodeInfo[i], true, true);
27058 var node = this.getNode(nodeInfo);
27059 if(!node || this.isSelected(node)){
27060 return; // already selected.
27063 this.clearSelections(true);
27066 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27067 Roo.fly(node).addClass(this.selectedClass);
27068 this.selections.push(node);
27069 if(!suppressEvent){
27070 this.fireEvent("selectionchange", this, this.selections);
27078 * @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
27079 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27080 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27082 unselect : function(nodeInfo, keepExisting, suppressEvent)
27084 if(nodeInfo instanceof Array){
27085 Roo.each(this.selections, function(s) {
27086 this.unselect(s, nodeInfo);
27090 var node = this.getNode(nodeInfo);
27091 if(!node || !this.isSelected(node)){
27092 //Roo.log("not selected");
27093 return; // not selected.
27097 Roo.each(this.selections, function(s) {
27099 Roo.fly(node).removeClass(this.selectedClass);
27106 this.selections= ns;
27107 this.fireEvent("selectionchange", this, this.selections);
27111 * Gets a template node.
27112 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27113 * @return {HTMLElement} The node or null if it wasn't found
27115 getNode : function(nodeInfo){
27116 if(typeof nodeInfo == "string"){
27117 return document.getElementById(nodeInfo);
27118 }else if(typeof nodeInfo == "number"){
27119 return this.nodes[nodeInfo];
27125 * Gets a range template nodes.
27126 * @param {Number} startIndex
27127 * @param {Number} endIndex
27128 * @return {Array} An array of nodes
27130 getNodes : function(start, end){
27131 var ns = this.nodes;
27132 start = start || 0;
27133 end = typeof end == "undefined" ? ns.length - 1 : end;
27136 for(var i = start; i <= end; i++){
27140 for(var i = start; i >= end; i--){
27148 * Finds the index of the passed node
27149 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27150 * @return {Number} The index of the node or -1
27152 indexOf : function(node){
27153 node = this.getNode(node);
27154 if(typeof node.nodeIndex == "number"){
27155 return node.nodeIndex;
27157 var ns = this.nodes;
27158 for(var i = 0, len = ns.length; i < len; i++){
27168 * Ext JS Library 1.1.1
27169 * Copyright(c) 2006-2007, Ext JS, LLC.
27171 * Originally Released Under LGPL - original licence link has changed is not relivant.
27174 * <script type="text/javascript">
27178 * @class Roo.JsonView
27179 * @extends Roo.View
27180 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27182 var view = new Roo.JsonView({
27183 container: "my-element",
27184 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27189 // listen for node click?
27190 view.on("click", function(vw, index, node, e){
27191 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27194 // direct load of JSON data
27195 view.load("foobar.php");
27197 // Example from my blog list
27198 var tpl = new Roo.Template(
27199 '<div class="entry">' +
27200 '<a class="entry-title" href="{link}">{title}</a>' +
27201 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27202 "</div><hr />"
27205 var moreView = new Roo.JsonView({
27206 container : "entry-list",
27210 moreView.on("beforerender", this.sortEntries, this);
27212 url: "/blog/get-posts.php",
27213 params: "allposts=true",
27214 text: "Loading Blog Entries..."
27218 * Note: old code is supported with arguments : (container, template, config)
27222 * Create a new JsonView
27224 * @param {Object} config The config object
27227 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27230 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27232 var um = this.el.getUpdateManager();
27233 um.setRenderer(this);
27234 um.on("update", this.onLoad, this);
27235 um.on("failure", this.onLoadException, this);
27238 * @event beforerender
27239 * Fires before rendering of the downloaded JSON data.
27240 * @param {Roo.JsonView} this
27241 * @param {Object} data The JSON data loaded
27245 * Fires when data is loaded.
27246 * @param {Roo.JsonView} this
27247 * @param {Object} data The JSON data loaded
27248 * @param {Object} response The raw Connect response object
27251 * @event loadexception
27252 * Fires when loading fails.
27253 * @param {Roo.JsonView} this
27254 * @param {Object} response The raw Connect response object
27257 'beforerender' : true,
27259 'loadexception' : true
27262 Roo.extend(Roo.JsonView, Roo.View, {
27264 * @type {String} The root property in the loaded JSON object that contains the data
27269 * Refreshes the view.
27271 refresh : function(){
27272 this.clearSelections();
27273 this.el.update("");
27275 var o = this.jsonData;
27276 if(o && o.length > 0){
27277 for(var i = 0, len = o.length; i < len; i++){
27278 var data = this.prepareData(o[i], i, o);
27279 html[html.length] = this.tpl.apply(data);
27282 html.push(this.emptyText);
27284 this.el.update(html.join(""));
27285 this.nodes = this.el.dom.childNodes;
27286 this.updateIndexes(0);
27290 * 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.
27291 * @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:
27294 url: "your-url.php",
27295 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27296 callback: yourFunction,
27297 scope: yourObject, //(optional scope)
27300 text: "Loading...",
27305 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27306 * 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.
27307 * @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}
27308 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27309 * @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.
27312 var um = this.el.getUpdateManager();
27313 um.update.apply(um, arguments);
27316 // note - render is a standard framework call...
27317 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27318 render : function(el, response){
27320 this.clearSelections();
27321 this.el.update("");
27324 if (response != '') {
27325 o = Roo.util.JSON.decode(response.responseText);
27328 o = o[this.jsonRoot];
27334 * The current JSON data or null
27337 this.beforeRender();
27342 * Get the number of records in the current JSON dataset
27345 getCount : function(){
27346 return this.jsonData ? this.jsonData.length : 0;
27350 * Returns the JSON object for the specified node(s)
27351 * @param {HTMLElement/Array} node The node or an array of nodes
27352 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27353 * you get the JSON object for the node
27355 getNodeData : function(node){
27356 if(node instanceof Array){
27358 for(var i = 0, len = node.length; i < len; i++){
27359 data.push(this.getNodeData(node[i]));
27363 return this.jsonData[this.indexOf(node)] || null;
27366 beforeRender : function(){
27367 this.snapshot = this.jsonData;
27369 this.sort.apply(this, this.sortInfo);
27371 this.fireEvent("beforerender", this, this.jsonData);
27374 onLoad : function(el, o){
27375 this.fireEvent("load", this, this.jsonData, o);
27378 onLoadException : function(el, o){
27379 this.fireEvent("loadexception", this, o);
27383 * Filter the data by a specific property.
27384 * @param {String} property A property on your JSON objects
27385 * @param {String/RegExp} value Either string that the property values
27386 * should start with, or a RegExp to test against the property
27388 filter : function(property, value){
27391 var ss = this.snapshot;
27392 if(typeof value == "string"){
27393 var vlen = value.length;
27395 this.clearFilter();
27398 value = value.toLowerCase();
27399 for(var i = 0, len = ss.length; i < len; i++){
27401 if(o[property].substr(0, vlen).toLowerCase() == value){
27405 } else if(value.exec){ // regex?
27406 for(var i = 0, len = ss.length; i < len; i++){
27408 if(value.test(o[property])){
27415 this.jsonData = data;
27421 * Filter by a function. The passed function will be called with each
27422 * object in the current dataset. If the function returns true the value is kept,
27423 * otherwise it is filtered.
27424 * @param {Function} fn
27425 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27427 filterBy : function(fn, scope){
27430 var ss = this.snapshot;
27431 for(var i = 0, len = ss.length; i < len; i++){
27433 if(fn.call(scope || this, o)){
27437 this.jsonData = data;
27443 * Clears the current filter.
27445 clearFilter : function(){
27446 if(this.snapshot && this.jsonData != this.snapshot){
27447 this.jsonData = this.snapshot;
27454 * Sorts the data for this view and refreshes it.
27455 * @param {String} property A property on your JSON objects to sort on
27456 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27457 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27459 sort : function(property, dir, sortType){
27460 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27463 var dsc = dir && dir.toLowerCase() == "desc";
27464 var f = function(o1, o2){
27465 var v1 = sortType ? sortType(o1[p]) : o1[p];
27466 var v2 = sortType ? sortType(o2[p]) : o2[p];
27469 return dsc ? +1 : -1;
27470 } else if(v1 > v2){
27471 return dsc ? -1 : +1;
27476 this.jsonData.sort(f);
27478 if(this.jsonData != this.snapshot){
27479 this.snapshot.sort(f);
27485 * Ext JS Library 1.1.1
27486 * Copyright(c) 2006-2007, Ext JS, LLC.
27488 * Originally Released Under LGPL - original licence link has changed is not relivant.
27491 * <script type="text/javascript">
27496 * @class Roo.ColorPalette
27497 * @extends Roo.Component
27498 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27499 * Here's an example of typical usage:
27501 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27502 cp.render('my-div');
27504 cp.on('select', function(palette, selColor){
27505 // do something with selColor
27509 * Create a new ColorPalette
27510 * @param {Object} config The config object
27512 Roo.ColorPalette = function(config){
27513 Roo.ColorPalette.superclass.constructor.call(this, config);
27517 * Fires when a color is selected
27518 * @param {ColorPalette} this
27519 * @param {String} color The 6-digit color hex code (without the # symbol)
27525 this.on("select", this.handler, this.scope, true);
27528 Roo.extend(Roo.ColorPalette, Roo.Component, {
27530 * @cfg {String} itemCls
27531 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27533 itemCls : "x-color-palette",
27535 * @cfg {String} value
27536 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27537 * the hex codes are case-sensitive.
27540 clickEvent:'click',
27542 ctype: "Roo.ColorPalette",
27545 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27547 allowReselect : false,
27550 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27551 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27552 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27553 * of colors with the width setting until the box is symmetrical.</p>
27554 * <p>You can override individual colors if needed:</p>
27556 var cp = new Roo.ColorPalette();
27557 cp.colors[0] = "FF0000"; // change the first box to red
27560 Or you can provide a custom array of your own for complete control:
27562 var cp = new Roo.ColorPalette();
27563 cp.colors = ["000000", "993300", "333300"];
27568 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27569 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27570 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27571 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27572 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27576 onRender : function(container, position){
27577 var t = new Roo.MasterTemplate(
27578 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27580 var c = this.colors;
27581 for(var i = 0, len = c.length; i < len; i++){
27584 var el = document.createElement("div");
27585 el.className = this.itemCls;
27587 container.dom.insertBefore(el, position);
27588 this.el = Roo.get(el);
27589 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27590 if(this.clickEvent != 'click'){
27591 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27596 afterRender : function(){
27597 Roo.ColorPalette.superclass.afterRender.call(this);
27599 var s = this.value;
27606 handleClick : function(e, t){
27607 e.preventDefault();
27608 if(!this.disabled){
27609 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27610 this.select(c.toUpperCase());
27615 * Selects the specified color in the palette (fires the select event)
27616 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27618 select : function(color){
27619 color = color.replace("#", "");
27620 if(color != this.value || this.allowReselect){
27623 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27625 el.child("a.color-"+color).addClass("x-color-palette-sel");
27626 this.value = color;
27627 this.fireEvent("select", this, color);
27632 * Ext JS Library 1.1.1
27633 * Copyright(c) 2006-2007, Ext JS, LLC.
27635 * Originally Released Under LGPL - original licence link has changed is not relivant.
27638 * <script type="text/javascript">
27642 * @class Roo.DatePicker
27643 * @extends Roo.Component
27644 * Simple date picker class.
27646 * Create a new DatePicker
27647 * @param {Object} config The config object
27649 Roo.DatePicker = function(config){
27650 Roo.DatePicker.superclass.constructor.call(this, config);
27652 this.value = config && config.value ?
27653 config.value.clearTime() : new Date().clearTime();
27658 * Fires when a date is selected
27659 * @param {DatePicker} this
27660 * @param {Date} date The selected date
27664 * @event monthchange
27665 * Fires when the displayed month changes
27666 * @param {DatePicker} this
27667 * @param {Date} date The selected month
27669 'monthchange': true
27673 this.on("select", this.handler, this.scope || this);
27675 // build the disabledDatesRE
27676 if(!this.disabledDatesRE && this.disabledDates){
27677 var dd = this.disabledDates;
27679 for(var i = 0; i < dd.length; i++){
27681 if(i != dd.length-1) {
27685 this.disabledDatesRE = new RegExp(re + ")");
27689 Roo.extend(Roo.DatePicker, Roo.Component, {
27691 * @cfg {String} todayText
27692 * The text to display on the button that selects the current date (defaults to "Today")
27694 todayText : "Today",
27696 * @cfg {String} okText
27697 * The text to display on the ok button
27699 okText : " OK ", //   to give the user extra clicking room
27701 * @cfg {String} cancelText
27702 * The text to display on the cancel button
27704 cancelText : "Cancel",
27706 * @cfg {String} todayTip
27707 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27709 todayTip : "{0} (Spacebar)",
27711 * @cfg {Date} minDate
27712 * Minimum allowable date (JavaScript date object, defaults to null)
27716 * @cfg {Date} maxDate
27717 * Maximum allowable date (JavaScript date object, defaults to null)
27721 * @cfg {String} minText
27722 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27724 minText : "This date is before the minimum date",
27726 * @cfg {String} maxText
27727 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27729 maxText : "This date is after the maximum date",
27731 * @cfg {String} format
27732 * The default date format string which can be overriden for localization support. The format must be
27733 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27737 * @cfg {Array} disabledDays
27738 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27740 disabledDays : null,
27742 * @cfg {String} disabledDaysText
27743 * The tooltip to display when the date falls on a disabled day (defaults to "")
27745 disabledDaysText : "",
27747 * @cfg {RegExp} disabledDatesRE
27748 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27750 disabledDatesRE : null,
27752 * @cfg {String} disabledDatesText
27753 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27755 disabledDatesText : "",
27757 * @cfg {Boolean} constrainToViewport
27758 * True to constrain the date picker to the viewport (defaults to true)
27760 constrainToViewport : true,
27762 * @cfg {Array} monthNames
27763 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27765 monthNames : Date.monthNames,
27767 * @cfg {Array} dayNames
27768 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27770 dayNames : Date.dayNames,
27772 * @cfg {String} nextText
27773 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27775 nextText: 'Next Month (Control+Right)',
27777 * @cfg {String} prevText
27778 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27780 prevText: 'Previous Month (Control+Left)',
27782 * @cfg {String} monthYearText
27783 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27785 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27787 * @cfg {Number} startDay
27788 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27792 * @cfg {Bool} showClear
27793 * Show a clear button (usefull for date form elements that can be blank.)
27799 * Sets the value of the date field
27800 * @param {Date} value The date to set
27802 setValue : function(value){
27803 var old = this.value;
27805 if (typeof(value) == 'string') {
27807 value = Date.parseDate(value, this.format);
27810 value = new Date();
27813 this.value = value.clearTime(true);
27815 this.update(this.value);
27820 * Gets the current selected value of the date field
27821 * @return {Date} The selected date
27823 getValue : function(){
27828 focus : function(){
27830 this.update(this.activeDate);
27835 onRender : function(container, position){
27838 '<table cellspacing="0">',
27839 '<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>',
27840 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27841 var dn = this.dayNames;
27842 for(var i = 0; i < 7; i++){
27843 var d = this.startDay+i;
27847 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27849 m[m.length] = "</tr></thead><tbody><tr>";
27850 for(var i = 0; i < 42; i++) {
27851 if(i % 7 == 0 && i != 0){
27852 m[m.length] = "</tr><tr>";
27854 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27856 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27857 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27859 var el = document.createElement("div");
27860 el.className = "x-date-picker";
27861 el.innerHTML = m.join("");
27863 container.dom.insertBefore(el, position);
27865 this.el = Roo.get(el);
27866 this.eventEl = Roo.get(el.firstChild);
27868 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27869 handler: this.showPrevMonth,
27871 preventDefault:true,
27875 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27876 handler: this.showNextMonth,
27878 preventDefault:true,
27882 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27884 this.monthPicker = this.el.down('div.x-date-mp');
27885 this.monthPicker.enableDisplayMode('block');
27887 var kn = new Roo.KeyNav(this.eventEl, {
27888 "left" : function(e){
27890 this.showPrevMonth() :
27891 this.update(this.activeDate.add("d", -1));
27894 "right" : function(e){
27896 this.showNextMonth() :
27897 this.update(this.activeDate.add("d", 1));
27900 "up" : function(e){
27902 this.showNextYear() :
27903 this.update(this.activeDate.add("d", -7));
27906 "down" : function(e){
27908 this.showPrevYear() :
27909 this.update(this.activeDate.add("d", 7));
27912 "pageUp" : function(e){
27913 this.showNextMonth();
27916 "pageDown" : function(e){
27917 this.showPrevMonth();
27920 "enter" : function(e){
27921 e.stopPropagation();
27928 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27930 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27932 this.el.unselectable();
27934 this.cells = this.el.select("table.x-date-inner tbody td");
27935 this.textNodes = this.el.query("table.x-date-inner tbody span");
27937 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27939 tooltip: this.monthYearText
27942 this.mbtn.on('click', this.showMonthPicker, this);
27943 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27946 var today = (new Date()).dateFormat(this.format);
27948 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27949 if (this.showClear) {
27950 baseTb.add( new Roo.Toolbar.Fill());
27953 text: String.format(this.todayText, today),
27954 tooltip: String.format(this.todayTip, today),
27955 handler: this.selectToday,
27959 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27962 if (this.showClear) {
27964 baseTb.add( new Roo.Toolbar.Fill());
27967 cls: 'x-btn-icon x-btn-clear',
27968 handler: function() {
27970 this.fireEvent("select", this, '');
27980 this.update(this.value);
27983 createMonthPicker : function(){
27984 if(!this.monthPicker.dom.firstChild){
27985 var buf = ['<table border="0" cellspacing="0">'];
27986 for(var i = 0; i < 6; i++){
27988 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27989 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27991 '<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>' :
27992 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27996 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27998 '</button><button type="button" class="x-date-mp-cancel">',
28000 '</button></td></tr>',
28003 this.monthPicker.update(buf.join(''));
28004 this.monthPicker.on('click', this.onMonthClick, this);
28005 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28007 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28008 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28010 this.mpMonths.each(function(m, a, i){
28013 m.dom.xmonth = 5 + Math.round(i * .5);
28015 m.dom.xmonth = Math.round((i-1) * .5);
28021 showMonthPicker : function(){
28022 this.createMonthPicker();
28023 var size = this.el.getSize();
28024 this.monthPicker.setSize(size);
28025 this.monthPicker.child('table').setSize(size);
28027 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28028 this.updateMPMonth(this.mpSelMonth);
28029 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28030 this.updateMPYear(this.mpSelYear);
28032 this.monthPicker.slideIn('t', {duration:.2});
28035 updateMPYear : function(y){
28037 var ys = this.mpYears.elements;
28038 for(var i = 1; i <= 10; i++){
28039 var td = ys[i-1], y2;
28041 y2 = y + Math.round(i * .5);
28042 td.firstChild.innerHTML = y2;
28045 y2 = y - (5-Math.round(i * .5));
28046 td.firstChild.innerHTML = y2;
28049 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28053 updateMPMonth : function(sm){
28054 this.mpMonths.each(function(m, a, i){
28055 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28059 selectMPMonth: function(m){
28063 onMonthClick : function(e, t){
28065 var el = new Roo.Element(t), pn;
28066 if(el.is('button.x-date-mp-cancel')){
28067 this.hideMonthPicker();
28069 else if(el.is('button.x-date-mp-ok')){
28070 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28071 this.hideMonthPicker();
28073 else if(pn = el.up('td.x-date-mp-month', 2)){
28074 this.mpMonths.removeClass('x-date-mp-sel');
28075 pn.addClass('x-date-mp-sel');
28076 this.mpSelMonth = pn.dom.xmonth;
28078 else if(pn = el.up('td.x-date-mp-year', 2)){
28079 this.mpYears.removeClass('x-date-mp-sel');
28080 pn.addClass('x-date-mp-sel');
28081 this.mpSelYear = pn.dom.xyear;
28083 else if(el.is('a.x-date-mp-prev')){
28084 this.updateMPYear(this.mpyear-10);
28086 else if(el.is('a.x-date-mp-next')){
28087 this.updateMPYear(this.mpyear+10);
28091 onMonthDblClick : function(e, t){
28093 var el = new Roo.Element(t), pn;
28094 if(pn = el.up('td.x-date-mp-month', 2)){
28095 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28096 this.hideMonthPicker();
28098 else if(pn = el.up('td.x-date-mp-year', 2)){
28099 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28100 this.hideMonthPicker();
28104 hideMonthPicker : function(disableAnim){
28105 if(this.monthPicker){
28106 if(disableAnim === true){
28107 this.monthPicker.hide();
28109 this.monthPicker.slideOut('t', {duration:.2});
28115 showPrevMonth : function(e){
28116 this.update(this.activeDate.add("mo", -1));
28120 showNextMonth : function(e){
28121 this.update(this.activeDate.add("mo", 1));
28125 showPrevYear : function(){
28126 this.update(this.activeDate.add("y", -1));
28130 showNextYear : function(){
28131 this.update(this.activeDate.add("y", 1));
28135 handleMouseWheel : function(e){
28136 var delta = e.getWheelDelta();
28138 this.showPrevMonth();
28140 } else if(delta < 0){
28141 this.showNextMonth();
28147 handleDateClick : function(e, t){
28149 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28150 this.setValue(new Date(t.dateValue));
28151 this.fireEvent("select", this, this.value);
28156 selectToday : function(){
28157 this.setValue(new Date().clearTime());
28158 this.fireEvent("select", this, this.value);
28162 update : function(date)
28164 var vd = this.activeDate;
28165 this.activeDate = date;
28167 var t = date.getTime();
28168 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28169 this.cells.removeClass("x-date-selected");
28170 this.cells.each(function(c){
28171 if(c.dom.firstChild.dateValue == t){
28172 c.addClass("x-date-selected");
28173 setTimeout(function(){
28174 try{c.dom.firstChild.focus();}catch(e){}
28183 var days = date.getDaysInMonth();
28184 var firstOfMonth = date.getFirstDateOfMonth();
28185 var startingPos = firstOfMonth.getDay()-this.startDay;
28187 if(startingPos <= this.startDay){
28191 var pm = date.add("mo", -1);
28192 var prevStart = pm.getDaysInMonth()-startingPos;
28194 var cells = this.cells.elements;
28195 var textEls = this.textNodes;
28196 days += startingPos;
28198 // convert everything to numbers so it's fast
28199 var day = 86400000;
28200 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28201 var today = new Date().clearTime().getTime();
28202 var sel = date.clearTime().getTime();
28203 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28204 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28205 var ddMatch = this.disabledDatesRE;
28206 var ddText = this.disabledDatesText;
28207 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28208 var ddaysText = this.disabledDaysText;
28209 var format = this.format;
28211 var setCellClass = function(cal, cell){
28213 var t = d.getTime();
28214 cell.firstChild.dateValue = t;
28216 cell.className += " x-date-today";
28217 cell.title = cal.todayText;
28220 cell.className += " x-date-selected";
28221 setTimeout(function(){
28222 try{cell.firstChild.focus();}catch(e){}
28227 cell.className = " x-date-disabled";
28228 cell.title = cal.minText;
28232 cell.className = " x-date-disabled";
28233 cell.title = cal.maxText;
28237 if(ddays.indexOf(d.getDay()) != -1){
28238 cell.title = ddaysText;
28239 cell.className = " x-date-disabled";
28242 if(ddMatch && format){
28243 var fvalue = d.dateFormat(format);
28244 if(ddMatch.test(fvalue)){
28245 cell.title = ddText.replace("%0", fvalue);
28246 cell.className = " x-date-disabled";
28252 for(; i < startingPos; i++) {
28253 textEls[i].innerHTML = (++prevStart);
28254 d.setDate(d.getDate()+1);
28255 cells[i].className = "x-date-prevday";
28256 setCellClass(this, cells[i]);
28258 for(; i < days; i++){
28259 intDay = i - startingPos + 1;
28260 textEls[i].innerHTML = (intDay);
28261 d.setDate(d.getDate()+1);
28262 cells[i].className = "x-date-active";
28263 setCellClass(this, cells[i]);
28266 for(; i < 42; i++) {
28267 textEls[i].innerHTML = (++extraDays);
28268 d.setDate(d.getDate()+1);
28269 cells[i].className = "x-date-nextday";
28270 setCellClass(this, cells[i]);
28273 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28274 this.fireEvent('monthchange', this, date);
28276 if(!this.internalRender){
28277 var main = this.el.dom.firstChild;
28278 var w = main.offsetWidth;
28279 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28280 Roo.fly(main).setWidth(w);
28281 this.internalRender = true;
28282 // opera does not respect the auto grow header center column
28283 // then, after it gets a width opera refuses to recalculate
28284 // without a second pass
28285 if(Roo.isOpera && !this.secondPass){
28286 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28287 this.secondPass = true;
28288 this.update.defer(10, this, [date]);
28296 * Ext JS Library 1.1.1
28297 * Copyright(c) 2006-2007, Ext JS, LLC.
28299 * Originally Released Under LGPL - original licence link has changed is not relivant.
28302 * <script type="text/javascript">
28305 * @class Roo.TabPanel
28306 * @extends Roo.util.Observable
28307 * A lightweight tab container.
28311 // basic tabs 1, built from existing content
28312 var tabs = new Roo.TabPanel("tabs1");
28313 tabs.addTab("script", "View Script");
28314 tabs.addTab("markup", "View Markup");
28315 tabs.activate("script");
28317 // more advanced tabs, built from javascript
28318 var jtabs = new Roo.TabPanel("jtabs");
28319 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28321 // set up the UpdateManager
28322 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28323 var updater = tab2.getUpdateManager();
28324 updater.setDefaultUrl("ajax1.htm");
28325 tab2.on('activate', updater.refresh, updater, true);
28327 // Use setUrl for Ajax loading
28328 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28329 tab3.setUrl("ajax2.htm", null, true);
28332 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28335 jtabs.activate("jtabs-1");
28338 * Create a new TabPanel.
28339 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28340 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28342 Roo.TabPanel = function(container, config){
28344 * The container element for this TabPanel.
28345 * @type Roo.Element
28347 this.el = Roo.get(container, true);
28349 if(typeof config == "boolean"){
28350 this.tabPosition = config ? "bottom" : "top";
28352 Roo.apply(this, config);
28355 if(this.tabPosition == "bottom"){
28356 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28357 this.el.addClass("x-tabs-bottom");
28359 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28360 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28361 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28363 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28365 if(this.tabPosition != "bottom"){
28366 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28367 * @type Roo.Element
28369 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28370 this.el.addClass("x-tabs-top");
28374 this.bodyEl.setStyle("position", "relative");
28376 this.active = null;
28377 this.activateDelegate = this.activate.createDelegate(this);
28382 * Fires when the active tab changes
28383 * @param {Roo.TabPanel} this
28384 * @param {Roo.TabPanelItem} activePanel The new active tab
28388 * @event beforetabchange
28389 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28390 * @param {Roo.TabPanel} this
28391 * @param {Object} e Set cancel to true on this object to cancel the tab change
28392 * @param {Roo.TabPanelItem} tab The tab being changed to
28394 "beforetabchange" : true
28397 Roo.EventManager.onWindowResize(this.onResize, this);
28398 this.cpad = this.el.getPadding("lr");
28399 this.hiddenCount = 0;
28402 // toolbar on the tabbar support...
28403 if (this.toolbar) {
28404 var tcfg = this.toolbar;
28405 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28406 this.toolbar = new Roo.Toolbar(tcfg);
28407 if (Roo.isSafari) {
28408 var tbl = tcfg.container.child('table', true);
28409 tbl.setAttribute('width', '100%');
28416 Roo.TabPanel.superclass.constructor.call(this);
28419 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28421 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28423 tabPosition : "top",
28425 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28427 currentTabWidth : 0,
28429 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28433 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28437 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28439 preferredTabWidth : 175,
28441 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28443 resizeTabs : false,
28445 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28447 monitorResize : true,
28449 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28454 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28455 * @param {String} id The id of the div to use <b>or create</b>
28456 * @param {String} text The text for the tab
28457 * @param {String} content (optional) Content to put in the TabPanelItem body
28458 * @param {Boolean} closable (optional) True to create a close icon on the tab
28459 * @return {Roo.TabPanelItem} The created TabPanelItem
28461 addTab : function(id, text, content, closable){
28462 var item = new Roo.TabPanelItem(this, id, text, closable);
28463 this.addTabItem(item);
28465 item.setContent(content);
28471 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28472 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28473 * @return {Roo.TabPanelItem}
28475 getTab : function(id){
28476 return this.items[id];
28480 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28481 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28483 hideTab : function(id){
28484 var t = this.items[id];
28487 this.hiddenCount++;
28488 this.autoSizeTabs();
28493 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28494 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28496 unhideTab : function(id){
28497 var t = this.items[id];
28499 t.setHidden(false);
28500 this.hiddenCount--;
28501 this.autoSizeTabs();
28506 * Adds an existing {@link Roo.TabPanelItem}.
28507 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28509 addTabItem : function(item){
28510 this.items[item.id] = item;
28511 this.items.push(item);
28512 if(this.resizeTabs){
28513 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28514 this.autoSizeTabs();
28521 * Removes a {@link Roo.TabPanelItem}.
28522 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28524 removeTab : function(id){
28525 var items = this.items;
28526 var tab = items[id];
28527 if(!tab) { return; }
28528 var index = items.indexOf(tab);
28529 if(this.active == tab && items.length > 1){
28530 var newTab = this.getNextAvailable(index);
28535 this.stripEl.dom.removeChild(tab.pnode.dom);
28536 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28537 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28539 items.splice(index, 1);
28540 delete this.items[tab.id];
28541 tab.fireEvent("close", tab);
28542 tab.purgeListeners();
28543 this.autoSizeTabs();
28546 getNextAvailable : function(start){
28547 var items = this.items;
28549 // look for a next tab that will slide over to
28550 // replace the one being removed
28551 while(index < items.length){
28552 var item = items[++index];
28553 if(item && !item.isHidden()){
28557 // if one isn't found select the previous tab (on the left)
28560 var item = items[--index];
28561 if(item && !item.isHidden()){
28569 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28570 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28572 disableTab : function(id){
28573 var tab = this.items[id];
28574 if(tab && this.active != tab){
28580 * Enables a {@link Roo.TabPanelItem} that is disabled.
28581 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28583 enableTab : function(id){
28584 var tab = this.items[id];
28589 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28590 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28591 * @return {Roo.TabPanelItem} The TabPanelItem.
28593 activate : function(id){
28594 var tab = this.items[id];
28598 if(tab == this.active || tab.disabled){
28602 this.fireEvent("beforetabchange", this, e, tab);
28603 if(e.cancel !== true && !tab.disabled){
28605 this.active.hide();
28607 this.active = this.items[id];
28608 this.active.show();
28609 this.fireEvent("tabchange", this, this.active);
28615 * Gets the active {@link Roo.TabPanelItem}.
28616 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28618 getActiveTab : function(){
28619 return this.active;
28623 * Updates the tab body element to fit the height of the container element
28624 * for overflow scrolling
28625 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28627 syncHeight : function(targetHeight){
28628 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28629 var bm = this.bodyEl.getMargins();
28630 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28631 this.bodyEl.setHeight(newHeight);
28635 onResize : function(){
28636 if(this.monitorResize){
28637 this.autoSizeTabs();
28642 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28644 beginUpdate : function(){
28645 this.updating = true;
28649 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28651 endUpdate : function(){
28652 this.updating = false;
28653 this.autoSizeTabs();
28657 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28659 autoSizeTabs : function(){
28660 var count = this.items.length;
28661 var vcount = count - this.hiddenCount;
28662 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28665 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28666 var availWidth = Math.floor(w / vcount);
28667 var b = this.stripBody;
28668 if(b.getWidth() > w){
28669 var tabs = this.items;
28670 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28671 if(availWidth < this.minTabWidth){
28672 /*if(!this.sleft){ // incomplete scrolling code
28673 this.createScrollButtons();
28676 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28679 if(this.currentTabWidth < this.preferredTabWidth){
28680 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28686 * Returns the number of tabs in this TabPanel.
28689 getCount : function(){
28690 return this.items.length;
28694 * Resizes all the tabs to the passed width
28695 * @param {Number} The new width
28697 setTabWidth : function(width){
28698 this.currentTabWidth = width;
28699 for(var i = 0, len = this.items.length; i < len; i++) {
28700 if(!this.items[i].isHidden()) {
28701 this.items[i].setWidth(width);
28707 * Destroys this TabPanel
28708 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28710 destroy : function(removeEl){
28711 Roo.EventManager.removeResizeListener(this.onResize, this);
28712 for(var i = 0, len = this.items.length; i < len; i++){
28713 this.items[i].purgeListeners();
28715 if(removeEl === true){
28716 this.el.update("");
28723 * @class Roo.TabPanelItem
28724 * @extends Roo.util.Observable
28725 * Represents an individual item (tab plus body) in a TabPanel.
28726 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28727 * @param {String} id The id of this TabPanelItem
28728 * @param {String} text The text for the tab of this TabPanelItem
28729 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28731 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28733 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28734 * @type Roo.TabPanel
28736 this.tabPanel = tabPanel;
28738 * The id for this TabPanelItem
28743 this.disabled = false;
28747 this.loaded = false;
28748 this.closable = closable;
28751 * The body element for this TabPanelItem.
28752 * @type Roo.Element
28754 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28755 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28756 this.bodyEl.setStyle("display", "block");
28757 this.bodyEl.setStyle("zoom", "1");
28760 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28762 this.el = Roo.get(els.el, true);
28763 this.inner = Roo.get(els.inner, true);
28764 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28765 this.pnode = Roo.get(els.el.parentNode, true);
28766 this.el.on("mousedown", this.onTabMouseDown, this);
28767 this.el.on("click", this.onTabClick, this);
28770 var c = Roo.get(els.close, true);
28771 c.dom.title = this.closeText;
28772 c.addClassOnOver("close-over");
28773 c.on("click", this.closeClick, this);
28779 * Fires when this tab becomes the active tab.
28780 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28781 * @param {Roo.TabPanelItem} this
28785 * @event beforeclose
28786 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28787 * @param {Roo.TabPanelItem} this
28788 * @param {Object} e Set cancel to true on this object to cancel the close.
28790 "beforeclose": true,
28793 * Fires when this tab is closed.
28794 * @param {Roo.TabPanelItem} this
28798 * @event deactivate
28799 * Fires when this tab is no longer the active tab.
28800 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28801 * @param {Roo.TabPanelItem} this
28803 "deactivate" : true
28805 this.hidden = false;
28807 Roo.TabPanelItem.superclass.constructor.call(this);
28810 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28811 purgeListeners : function(){
28812 Roo.util.Observable.prototype.purgeListeners.call(this);
28813 this.el.removeAllListeners();
28816 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28819 this.pnode.addClass("on");
28822 this.tabPanel.stripWrap.repaint();
28824 this.fireEvent("activate", this.tabPanel, this);
28828 * Returns true if this tab is the active tab.
28829 * @return {Boolean}
28831 isActive : function(){
28832 return this.tabPanel.getActiveTab() == this;
28836 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28839 this.pnode.removeClass("on");
28841 this.fireEvent("deactivate", this.tabPanel, this);
28844 hideAction : function(){
28845 this.bodyEl.hide();
28846 this.bodyEl.setStyle("position", "absolute");
28847 this.bodyEl.setLeft("-20000px");
28848 this.bodyEl.setTop("-20000px");
28851 showAction : function(){
28852 this.bodyEl.setStyle("position", "relative");
28853 this.bodyEl.setTop("");
28854 this.bodyEl.setLeft("");
28855 this.bodyEl.show();
28859 * Set the tooltip for the tab.
28860 * @param {String} tooltip The tab's tooltip
28862 setTooltip : function(text){
28863 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28864 this.textEl.dom.qtip = text;
28865 this.textEl.dom.removeAttribute('title');
28867 this.textEl.dom.title = text;
28871 onTabClick : function(e){
28872 e.preventDefault();
28873 this.tabPanel.activate(this.id);
28876 onTabMouseDown : function(e){
28877 e.preventDefault();
28878 this.tabPanel.activate(this.id);
28881 getWidth : function(){
28882 return this.inner.getWidth();
28885 setWidth : function(width){
28886 var iwidth = width - this.pnode.getPadding("lr");
28887 this.inner.setWidth(iwidth);
28888 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28889 this.pnode.setWidth(width);
28893 * Show or hide the tab
28894 * @param {Boolean} hidden True to hide or false to show.
28896 setHidden : function(hidden){
28897 this.hidden = hidden;
28898 this.pnode.setStyle("display", hidden ? "none" : "");
28902 * Returns true if this tab is "hidden"
28903 * @return {Boolean}
28905 isHidden : function(){
28906 return this.hidden;
28910 * Returns the text for this tab
28913 getText : function(){
28917 autoSize : function(){
28918 //this.el.beginMeasure();
28919 this.textEl.setWidth(1);
28921 * #2804 [new] Tabs in Roojs
28922 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28924 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28925 //this.el.endMeasure();
28929 * Sets the text for the tab (Note: this also sets the tooltip text)
28930 * @param {String} text The tab's text and tooltip
28932 setText : function(text){
28934 this.textEl.update(text);
28935 this.setTooltip(text);
28936 if(!this.tabPanel.resizeTabs){
28941 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28943 activate : function(){
28944 this.tabPanel.activate(this.id);
28948 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28950 disable : function(){
28951 if(this.tabPanel.active != this){
28952 this.disabled = true;
28953 this.pnode.addClass("disabled");
28958 * Enables this TabPanelItem if it was previously disabled.
28960 enable : function(){
28961 this.disabled = false;
28962 this.pnode.removeClass("disabled");
28966 * Sets the content for this TabPanelItem.
28967 * @param {String} content The content
28968 * @param {Boolean} loadScripts true to look for and load scripts
28970 setContent : function(content, loadScripts){
28971 this.bodyEl.update(content, loadScripts);
28975 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28976 * @return {Roo.UpdateManager} The UpdateManager
28978 getUpdateManager : function(){
28979 return this.bodyEl.getUpdateManager();
28983 * Set a URL to be used to load the content for this TabPanelItem.
28984 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28985 * @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)
28986 * @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)
28987 * @return {Roo.UpdateManager} The UpdateManager
28989 setUrl : function(url, params, loadOnce){
28990 if(this.refreshDelegate){
28991 this.un('activate', this.refreshDelegate);
28993 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28994 this.on("activate", this.refreshDelegate);
28995 return this.bodyEl.getUpdateManager();
28999 _handleRefresh : function(url, params, loadOnce){
29000 if(!loadOnce || !this.loaded){
29001 var updater = this.bodyEl.getUpdateManager();
29002 updater.update(url, params, this._setLoaded.createDelegate(this));
29007 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29008 * Will fail silently if the setUrl method has not been called.
29009 * This does not activate the panel, just updates its content.
29011 refresh : function(){
29012 if(this.refreshDelegate){
29013 this.loaded = false;
29014 this.refreshDelegate();
29019 _setLoaded : function(){
29020 this.loaded = true;
29024 closeClick : function(e){
29027 this.fireEvent("beforeclose", this, o);
29028 if(o.cancel !== true){
29029 this.tabPanel.removeTab(this.id);
29033 * The text displayed in the tooltip for the close icon.
29036 closeText : "Close this tab"
29040 Roo.TabPanel.prototype.createStrip = function(container){
29041 var strip = document.createElement("div");
29042 strip.className = "x-tabs-wrap";
29043 container.appendChild(strip);
29047 Roo.TabPanel.prototype.createStripList = function(strip){
29048 // div wrapper for retard IE
29049 // returns the "tr" element.
29050 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29051 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29052 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29053 return strip.firstChild.firstChild.firstChild.firstChild;
29056 Roo.TabPanel.prototype.createBody = function(container){
29057 var body = document.createElement("div");
29058 Roo.id(body, "tab-body");
29059 Roo.fly(body).addClass("x-tabs-body");
29060 container.appendChild(body);
29064 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29065 var body = Roo.getDom(id);
29067 body = document.createElement("div");
29070 Roo.fly(body).addClass("x-tabs-item-body");
29071 bodyEl.insertBefore(body, bodyEl.firstChild);
29075 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29076 var td = document.createElement("td");
29077 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29078 //stripEl.appendChild(td);
29080 td.className = "x-tabs-closable";
29081 if(!this.closeTpl){
29082 this.closeTpl = new Roo.Template(
29083 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29084 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29085 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29088 var el = this.closeTpl.overwrite(td, {"text": text});
29089 var close = el.getElementsByTagName("div")[0];
29090 var inner = el.getElementsByTagName("em")[0];
29091 return {"el": el, "close": close, "inner": inner};
29094 this.tabTpl = new Roo.Template(
29095 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29096 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29099 var el = this.tabTpl.overwrite(td, {"text": text});
29100 var inner = el.getElementsByTagName("em")[0];
29101 return {"el": el, "inner": inner};
29105 * Ext JS Library 1.1.1
29106 * Copyright(c) 2006-2007, Ext JS, LLC.
29108 * Originally Released Under LGPL - original licence link has changed is not relivant.
29111 * <script type="text/javascript">
29115 * @class Roo.Button
29116 * @extends Roo.util.Observable
29117 * Simple Button class
29118 * @cfg {String} text The button text
29119 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29120 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29121 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29122 * @cfg {Object} scope The scope of the handler
29123 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29124 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29125 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29126 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29127 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29128 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29129 applies if enableToggle = true)
29130 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29131 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29132 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29134 * Create a new button
29135 * @param {Object} config The config object
29137 Roo.Button = function(renderTo, config)
29141 renderTo = config.renderTo || false;
29144 Roo.apply(this, config);
29148 * Fires when this button is clicked
29149 * @param {Button} this
29150 * @param {EventObject} e The click event
29155 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29156 * @param {Button} this
29157 * @param {Boolean} pressed
29162 * Fires when the mouse hovers over the button
29163 * @param {Button} this
29164 * @param {Event} e The event object
29166 'mouseover' : true,
29169 * Fires when the mouse exits the button
29170 * @param {Button} this
29171 * @param {Event} e The event object
29176 * Fires when the button is rendered
29177 * @param {Button} this
29182 this.menu = Roo.menu.MenuMgr.get(this.menu);
29184 // register listeners first!! - so render can be captured..
29185 Roo.util.Observable.call(this);
29187 this.render(renderTo);
29193 Roo.extend(Roo.Button, Roo.util.Observable, {
29199 * Read-only. True if this button is hidden
29204 * Read-only. True if this button is disabled
29209 * Read-only. True if this button is pressed (only if enableToggle = true)
29215 * @cfg {Number} tabIndex
29216 * The DOM tabIndex for this button (defaults to undefined)
29218 tabIndex : undefined,
29221 * @cfg {Boolean} enableToggle
29222 * True to enable pressed/not pressed toggling (defaults to false)
29224 enableToggle: false,
29226 * @cfg {Mixed} menu
29227 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29231 * @cfg {String} menuAlign
29232 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29234 menuAlign : "tl-bl?",
29237 * @cfg {String} iconCls
29238 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29240 iconCls : undefined,
29242 * @cfg {String} type
29243 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29248 menuClassTarget: 'tr',
29251 * @cfg {String} clickEvent
29252 * The type of event to map to the button's event handler (defaults to 'click')
29254 clickEvent : 'click',
29257 * @cfg {Boolean} handleMouseEvents
29258 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29260 handleMouseEvents : true,
29263 * @cfg {String} tooltipType
29264 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29266 tooltipType : 'qtip',
29269 * @cfg {String} cls
29270 * A CSS class to apply to the button's main element.
29274 * @cfg {Roo.Template} template (Optional)
29275 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29276 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29277 * require code modifications if required elements (e.g. a button) aren't present.
29281 render : function(renderTo){
29283 if(this.hideParent){
29284 this.parentEl = Roo.get(renderTo);
29286 if(!this.dhconfig){
29287 if(!this.template){
29288 if(!Roo.Button.buttonTemplate){
29289 // hideous table template
29290 Roo.Button.buttonTemplate = new Roo.Template(
29291 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29292 '<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>',
29293 "</tr></tbody></table>");
29295 this.template = Roo.Button.buttonTemplate;
29297 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29298 var btnEl = btn.child("button:first");
29299 btnEl.on('focus', this.onFocus, this);
29300 btnEl.on('blur', this.onBlur, this);
29302 btn.addClass(this.cls);
29305 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29308 btnEl.addClass(this.iconCls);
29310 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29313 if(this.tabIndex !== undefined){
29314 btnEl.dom.tabIndex = this.tabIndex;
29317 if(typeof this.tooltip == 'object'){
29318 Roo.QuickTips.tips(Roo.apply({
29322 btnEl.dom[this.tooltipType] = this.tooltip;
29326 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29330 this.el.dom.id = this.el.id = this.id;
29333 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29334 this.menu.on("show", this.onMenuShow, this);
29335 this.menu.on("hide", this.onMenuHide, this);
29337 btn.addClass("x-btn");
29338 if(Roo.isIE && !Roo.isIE7){
29339 this.autoWidth.defer(1, this);
29343 if(this.handleMouseEvents){
29344 btn.on("mouseover", this.onMouseOver, this);
29345 btn.on("mouseout", this.onMouseOut, this);
29346 btn.on("mousedown", this.onMouseDown, this);
29348 btn.on(this.clickEvent, this.onClick, this);
29349 //btn.on("mouseup", this.onMouseUp, this);
29356 Roo.ButtonToggleMgr.register(this);
29358 this.el.addClass("x-btn-pressed");
29361 var repeater = new Roo.util.ClickRepeater(btn,
29362 typeof this.repeat == "object" ? this.repeat : {}
29364 repeater.on("click", this.onClick, this);
29367 this.fireEvent('render', this);
29371 * Returns the button's underlying element
29372 * @return {Roo.Element} The element
29374 getEl : function(){
29379 * Destroys this Button and removes any listeners.
29381 destroy : function(){
29382 Roo.ButtonToggleMgr.unregister(this);
29383 this.el.removeAllListeners();
29384 this.purgeListeners();
29389 autoWidth : function(){
29391 this.el.setWidth("auto");
29392 if(Roo.isIE7 && Roo.isStrict){
29393 var ib = this.el.child('button');
29394 if(ib && ib.getWidth() > 20){
29396 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29401 this.el.beginMeasure();
29403 if(this.el.getWidth() < this.minWidth){
29404 this.el.setWidth(this.minWidth);
29407 this.el.endMeasure();
29414 * Assigns this button's click handler
29415 * @param {Function} handler The function to call when the button is clicked
29416 * @param {Object} scope (optional) Scope for the function passed in
29418 setHandler : function(handler, scope){
29419 this.handler = handler;
29420 this.scope = scope;
29424 * Sets this button's text
29425 * @param {String} text The button text
29427 setText : function(text){
29430 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29436 * Gets the text for this button
29437 * @return {String} The button text
29439 getText : function(){
29447 this.hidden = false;
29449 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29457 this.hidden = true;
29459 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29464 * Convenience function for boolean show/hide
29465 * @param {Boolean} visible True to show, false to hide
29467 setVisible: function(visible){
29476 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29477 * @param {Boolean} state (optional) Force a particular state
29479 toggle : function(state){
29480 state = state === undefined ? !this.pressed : state;
29481 if(state != this.pressed){
29483 this.el.addClass("x-btn-pressed");
29484 this.pressed = true;
29485 this.fireEvent("toggle", this, true);
29487 this.el.removeClass("x-btn-pressed");
29488 this.pressed = false;
29489 this.fireEvent("toggle", this, false);
29491 if(this.toggleHandler){
29492 this.toggleHandler.call(this.scope || this, this, state);
29500 focus : function(){
29501 this.el.child('button:first').focus();
29505 * Disable this button
29507 disable : function(){
29509 this.el.addClass("x-btn-disabled");
29511 this.disabled = true;
29515 * Enable this button
29517 enable : function(){
29519 this.el.removeClass("x-btn-disabled");
29521 this.disabled = false;
29525 * Convenience function for boolean enable/disable
29526 * @param {Boolean} enabled True to enable, false to disable
29528 setDisabled : function(v){
29529 this[v !== true ? "enable" : "disable"]();
29533 onClick : function(e)
29536 e.preventDefault();
29541 if(!this.disabled){
29542 if(this.enableToggle){
29545 if(this.menu && !this.menu.isVisible()){
29546 this.menu.show(this.el, this.menuAlign);
29548 this.fireEvent("click", this, e);
29550 this.el.removeClass("x-btn-over");
29551 this.handler.call(this.scope || this, this, e);
29556 onMouseOver : function(e){
29557 if(!this.disabled){
29558 this.el.addClass("x-btn-over");
29559 this.fireEvent('mouseover', this, e);
29563 onMouseOut : function(e){
29564 if(!e.within(this.el, true)){
29565 this.el.removeClass("x-btn-over");
29566 this.fireEvent('mouseout', this, e);
29570 onFocus : function(e){
29571 if(!this.disabled){
29572 this.el.addClass("x-btn-focus");
29576 onBlur : function(e){
29577 this.el.removeClass("x-btn-focus");
29580 onMouseDown : function(e){
29581 if(!this.disabled && e.button == 0){
29582 this.el.addClass("x-btn-click");
29583 Roo.get(document).on('mouseup', this.onMouseUp, this);
29587 onMouseUp : function(e){
29589 this.el.removeClass("x-btn-click");
29590 Roo.get(document).un('mouseup', this.onMouseUp, this);
29594 onMenuShow : function(e){
29595 this.el.addClass("x-btn-menu-active");
29598 onMenuHide : function(e){
29599 this.el.removeClass("x-btn-menu-active");
29603 // Private utility class used by Button
29604 Roo.ButtonToggleMgr = function(){
29607 function toggleGroup(btn, state){
29609 var g = groups[btn.toggleGroup];
29610 for(var i = 0, l = g.length; i < l; i++){
29612 g[i].toggle(false);
29619 register : function(btn){
29620 if(!btn.toggleGroup){
29623 var g = groups[btn.toggleGroup];
29625 g = groups[btn.toggleGroup] = [];
29628 btn.on("toggle", toggleGroup);
29631 unregister : function(btn){
29632 if(!btn.toggleGroup){
29635 var g = groups[btn.toggleGroup];
29638 btn.un("toggle", toggleGroup);
29644 * Ext JS Library 1.1.1
29645 * Copyright(c) 2006-2007, Ext JS, LLC.
29647 * Originally Released Under LGPL - original licence link has changed is not relivant.
29650 * <script type="text/javascript">
29654 * @class Roo.SplitButton
29655 * @extends Roo.Button
29656 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29657 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29658 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29659 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29660 * @cfg {String} arrowTooltip The title attribute of the arrow
29662 * Create a new menu button
29663 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29664 * @param {Object} config The config object
29666 Roo.SplitButton = function(renderTo, config){
29667 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29669 * @event arrowclick
29670 * Fires when this button's arrow is clicked
29671 * @param {SplitButton} this
29672 * @param {EventObject} e The click event
29674 this.addEvents({"arrowclick":true});
29677 Roo.extend(Roo.SplitButton, Roo.Button, {
29678 render : function(renderTo){
29679 // this is one sweet looking template!
29680 var tpl = new Roo.Template(
29681 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29682 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29683 '<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>',
29684 "</tbody></table></td><td>",
29685 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29686 '<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>',
29687 "</tbody></table></td></tr></table>"
29689 var btn = tpl.append(renderTo, [this.text, this.type], true);
29690 var btnEl = btn.child("button");
29692 btn.addClass(this.cls);
29695 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29698 btnEl.addClass(this.iconCls);
29700 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29704 if(this.handleMouseEvents){
29705 btn.on("mouseover", this.onMouseOver, this);
29706 btn.on("mouseout", this.onMouseOut, this);
29707 btn.on("mousedown", this.onMouseDown, this);
29708 btn.on("mouseup", this.onMouseUp, this);
29710 btn.on(this.clickEvent, this.onClick, this);
29712 if(typeof this.tooltip == 'object'){
29713 Roo.QuickTips.tips(Roo.apply({
29717 btnEl.dom[this.tooltipType] = this.tooltip;
29720 if(this.arrowTooltip){
29721 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29730 this.el.addClass("x-btn-pressed");
29732 if(Roo.isIE && !Roo.isIE7){
29733 this.autoWidth.defer(1, this);
29738 this.menu.on("show", this.onMenuShow, this);
29739 this.menu.on("hide", this.onMenuHide, this);
29741 this.fireEvent('render', this);
29745 autoWidth : function(){
29747 var tbl = this.el.child("table:first");
29748 var tbl2 = this.el.child("table:last");
29749 this.el.setWidth("auto");
29750 tbl.setWidth("auto");
29751 if(Roo.isIE7 && Roo.isStrict){
29752 var ib = this.el.child('button:first');
29753 if(ib && ib.getWidth() > 20){
29755 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29760 this.el.beginMeasure();
29762 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29763 tbl.setWidth(this.minWidth-tbl2.getWidth());
29766 this.el.endMeasure();
29769 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29773 * Sets this button's click handler
29774 * @param {Function} handler The function to call when the button is clicked
29775 * @param {Object} scope (optional) Scope for the function passed above
29777 setHandler : function(handler, scope){
29778 this.handler = handler;
29779 this.scope = scope;
29783 * Sets this button's arrow click handler
29784 * @param {Function} handler The function to call when the arrow is clicked
29785 * @param {Object} scope (optional) Scope for the function passed above
29787 setArrowHandler : function(handler, scope){
29788 this.arrowHandler = handler;
29789 this.scope = scope;
29795 focus : function(){
29797 this.el.child("button:first").focus();
29802 onClick : function(e){
29803 e.preventDefault();
29804 if(!this.disabled){
29805 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29806 if(this.menu && !this.menu.isVisible()){
29807 this.menu.show(this.el, this.menuAlign);
29809 this.fireEvent("arrowclick", this, e);
29810 if(this.arrowHandler){
29811 this.arrowHandler.call(this.scope || this, this, e);
29814 this.fireEvent("click", this, e);
29816 this.handler.call(this.scope || this, this, e);
29822 onMouseDown : function(e){
29823 if(!this.disabled){
29824 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29828 onMouseUp : function(e){
29829 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29834 // backwards compat
29835 Roo.MenuButton = Roo.SplitButton;/*
29837 * Ext JS Library 1.1.1
29838 * Copyright(c) 2006-2007, Ext JS, LLC.
29840 * Originally Released Under LGPL - original licence link has changed is not relivant.
29843 * <script type="text/javascript">
29847 * @class Roo.Toolbar
29848 * Basic Toolbar class.
29850 * Creates a new Toolbar
29851 * @param {Object} container The config object
29853 Roo.Toolbar = function(container, buttons, config)
29855 /// old consturctor format still supported..
29856 if(container instanceof Array){ // omit the container for later rendering
29857 buttons = container;
29861 if (typeof(container) == 'object' && container.xtype) {
29862 config = container;
29863 container = config.container;
29864 buttons = config.buttons || []; // not really - use items!!
29867 if (config && config.items) {
29868 xitems = config.items;
29869 delete config.items;
29871 Roo.apply(this, config);
29872 this.buttons = buttons;
29875 this.render(container);
29877 this.xitems = xitems;
29878 Roo.each(xitems, function(b) {
29884 Roo.Toolbar.prototype = {
29886 * @cfg {Array} items
29887 * array of button configs or elements to add (will be converted to a MixedCollection)
29891 * @cfg {String/HTMLElement/Element} container
29892 * The id or element that will contain the toolbar
29895 render : function(ct){
29896 this.el = Roo.get(ct);
29898 this.el.addClass(this.cls);
29900 // using a table allows for vertical alignment
29901 // 100% width is needed by Safari...
29902 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29903 this.tr = this.el.child("tr", true);
29905 this.items = new Roo.util.MixedCollection(false, function(o){
29906 return o.id || ("item" + (++autoId));
29909 this.add.apply(this, this.buttons);
29910 delete this.buttons;
29915 * Adds element(s) to the toolbar -- this function takes a variable number of
29916 * arguments of mixed type and adds them to the toolbar.
29917 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29919 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29920 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29921 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29922 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29923 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29924 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29925 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29926 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29927 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29929 * @param {Mixed} arg2
29930 * @param {Mixed} etc.
29933 var a = arguments, l = a.length;
29934 for(var i = 0; i < l; i++){
29939 _add : function(el) {
29942 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29945 if (el.applyTo){ // some kind of form field
29946 return this.addField(el);
29948 if (el.render){ // some kind of Toolbar.Item
29949 return this.addItem(el);
29951 if (typeof el == "string"){ // string
29952 if(el == "separator" || el == "-"){
29953 return this.addSeparator();
29956 return this.addSpacer();
29959 return this.addFill();
29961 return this.addText(el);
29964 if(el.tagName){ // element
29965 return this.addElement(el);
29967 if(typeof el == "object"){ // must be button config?
29968 return this.addButton(el);
29970 // and now what?!?!
29976 * Add an Xtype element
29977 * @param {Object} xtype Xtype Object
29978 * @return {Object} created Object
29980 addxtype : function(e){
29981 return this.add(e);
29985 * Returns the Element for this toolbar.
29986 * @return {Roo.Element}
29988 getEl : function(){
29994 * @return {Roo.Toolbar.Item} The separator item
29996 addSeparator : function(){
29997 return this.addItem(new Roo.Toolbar.Separator());
30001 * Adds a spacer element
30002 * @return {Roo.Toolbar.Spacer} The spacer item
30004 addSpacer : function(){
30005 return this.addItem(new Roo.Toolbar.Spacer());
30009 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30010 * @return {Roo.Toolbar.Fill} The fill item
30012 addFill : function(){
30013 return this.addItem(new Roo.Toolbar.Fill());
30017 * Adds any standard HTML element to the toolbar
30018 * @param {String/HTMLElement/Element} el The element or id of the element to add
30019 * @return {Roo.Toolbar.Item} The element's item
30021 addElement : function(el){
30022 return this.addItem(new Roo.Toolbar.Item(el));
30025 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30026 * @type Roo.util.MixedCollection
30031 * Adds any Toolbar.Item or subclass
30032 * @param {Roo.Toolbar.Item} item
30033 * @return {Roo.Toolbar.Item} The item
30035 addItem : function(item){
30036 var td = this.nextBlock();
30038 this.items.add(item);
30043 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30044 * @param {Object/Array} config A button config or array of configs
30045 * @return {Roo.Toolbar.Button/Array}
30047 addButton : function(config){
30048 if(config instanceof Array){
30050 for(var i = 0, len = config.length; i < len; i++) {
30051 buttons.push(this.addButton(config[i]));
30056 if(!(config instanceof Roo.Toolbar.Button)){
30058 new Roo.Toolbar.SplitButton(config) :
30059 new Roo.Toolbar.Button(config);
30061 var td = this.nextBlock();
30068 * Adds text to the toolbar
30069 * @param {String} text The text to add
30070 * @return {Roo.Toolbar.Item} The element's item
30072 addText : function(text){
30073 return this.addItem(new Roo.Toolbar.TextItem(text));
30077 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30078 * @param {Number} index The index where the item is to be inserted
30079 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30080 * @return {Roo.Toolbar.Button/Item}
30082 insertButton : function(index, item){
30083 if(item instanceof Array){
30085 for(var i = 0, len = item.length; i < len; i++) {
30086 buttons.push(this.insertButton(index + i, item[i]));
30090 if (!(item instanceof Roo.Toolbar.Button)){
30091 item = new Roo.Toolbar.Button(item);
30093 var td = document.createElement("td");
30094 this.tr.insertBefore(td, this.tr.childNodes[index]);
30096 this.items.insert(index, item);
30101 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30102 * @param {Object} config
30103 * @return {Roo.Toolbar.Item} The element's item
30105 addDom : function(config, returnEl){
30106 var td = this.nextBlock();
30107 Roo.DomHelper.overwrite(td, config);
30108 var ti = new Roo.Toolbar.Item(td.firstChild);
30110 this.items.add(ti);
30115 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30116 * @type Roo.util.MixedCollection
30121 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30122 * Note: the field should not have been rendered yet. For a field that has already been
30123 * rendered, use {@link #addElement}.
30124 * @param {Roo.form.Field} field
30125 * @return {Roo.ToolbarItem}
30129 addField : function(field) {
30130 if (!this.fields) {
30132 this.fields = new Roo.util.MixedCollection(false, function(o){
30133 return o.id || ("item" + (++autoId));
30138 var td = this.nextBlock();
30140 var ti = new Roo.Toolbar.Item(td.firstChild);
30142 this.items.add(ti);
30143 this.fields.add(field);
30154 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30155 this.el.child('div').hide();
30163 this.el.child('div').show();
30167 nextBlock : function(){
30168 var td = document.createElement("td");
30169 this.tr.appendChild(td);
30174 destroy : function(){
30175 if(this.items){ // rendered?
30176 Roo.destroy.apply(Roo, this.items.items);
30178 if(this.fields){ // rendered?
30179 Roo.destroy.apply(Roo, this.fields.items);
30181 Roo.Element.uncache(this.el, this.tr);
30186 * @class Roo.Toolbar.Item
30187 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30189 * Creates a new Item
30190 * @param {HTMLElement} el
30192 Roo.Toolbar.Item = function(el){
30194 if (typeof (el.xtype) != 'undefined') {
30199 this.el = Roo.getDom(el);
30200 this.id = Roo.id(this.el);
30201 this.hidden = false;
30206 * Fires when the button is rendered
30207 * @param {Button} this
30211 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30213 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30214 //Roo.Toolbar.Item.prototype = {
30217 * Get this item's HTML Element
30218 * @return {HTMLElement}
30220 getEl : function(){
30225 render : function(td){
30228 td.appendChild(this.el);
30230 this.fireEvent('render', this);
30234 * Removes and destroys this item.
30236 destroy : function(){
30237 this.td.parentNode.removeChild(this.td);
30244 this.hidden = false;
30245 this.td.style.display = "";
30252 this.hidden = true;
30253 this.td.style.display = "none";
30257 * Convenience function for boolean show/hide.
30258 * @param {Boolean} visible true to show/false to hide
30260 setVisible: function(visible){
30269 * Try to focus this item.
30271 focus : function(){
30272 Roo.fly(this.el).focus();
30276 * Disables this item.
30278 disable : function(){
30279 Roo.fly(this.td).addClass("x-item-disabled");
30280 this.disabled = true;
30281 this.el.disabled = true;
30285 * Enables this item.
30287 enable : function(){
30288 Roo.fly(this.td).removeClass("x-item-disabled");
30289 this.disabled = false;
30290 this.el.disabled = false;
30296 * @class Roo.Toolbar.Separator
30297 * @extends Roo.Toolbar.Item
30298 * A simple toolbar separator class
30300 * Creates a new Separator
30302 Roo.Toolbar.Separator = function(cfg){
30304 var s = document.createElement("span");
30305 s.className = "ytb-sep";
30310 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30312 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30313 enable:Roo.emptyFn,
30314 disable:Roo.emptyFn,
30319 * @class Roo.Toolbar.Spacer
30320 * @extends Roo.Toolbar.Item
30321 * A simple element that adds extra horizontal space to a toolbar.
30323 * Creates a new Spacer
30325 Roo.Toolbar.Spacer = function(cfg){
30326 var s = document.createElement("div");
30327 s.className = "ytb-spacer";
30331 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30333 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30334 enable:Roo.emptyFn,
30335 disable:Roo.emptyFn,
30340 * @class Roo.Toolbar.Fill
30341 * @extends Roo.Toolbar.Spacer
30342 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30344 * Creates a new Spacer
30346 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30348 render : function(td){
30349 td.style.width = '100%';
30350 Roo.Toolbar.Fill.superclass.render.call(this, td);
30355 * @class Roo.Toolbar.TextItem
30356 * @extends Roo.Toolbar.Item
30357 * A simple class that renders text directly into a toolbar.
30359 * Creates a new TextItem
30360 * @param {String} text
30362 Roo.Toolbar.TextItem = function(cfg){
30363 var text = cfg || "";
30364 if (typeof(cfg) == 'object') {
30365 text = cfg.text || "";
30369 var s = document.createElement("span");
30370 s.className = "ytb-text";
30371 s.innerHTML = text;
30376 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30378 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30381 enable:Roo.emptyFn,
30382 disable:Roo.emptyFn,
30387 * @class Roo.Toolbar.Button
30388 * @extends Roo.Button
30389 * A button that renders into a toolbar.
30391 * Creates a new Button
30392 * @param {Object} config A standard {@link Roo.Button} config object
30394 Roo.Toolbar.Button = function(config){
30395 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30397 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30398 render : function(td){
30400 Roo.Toolbar.Button.superclass.render.call(this, td);
30404 * Removes and destroys this button
30406 destroy : function(){
30407 Roo.Toolbar.Button.superclass.destroy.call(this);
30408 this.td.parentNode.removeChild(this.td);
30412 * Shows this button
30415 this.hidden = false;
30416 this.td.style.display = "";
30420 * Hides this button
30423 this.hidden = true;
30424 this.td.style.display = "none";
30428 * Disables this item
30430 disable : function(){
30431 Roo.fly(this.td).addClass("x-item-disabled");
30432 this.disabled = true;
30436 * Enables this item
30438 enable : function(){
30439 Roo.fly(this.td).removeClass("x-item-disabled");
30440 this.disabled = false;
30443 // backwards compat
30444 Roo.ToolbarButton = Roo.Toolbar.Button;
30447 * @class Roo.Toolbar.SplitButton
30448 * @extends Roo.SplitButton
30449 * A menu button that renders into a toolbar.
30451 * Creates a new SplitButton
30452 * @param {Object} config A standard {@link Roo.SplitButton} config object
30454 Roo.Toolbar.SplitButton = function(config){
30455 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30457 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30458 render : function(td){
30460 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30464 * Removes and destroys this button
30466 destroy : function(){
30467 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30468 this.td.parentNode.removeChild(this.td);
30472 * Shows this button
30475 this.hidden = false;
30476 this.td.style.display = "";
30480 * Hides this button
30483 this.hidden = true;
30484 this.td.style.display = "none";
30488 // backwards compat
30489 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30491 * Ext JS Library 1.1.1
30492 * Copyright(c) 2006-2007, Ext JS, LLC.
30494 * Originally Released Under LGPL - original licence link has changed is not relivant.
30497 * <script type="text/javascript">
30501 * @class Roo.PagingToolbar
30502 * @extends Roo.Toolbar
30503 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30505 * Create a new PagingToolbar
30506 * @param {Object} config The config object
30508 Roo.PagingToolbar = function(el, ds, config)
30510 // old args format still supported... - xtype is prefered..
30511 if (typeof(el) == 'object' && el.xtype) {
30512 // created from xtype...
30514 ds = el.dataSource;
30515 el = config.container;
30518 if (config.items) {
30519 items = config.items;
30523 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30526 this.renderButtons(this.el);
30529 // supprot items array.
30531 Roo.each(items, function(e) {
30532 this.add(Roo.factory(e));
30537 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30539 * @cfg {Roo.data.Store} dataSource
30540 * The underlying data store providing the paged data
30543 * @cfg {String/HTMLElement/Element} container
30544 * container The id or element that will contain the toolbar
30547 * @cfg {Boolean} displayInfo
30548 * True to display the displayMsg (defaults to false)
30551 * @cfg {Number} pageSize
30552 * The number of records to display per page (defaults to 20)
30556 * @cfg {String} displayMsg
30557 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30559 displayMsg : 'Displaying {0} - {1} of {2}',
30561 * @cfg {String} emptyMsg
30562 * The message to display when no records are found (defaults to "No data to display")
30564 emptyMsg : 'No data to display',
30566 * Customizable piece of the default paging text (defaults to "Page")
30569 beforePageText : "Page",
30571 * Customizable piece of the default paging text (defaults to "of %0")
30574 afterPageText : "of {0}",
30576 * Customizable piece of the default paging text (defaults to "First Page")
30579 firstText : "First Page",
30581 * Customizable piece of the default paging text (defaults to "Previous Page")
30584 prevText : "Previous Page",
30586 * Customizable piece of the default paging text (defaults to "Next Page")
30589 nextText : "Next Page",
30591 * Customizable piece of the default paging text (defaults to "Last Page")
30594 lastText : "Last Page",
30596 * Customizable piece of the default paging text (defaults to "Refresh")
30599 refreshText : "Refresh",
30602 renderButtons : function(el){
30603 Roo.PagingToolbar.superclass.render.call(this, el);
30604 this.first = this.addButton({
30605 tooltip: this.firstText,
30606 cls: "x-btn-icon x-grid-page-first",
30608 handler: this.onClick.createDelegate(this, ["first"])
30610 this.prev = this.addButton({
30611 tooltip: this.prevText,
30612 cls: "x-btn-icon x-grid-page-prev",
30614 handler: this.onClick.createDelegate(this, ["prev"])
30616 //this.addSeparator();
30617 this.add(this.beforePageText);
30618 this.field = Roo.get(this.addDom({
30623 cls: "x-grid-page-number"
30625 this.field.on("keydown", this.onPagingKeydown, this);
30626 this.field.on("focus", function(){this.dom.select();});
30627 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30628 this.field.setHeight(18);
30629 //this.addSeparator();
30630 this.next = this.addButton({
30631 tooltip: this.nextText,
30632 cls: "x-btn-icon x-grid-page-next",
30634 handler: this.onClick.createDelegate(this, ["next"])
30636 this.last = this.addButton({
30637 tooltip: this.lastText,
30638 cls: "x-btn-icon x-grid-page-last",
30640 handler: this.onClick.createDelegate(this, ["last"])
30642 //this.addSeparator();
30643 this.loading = this.addButton({
30644 tooltip: this.refreshText,
30645 cls: "x-btn-icon x-grid-loading",
30646 handler: this.onClick.createDelegate(this, ["refresh"])
30649 if(this.displayInfo){
30650 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30655 updateInfo : function(){
30656 if(this.displayEl){
30657 var count = this.ds.getCount();
30658 var msg = count == 0 ?
30662 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30664 this.displayEl.update(msg);
30669 onLoad : function(ds, r, o){
30670 this.cursor = o.params ? o.params.start : 0;
30671 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30673 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30674 this.field.dom.value = ap;
30675 this.first.setDisabled(ap == 1);
30676 this.prev.setDisabled(ap == 1);
30677 this.next.setDisabled(ap == ps);
30678 this.last.setDisabled(ap == ps);
30679 this.loading.enable();
30684 getPageData : function(){
30685 var total = this.ds.getTotalCount();
30688 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30689 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30694 onLoadError : function(){
30695 this.loading.enable();
30699 onPagingKeydown : function(e){
30700 var k = e.getKey();
30701 var d = this.getPageData();
30703 var v = this.field.dom.value, pageNum;
30704 if(!v || isNaN(pageNum = parseInt(v, 10))){
30705 this.field.dom.value = d.activePage;
30708 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30709 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30712 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))
30714 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30715 this.field.dom.value = pageNum;
30716 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30719 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30721 var v = this.field.dom.value, pageNum;
30722 var increment = (e.shiftKey) ? 10 : 1;
30723 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30726 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30727 this.field.dom.value = d.activePage;
30730 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30732 this.field.dom.value = parseInt(v, 10) + increment;
30733 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30734 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30741 beforeLoad : function(){
30743 this.loading.disable();
30748 onClick : function(which){
30752 ds.load({params:{start: 0, limit: this.pageSize}});
30755 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30758 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30761 var total = ds.getTotalCount();
30762 var extra = total % this.pageSize;
30763 var lastStart = extra ? (total - extra) : total-this.pageSize;
30764 ds.load({params:{start: lastStart, limit: this.pageSize}});
30767 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30773 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30774 * @param {Roo.data.Store} store The data store to unbind
30776 unbind : function(ds){
30777 ds.un("beforeload", this.beforeLoad, this);
30778 ds.un("load", this.onLoad, this);
30779 ds.un("loadexception", this.onLoadError, this);
30780 ds.un("remove", this.updateInfo, this);
30781 ds.un("add", this.updateInfo, this);
30782 this.ds = undefined;
30786 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30787 * @param {Roo.data.Store} store The data store to bind
30789 bind : function(ds){
30790 ds.on("beforeload", this.beforeLoad, this);
30791 ds.on("load", this.onLoad, this);
30792 ds.on("loadexception", this.onLoadError, this);
30793 ds.on("remove", this.updateInfo, this);
30794 ds.on("add", this.updateInfo, this);
30799 * Ext JS Library 1.1.1
30800 * Copyright(c) 2006-2007, Ext JS, LLC.
30802 * Originally Released Under LGPL - original licence link has changed is not relivant.
30805 * <script type="text/javascript">
30809 * @class Roo.Resizable
30810 * @extends Roo.util.Observable
30811 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30812 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30813 * 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
30814 * the element will be wrapped for you automatically.</p>
30815 * <p>Here is the list of valid resize handles:</p>
30818 ------ -------------------
30827 'hd' horizontal drag
30830 * <p>Here's an example showing the creation of a typical Resizable:</p>
30832 var resizer = new Roo.Resizable("element-id", {
30840 resizer.on("resize", myHandler);
30842 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30843 * resizer.east.setDisplayed(false);</p>
30844 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30845 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30846 * resize operation's new size (defaults to [0, 0])
30847 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30848 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30849 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30850 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30851 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30852 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30853 * @cfg {Number} width The width of the element in pixels (defaults to null)
30854 * @cfg {Number} height The height of the element in pixels (defaults to null)
30855 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30856 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30857 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30858 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30859 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30860 * in favor of the handles config option (defaults to false)
30861 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30862 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30863 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30864 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30865 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30866 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30867 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30868 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30869 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30870 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30871 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30873 * Create a new resizable component
30874 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30875 * @param {Object} config configuration options
30877 Roo.Resizable = function(el, config)
30879 this.el = Roo.get(el);
30881 if(config && config.wrap){
30882 config.resizeChild = this.el;
30883 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30884 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30885 this.el.setStyle("overflow", "hidden");
30886 this.el.setPositioning(config.resizeChild.getPositioning());
30887 config.resizeChild.clearPositioning();
30888 if(!config.width || !config.height){
30889 var csize = config.resizeChild.getSize();
30890 this.el.setSize(csize.width, csize.height);
30892 if(config.pinned && !config.adjustments){
30893 config.adjustments = "auto";
30897 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30898 this.proxy.unselectable();
30899 this.proxy.enableDisplayMode('block');
30901 Roo.apply(this, config);
30904 this.disableTrackOver = true;
30905 this.el.addClass("x-resizable-pinned");
30907 // if the element isn't positioned, make it relative
30908 var position = this.el.getStyle("position");
30909 if(position != "absolute" && position != "fixed"){
30910 this.el.setStyle("position", "relative");
30912 if(!this.handles){ // no handles passed, must be legacy style
30913 this.handles = 's,e,se';
30914 if(this.multiDirectional){
30915 this.handles += ',n,w';
30918 if(this.handles == "all"){
30919 this.handles = "n s e w ne nw se sw";
30921 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30922 var ps = Roo.Resizable.positions;
30923 for(var i = 0, len = hs.length; i < len; i++){
30924 if(hs[i] && ps[hs[i]]){
30925 var pos = ps[hs[i]];
30926 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30930 this.corner = this.southeast;
30932 // updateBox = the box can move..
30933 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30934 this.updateBox = true;
30937 this.activeHandle = null;
30939 if(this.resizeChild){
30940 if(typeof this.resizeChild == "boolean"){
30941 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30943 this.resizeChild = Roo.get(this.resizeChild, true);
30947 if(this.adjustments == "auto"){
30948 var rc = this.resizeChild;
30949 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30950 if(rc && (hw || hn)){
30951 rc.position("relative");
30952 rc.setLeft(hw ? hw.el.getWidth() : 0);
30953 rc.setTop(hn ? hn.el.getHeight() : 0);
30955 this.adjustments = [
30956 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30957 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30961 if(this.draggable){
30962 this.dd = this.dynamic ?
30963 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30964 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30970 * @event beforeresize
30971 * Fired before resize is allowed. Set enabled to false to cancel resize.
30972 * @param {Roo.Resizable} this
30973 * @param {Roo.EventObject} e The mousedown event
30975 "beforeresize" : true,
30978 * Fired a resizing.
30979 * @param {Roo.Resizable} this
30980 * @param {Number} x The new x position
30981 * @param {Number} y The new y position
30982 * @param {Number} w The new w width
30983 * @param {Number} h The new h hight
30984 * @param {Roo.EventObject} e The mouseup event
30989 * Fired after a resize.
30990 * @param {Roo.Resizable} this
30991 * @param {Number} width The new width
30992 * @param {Number} height The new height
30993 * @param {Roo.EventObject} e The mouseup event
30998 if(this.width !== null && this.height !== null){
30999 this.resizeTo(this.width, this.height);
31001 this.updateChildSize();
31004 this.el.dom.style.zoom = 1;
31006 Roo.Resizable.superclass.constructor.call(this);
31009 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31010 resizeChild : false,
31011 adjustments : [0, 0],
31021 multiDirectional : false,
31022 disableTrackOver : false,
31023 easing : 'easeOutStrong',
31024 widthIncrement : 0,
31025 heightIncrement : 0,
31029 preserveRatio : false,
31030 transparent: false,
31036 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31038 constrainTo: undefined,
31040 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31042 resizeRegion: undefined,
31046 * Perform a manual resize
31047 * @param {Number} width
31048 * @param {Number} height
31050 resizeTo : function(width, height){
31051 this.el.setSize(width, height);
31052 this.updateChildSize();
31053 this.fireEvent("resize", this, width, height, null);
31057 startSizing : function(e, handle){
31058 this.fireEvent("beforeresize", this, e);
31059 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31062 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31063 this.overlay.unselectable();
31064 this.overlay.enableDisplayMode("block");
31065 this.overlay.on("mousemove", this.onMouseMove, this);
31066 this.overlay.on("mouseup", this.onMouseUp, this);
31068 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31070 this.resizing = true;
31071 this.startBox = this.el.getBox();
31072 this.startPoint = e.getXY();
31073 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31074 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31076 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31077 this.overlay.show();
31079 if(this.constrainTo) {
31080 var ct = Roo.get(this.constrainTo);
31081 this.resizeRegion = ct.getRegion().adjust(
31082 ct.getFrameWidth('t'),
31083 ct.getFrameWidth('l'),
31084 -ct.getFrameWidth('b'),
31085 -ct.getFrameWidth('r')
31089 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31091 this.proxy.setBox(this.startBox);
31093 this.proxy.setStyle('visibility', 'visible');
31099 onMouseDown : function(handle, e){
31102 this.activeHandle = handle;
31103 this.startSizing(e, handle);
31108 onMouseUp : function(e){
31109 var size = this.resizeElement();
31110 this.resizing = false;
31112 this.overlay.hide();
31114 this.fireEvent("resize", this, size.width, size.height, e);
31118 updateChildSize : function(){
31120 if(this.resizeChild){
31122 var child = this.resizeChild;
31123 var adj = this.adjustments;
31124 if(el.dom.offsetWidth){
31125 var b = el.getSize(true);
31126 child.setSize(b.width+adj[0], b.height+adj[1]);
31128 // Second call here for IE
31129 // The first call enables instant resizing and
31130 // the second call corrects scroll bars if they
31133 setTimeout(function(){
31134 if(el.dom.offsetWidth){
31135 var b = el.getSize(true);
31136 child.setSize(b.width+adj[0], b.height+adj[1]);
31144 snap : function(value, inc, min){
31145 if(!inc || !value) {
31148 var newValue = value;
31149 var m = value % inc;
31152 newValue = value + (inc-m);
31154 newValue = value - m;
31157 return Math.max(min, newValue);
31161 resizeElement : function(){
31162 var box = this.proxy.getBox();
31163 if(this.updateBox){
31164 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31166 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31168 this.updateChildSize();
31176 constrain : function(v, diff, m, mx){
31179 }else if(v - diff > mx){
31186 onMouseMove : function(e){
31189 try{// try catch so if something goes wrong the user doesn't get hung
31191 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31195 //var curXY = this.startPoint;
31196 var curSize = this.curSize || this.startBox;
31197 var x = this.startBox.x, y = this.startBox.y;
31198 var ox = x, oy = y;
31199 var w = curSize.width, h = curSize.height;
31200 var ow = w, oh = h;
31201 var mw = this.minWidth, mh = this.minHeight;
31202 var mxw = this.maxWidth, mxh = this.maxHeight;
31203 var wi = this.widthIncrement;
31204 var hi = this.heightIncrement;
31206 var eventXY = e.getXY();
31207 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31208 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31210 var pos = this.activeHandle.position;
31215 w = Math.min(Math.max(mw, w), mxw);
31220 h = Math.min(Math.max(mh, h), mxh);
31225 w = Math.min(Math.max(mw, w), mxw);
31226 h = Math.min(Math.max(mh, h), mxh);
31229 diffY = this.constrain(h, diffY, mh, mxh);
31236 var adiffX = Math.abs(diffX);
31237 var sub = (adiffX % wi); // how much
31238 if (sub > (wi/2)) { // far enough to snap
31239 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31241 // remove difference..
31242 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31246 x = Math.max(this.minX, x);
31249 diffX = this.constrain(w, diffX, mw, mxw);
31255 w = Math.min(Math.max(mw, w), mxw);
31256 diffY = this.constrain(h, diffY, mh, mxh);
31261 diffX = this.constrain(w, diffX, mw, mxw);
31262 diffY = this.constrain(h, diffY, mh, mxh);
31269 diffX = this.constrain(w, diffX, mw, mxw);
31271 h = Math.min(Math.max(mh, h), mxh);
31277 var sw = this.snap(w, wi, mw);
31278 var sh = this.snap(h, hi, mh);
31279 if(sw != w || sh != h){
31302 if(this.preserveRatio){
31307 h = Math.min(Math.max(mh, h), mxh);
31312 w = Math.min(Math.max(mw, w), mxw);
31317 w = Math.min(Math.max(mw, w), mxw);
31323 w = Math.min(Math.max(mw, w), mxw);
31329 h = Math.min(Math.max(mh, h), mxh);
31337 h = Math.min(Math.max(mh, h), mxh);
31347 h = Math.min(Math.max(mh, h), mxh);
31355 if (pos == 'hdrag') {
31358 this.proxy.setBounds(x, y, w, h);
31360 this.resizeElement();
31364 this.fireEvent("resizing", this, x, y, w, h, e);
31368 handleOver : function(){
31370 this.el.addClass("x-resizable-over");
31375 handleOut : function(){
31376 if(!this.resizing){
31377 this.el.removeClass("x-resizable-over");
31382 * Returns the element this component is bound to.
31383 * @return {Roo.Element}
31385 getEl : function(){
31390 * Returns the resizeChild element (or null).
31391 * @return {Roo.Element}
31393 getResizeChild : function(){
31394 return this.resizeChild;
31396 groupHandler : function()
31401 * Destroys this resizable. If the element was wrapped and
31402 * removeEl is not true then the element remains.
31403 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31405 destroy : function(removeEl){
31406 this.proxy.remove();
31408 this.overlay.removeAllListeners();
31409 this.overlay.remove();
31411 var ps = Roo.Resizable.positions;
31413 if(typeof ps[k] != "function" && this[ps[k]]){
31414 var h = this[ps[k]];
31415 h.el.removeAllListeners();
31420 this.el.update("");
31427 // hash to map config positions to true positions
31428 Roo.Resizable.positions = {
31429 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31434 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31436 // only initialize the template if resizable is used
31437 var tpl = Roo.DomHelper.createTemplate(
31438 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31441 Roo.Resizable.Handle.prototype.tpl = tpl;
31443 this.position = pos;
31445 // show north drag fro topdra
31446 var handlepos = pos == 'hdrag' ? 'north' : pos;
31448 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31449 if (pos == 'hdrag') {
31450 this.el.setStyle('cursor', 'pointer');
31452 this.el.unselectable();
31454 this.el.setOpacity(0);
31456 this.el.on("mousedown", this.onMouseDown, this);
31457 if(!disableTrackOver){
31458 this.el.on("mouseover", this.onMouseOver, this);
31459 this.el.on("mouseout", this.onMouseOut, this);
31464 Roo.Resizable.Handle.prototype = {
31465 afterResize : function(rz){
31470 onMouseDown : function(e){
31471 this.rz.onMouseDown(this, e);
31474 onMouseOver : function(e){
31475 this.rz.handleOver(this, e);
31478 onMouseOut : function(e){
31479 this.rz.handleOut(this, e);
31483 * Ext JS Library 1.1.1
31484 * Copyright(c) 2006-2007, Ext JS, LLC.
31486 * Originally Released Under LGPL - original licence link has changed is not relivant.
31489 * <script type="text/javascript">
31493 * @class Roo.Editor
31494 * @extends Roo.Component
31495 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31497 * Create a new Editor
31498 * @param {Roo.form.Field} field The Field object (or descendant)
31499 * @param {Object} config The config object
31501 Roo.Editor = function(field, config){
31502 Roo.Editor.superclass.constructor.call(this, config);
31503 this.field = field;
31506 * @event beforestartedit
31507 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31508 * false from the handler of this event.
31509 * @param {Editor} this
31510 * @param {Roo.Element} boundEl The underlying element bound to this editor
31511 * @param {Mixed} value The field value being set
31513 "beforestartedit" : true,
31516 * Fires when this editor is displayed
31517 * @param {Roo.Element} boundEl The underlying element bound to this editor
31518 * @param {Mixed} value The starting field value
31520 "startedit" : true,
31522 * @event beforecomplete
31523 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31524 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31525 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31526 * event will not fire since no edit actually occurred.
31527 * @param {Editor} this
31528 * @param {Mixed} value The current field value
31529 * @param {Mixed} startValue The original field value
31531 "beforecomplete" : true,
31534 * Fires after editing is complete and any changed value has been written to the underlying field.
31535 * @param {Editor} this
31536 * @param {Mixed} value The current field value
31537 * @param {Mixed} startValue The original field value
31541 * @event specialkey
31542 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31543 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31544 * @param {Roo.form.Field} this
31545 * @param {Roo.EventObject} e The event object
31547 "specialkey" : true
31551 Roo.extend(Roo.Editor, Roo.Component, {
31553 * @cfg {Boolean/String} autosize
31554 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31555 * or "height" to adopt the height only (defaults to false)
31558 * @cfg {Boolean} revertInvalid
31559 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31560 * validation fails (defaults to true)
31563 * @cfg {Boolean} ignoreNoChange
31564 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31565 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31566 * will never be ignored.
31569 * @cfg {Boolean} hideEl
31570 * False to keep the bound element visible while the editor is displayed (defaults to true)
31573 * @cfg {Mixed} value
31574 * The data value of the underlying field (defaults to "")
31578 * @cfg {String} alignment
31579 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31583 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31584 * for bottom-right shadow (defaults to "frame")
31588 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31592 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31594 completeOnEnter : false,
31596 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31598 cancelOnEsc : false,
31600 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31605 onRender : function(ct, position){
31606 this.el = new Roo.Layer({
31607 shadow: this.shadow,
31613 constrain: this.constrain
31615 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31616 if(this.field.msgTarget != 'title'){
31617 this.field.msgTarget = 'qtip';
31619 this.field.render(this.el);
31621 this.field.el.dom.setAttribute('autocomplete', 'off');
31623 this.field.on("specialkey", this.onSpecialKey, this);
31624 if(this.swallowKeys){
31625 this.field.el.swallowEvent(['keydown','keypress']);
31628 this.field.on("blur", this.onBlur, this);
31629 if(this.field.grow){
31630 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31634 onSpecialKey : function(field, e)
31636 //Roo.log('editor onSpecialKey');
31637 if(this.completeOnEnter && e.getKey() == e.ENTER){
31639 this.completeEdit();
31642 // do not fire special key otherwise it might hide close the editor...
31643 if(e.getKey() == e.ENTER){
31646 if(this.cancelOnEsc && e.getKey() == e.ESC){
31650 this.fireEvent('specialkey', field, e);
31655 * Starts the editing process and shows the editor.
31656 * @param {String/HTMLElement/Element} el The element to edit
31657 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31658 * to the innerHTML of el.
31660 startEdit : function(el, value){
31662 this.completeEdit();
31664 this.boundEl = Roo.get(el);
31665 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31666 if(!this.rendered){
31667 this.render(this.parentEl || document.body);
31669 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31672 this.startValue = v;
31673 this.field.setValue(v);
31675 var sz = this.boundEl.getSize();
31676 switch(this.autoSize){
31678 this.setSize(sz.width, "");
31681 this.setSize("", sz.height);
31684 this.setSize(sz.width, sz.height);
31687 this.el.alignTo(this.boundEl, this.alignment);
31688 this.editing = true;
31690 Roo.QuickTips.disable();
31696 * Sets the height and width of this editor.
31697 * @param {Number} width The new width
31698 * @param {Number} height The new height
31700 setSize : function(w, h){
31701 this.field.setSize(w, h);
31708 * Realigns the editor to the bound field based on the current alignment config value.
31710 realign : function(){
31711 this.el.alignTo(this.boundEl, this.alignment);
31715 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31716 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31718 completeEdit : function(remainVisible){
31722 var v = this.getValue();
31723 if(this.revertInvalid !== false && !this.field.isValid()){
31724 v = this.startValue;
31725 this.cancelEdit(true);
31727 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31728 this.editing = false;
31732 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31733 this.editing = false;
31734 if(this.updateEl && this.boundEl){
31735 this.boundEl.update(v);
31737 if(remainVisible !== true){
31740 this.fireEvent("complete", this, v, this.startValue);
31745 onShow : function(){
31747 if(this.hideEl !== false){
31748 this.boundEl.hide();
31751 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31752 this.fixIEFocus = true;
31753 this.deferredFocus.defer(50, this);
31755 this.field.focus();
31757 this.fireEvent("startedit", this.boundEl, this.startValue);
31760 deferredFocus : function(){
31762 this.field.focus();
31767 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31768 * reverted to the original starting value.
31769 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31770 * cancel (defaults to false)
31772 cancelEdit : function(remainVisible){
31774 this.setValue(this.startValue);
31775 if(remainVisible !== true){
31782 onBlur : function(){
31783 if(this.allowBlur !== true && this.editing){
31784 this.completeEdit();
31789 onHide : function(){
31791 this.completeEdit();
31795 if(this.field.collapse){
31796 this.field.collapse();
31799 if(this.hideEl !== false){
31800 this.boundEl.show();
31803 Roo.QuickTips.enable();
31808 * Sets the data value of the editor
31809 * @param {Mixed} value Any valid value supported by the underlying field
31811 setValue : function(v){
31812 this.field.setValue(v);
31816 * Gets the data value of the editor
31817 * @return {Mixed} The data value
31819 getValue : function(){
31820 return this.field.getValue();
31824 * Ext JS Library 1.1.1
31825 * Copyright(c) 2006-2007, Ext JS, LLC.
31827 * Originally Released Under LGPL - original licence link has changed is not relivant.
31830 * <script type="text/javascript">
31834 * @class Roo.BasicDialog
31835 * @extends Roo.util.Observable
31836 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31838 var dlg = new Roo.BasicDialog("my-dlg", {
31847 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31848 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31849 dlg.addButton('Cancel', dlg.hide, dlg);
31852 <b>A Dialog should always be a direct child of the body element.</b>
31853 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31854 * @cfg {String} title Default text to display in the title bar (defaults to null)
31855 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31856 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31857 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31858 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31859 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31860 * (defaults to null with no animation)
31861 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31862 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31863 * property for valid values (defaults to 'all')
31864 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31865 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31866 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31867 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31868 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31869 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31870 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31871 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31872 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31873 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31874 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31875 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31876 * draggable = true (defaults to false)
31877 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31878 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31879 * shadow (defaults to false)
31880 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31881 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31882 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31883 * @cfg {Array} buttons Array of buttons
31884 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31886 * Create a new BasicDialog.
31887 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31888 * @param {Object} config Configuration options
31890 Roo.BasicDialog = function(el, config){
31891 this.el = Roo.get(el);
31892 var dh = Roo.DomHelper;
31893 if(!this.el && config && config.autoCreate){
31894 if(typeof config.autoCreate == "object"){
31895 if(!config.autoCreate.id){
31896 config.autoCreate.id = el;
31898 this.el = dh.append(document.body,
31899 config.autoCreate, true);
31901 this.el = dh.append(document.body,
31902 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31906 el.setDisplayed(true);
31907 el.hide = this.hideAction;
31909 el.addClass("x-dlg");
31911 Roo.apply(this, config);
31913 this.proxy = el.createProxy("x-dlg-proxy");
31914 this.proxy.hide = this.hideAction;
31915 this.proxy.setOpacity(.5);
31919 el.setWidth(config.width);
31922 el.setHeight(config.height);
31924 this.size = el.getSize();
31925 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31926 this.xy = [config.x,config.y];
31928 this.xy = el.getCenterXY(true);
31930 /** The header element @type Roo.Element */
31931 this.header = el.child("> .x-dlg-hd");
31932 /** The body element @type Roo.Element */
31933 this.body = el.child("> .x-dlg-bd");
31934 /** The footer element @type Roo.Element */
31935 this.footer = el.child("> .x-dlg-ft");
31938 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31941 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31944 this.header.unselectable();
31946 this.header.update(this.title);
31948 // this element allows the dialog to be focused for keyboard event
31949 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31950 this.focusEl.swallowEvent("click", true);
31952 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31954 // wrap the body and footer for special rendering
31955 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31957 this.bwrap.dom.appendChild(this.footer.dom);
31960 this.bg = this.el.createChild({
31961 tag: "div", cls:"x-dlg-bg",
31962 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31964 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31967 if(this.autoScroll !== false && !this.autoTabs){
31968 this.body.setStyle("overflow", "auto");
31971 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31973 if(this.closable !== false){
31974 this.el.addClass("x-dlg-closable");
31975 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31976 this.close.on("click", this.closeClick, this);
31977 this.close.addClassOnOver("x-dlg-close-over");
31979 if(this.collapsible !== false){
31980 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31981 this.collapseBtn.on("click", this.collapseClick, this);
31982 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31983 this.header.on("dblclick", this.collapseClick, this);
31985 if(this.resizable !== false){
31986 this.el.addClass("x-dlg-resizable");
31987 this.resizer = new Roo.Resizable(el, {
31988 minWidth: this.minWidth || 80,
31989 minHeight:this.minHeight || 80,
31990 handles: this.resizeHandles || "all",
31993 this.resizer.on("beforeresize", this.beforeResize, this);
31994 this.resizer.on("resize", this.onResize, this);
31996 if(this.draggable !== false){
31997 el.addClass("x-dlg-draggable");
31998 if (!this.proxyDrag) {
31999 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32002 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32004 dd.setHandleElId(this.header.id);
32005 dd.endDrag = this.endMove.createDelegate(this);
32006 dd.startDrag = this.startMove.createDelegate(this);
32007 dd.onDrag = this.onDrag.createDelegate(this);
32012 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32013 this.mask.enableDisplayMode("block");
32015 this.el.addClass("x-dlg-modal");
32018 this.shadow = new Roo.Shadow({
32019 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32020 offset : this.shadowOffset
32023 this.shadowOffset = 0;
32025 if(Roo.useShims && this.shim !== false){
32026 this.shim = this.el.createShim();
32027 this.shim.hide = this.hideAction;
32035 if (this.buttons) {
32036 var bts= this.buttons;
32038 Roo.each(bts, function(b) {
32047 * Fires when a key is pressed
32048 * @param {Roo.BasicDialog} this
32049 * @param {Roo.EventObject} e
32054 * Fires when this dialog is moved by the user.
32055 * @param {Roo.BasicDialog} this
32056 * @param {Number} x The new page X
32057 * @param {Number} y The new page Y
32062 * Fires when this dialog is resized by the user.
32063 * @param {Roo.BasicDialog} this
32064 * @param {Number} width The new width
32065 * @param {Number} height The new height
32069 * @event beforehide
32070 * Fires before this dialog is hidden.
32071 * @param {Roo.BasicDialog} this
32073 "beforehide" : true,
32076 * Fires when this dialog is hidden.
32077 * @param {Roo.BasicDialog} this
32081 * @event beforeshow
32082 * Fires before this dialog is shown.
32083 * @param {Roo.BasicDialog} this
32085 "beforeshow" : true,
32088 * Fires when this dialog is shown.
32089 * @param {Roo.BasicDialog} this
32093 el.on("keydown", this.onKeyDown, this);
32094 el.on("mousedown", this.toFront, this);
32095 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32097 Roo.DialogManager.register(this);
32098 Roo.BasicDialog.superclass.constructor.call(this);
32101 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32102 shadowOffset: Roo.isIE ? 6 : 5,
32105 minButtonWidth: 75,
32106 defaultButton: null,
32107 buttonAlign: "right",
32112 * Sets the dialog title text
32113 * @param {String} text The title text to display
32114 * @return {Roo.BasicDialog} this
32116 setTitle : function(text){
32117 this.header.update(text);
32122 closeClick : function(){
32127 collapseClick : function(){
32128 this[this.collapsed ? "expand" : "collapse"]();
32132 * Collapses the dialog to its minimized state (only the title bar is visible).
32133 * Equivalent to the user clicking the collapse dialog button.
32135 collapse : function(){
32136 if(!this.collapsed){
32137 this.collapsed = true;
32138 this.el.addClass("x-dlg-collapsed");
32139 this.restoreHeight = this.el.getHeight();
32140 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32145 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32146 * clicking the expand dialog button.
32148 expand : function(){
32149 if(this.collapsed){
32150 this.collapsed = false;
32151 this.el.removeClass("x-dlg-collapsed");
32152 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32157 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32158 * @return {Roo.TabPanel} The tabs component
32160 initTabs : function(){
32161 var tabs = this.getTabs();
32162 while(tabs.getTab(0)){
32165 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32167 tabs.addTab(Roo.id(dom), dom.title);
32175 beforeResize : function(){
32176 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32180 onResize : function(){
32181 this.refreshSize();
32182 this.syncBodyHeight();
32183 this.adjustAssets();
32185 this.fireEvent("resize", this, this.size.width, this.size.height);
32189 onKeyDown : function(e){
32190 if(this.isVisible()){
32191 this.fireEvent("keydown", this, e);
32196 * Resizes the dialog.
32197 * @param {Number} width
32198 * @param {Number} height
32199 * @return {Roo.BasicDialog} this
32201 resizeTo : function(width, height){
32202 this.el.setSize(width, height);
32203 this.size = {width: width, height: height};
32204 this.syncBodyHeight();
32205 if(this.fixedcenter){
32208 if(this.isVisible()){
32209 this.constrainXY();
32210 this.adjustAssets();
32212 this.fireEvent("resize", this, width, height);
32218 * Resizes the dialog to fit the specified content size.
32219 * @param {Number} width
32220 * @param {Number} height
32221 * @return {Roo.BasicDialog} this
32223 setContentSize : function(w, h){
32224 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32225 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32226 //if(!this.el.isBorderBox()){
32227 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32228 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32231 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32232 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32234 this.resizeTo(w, h);
32239 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32240 * executed in response to a particular key being pressed while the dialog is active.
32241 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32242 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32243 * @param {Function} fn The function to call
32244 * @param {Object} scope (optional) The scope of the function
32245 * @return {Roo.BasicDialog} this
32247 addKeyListener : function(key, fn, scope){
32248 var keyCode, shift, ctrl, alt;
32249 if(typeof key == "object" && !(key instanceof Array)){
32250 keyCode = key["key"];
32251 shift = key["shift"];
32252 ctrl = key["ctrl"];
32257 var handler = function(dlg, e){
32258 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32259 var k = e.getKey();
32260 if(keyCode instanceof Array){
32261 for(var i = 0, len = keyCode.length; i < len; i++){
32262 if(keyCode[i] == k){
32263 fn.call(scope || window, dlg, k, e);
32269 fn.call(scope || window, dlg, k, e);
32274 this.on("keydown", handler);
32279 * Returns the TabPanel component (creates it if it doesn't exist).
32280 * Note: If you wish to simply check for the existence of tabs without creating them,
32281 * check for a null 'tabs' property.
32282 * @return {Roo.TabPanel} The tabs component
32284 getTabs : function(){
32286 this.el.addClass("x-dlg-auto-tabs");
32287 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32288 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32294 * Adds a button to the footer section of the dialog.
32295 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32296 * object or a valid Roo.DomHelper element config
32297 * @param {Function} handler The function called when the button is clicked
32298 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32299 * @return {Roo.Button} The new button
32301 addButton : function(config, handler, scope){
32302 var dh = Roo.DomHelper;
32304 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32306 if(!this.btnContainer){
32307 var tb = this.footer.createChild({
32309 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32310 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32312 this.btnContainer = tb.firstChild.firstChild.firstChild;
32317 minWidth: this.minButtonWidth,
32320 if(typeof config == "string"){
32321 bconfig.text = config;
32324 bconfig.dhconfig = config;
32326 Roo.apply(bconfig, config);
32330 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32331 bconfig.position = Math.max(0, bconfig.position);
32332 fc = this.btnContainer.childNodes[bconfig.position];
32335 var btn = new Roo.Button(
32337 this.btnContainer.insertBefore(document.createElement("td"),fc)
32338 : this.btnContainer.appendChild(document.createElement("td")),
32339 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32342 this.syncBodyHeight();
32345 * Array of all the buttons that have been added to this dialog via addButton
32350 this.buttons.push(btn);
32355 * Sets the default button to be focused when the dialog is displayed.
32356 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32357 * @return {Roo.BasicDialog} this
32359 setDefaultButton : function(btn){
32360 this.defaultButton = btn;
32365 getHeaderFooterHeight : function(safe){
32368 height += this.header.getHeight();
32371 var fm = this.footer.getMargins();
32372 height += (this.footer.getHeight()+fm.top+fm.bottom);
32374 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32375 height += this.centerBg.getPadding("tb");
32380 syncBodyHeight : function()
32382 var bd = this.body, // the text
32383 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32385 var height = this.size.height - this.getHeaderFooterHeight(false);
32386 bd.setHeight(height-bd.getMargins("tb"));
32387 var hh = this.header.getHeight();
32388 var h = this.size.height-hh;
32391 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32392 bw.setHeight(h-cb.getPadding("tb"));
32394 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32395 bd.setWidth(bw.getWidth(true));
32397 this.tabs.syncHeight();
32399 this.tabs.el.repaint();
32405 * Restores the previous state of the dialog if Roo.state is configured.
32406 * @return {Roo.BasicDialog} this
32408 restoreState : function(){
32409 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32410 if(box && box.width){
32411 this.xy = [box.x, box.y];
32412 this.resizeTo(box.width, box.height);
32418 beforeShow : function(){
32420 if(this.fixedcenter){
32421 this.xy = this.el.getCenterXY(true);
32424 Roo.get(document.body).addClass("x-body-masked");
32425 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32428 this.constrainXY();
32432 animShow : function(){
32433 var b = Roo.get(this.animateTarget).getBox();
32434 this.proxy.setSize(b.width, b.height);
32435 this.proxy.setLocation(b.x, b.y);
32437 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32438 true, .35, this.showEl.createDelegate(this));
32442 * Shows the dialog.
32443 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32444 * @return {Roo.BasicDialog} this
32446 show : function(animateTarget){
32447 if (this.fireEvent("beforeshow", this) === false){
32450 if(this.syncHeightBeforeShow){
32451 this.syncBodyHeight();
32452 }else if(this.firstShow){
32453 this.firstShow = false;
32454 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32456 this.animateTarget = animateTarget || this.animateTarget;
32457 if(!this.el.isVisible()){
32459 if(this.animateTarget && Roo.get(this.animateTarget)){
32469 showEl : function(){
32471 this.el.setXY(this.xy);
32473 this.adjustAssets(true);
32476 // IE peekaboo bug - fix found by Dave Fenwick
32480 this.fireEvent("show", this);
32484 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32485 * dialog itself will receive focus.
32487 focus : function(){
32488 if(this.defaultButton){
32489 this.defaultButton.focus();
32491 this.focusEl.focus();
32496 constrainXY : function(){
32497 if(this.constraintoviewport !== false){
32498 if(!this.viewSize){
32499 if(this.container){
32500 var s = this.container.getSize();
32501 this.viewSize = [s.width, s.height];
32503 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32506 var s = Roo.get(this.container||document).getScroll();
32508 var x = this.xy[0], y = this.xy[1];
32509 var w = this.size.width, h = this.size.height;
32510 var vw = this.viewSize[0], vh = this.viewSize[1];
32511 // only move it if it needs it
32513 // first validate right/bottom
32514 if(x + w > vw+s.left){
32518 if(y + h > vh+s.top){
32522 // then make sure top/left isn't negative
32534 if(this.isVisible()){
32535 this.el.setLocation(x, y);
32536 this.adjustAssets();
32543 onDrag : function(){
32544 if(!this.proxyDrag){
32545 this.xy = this.el.getXY();
32546 this.adjustAssets();
32551 adjustAssets : function(doShow){
32552 var x = this.xy[0], y = this.xy[1];
32553 var w = this.size.width, h = this.size.height;
32554 if(doShow === true){
32556 this.shadow.show(this.el);
32562 if(this.shadow && this.shadow.isVisible()){
32563 this.shadow.show(this.el);
32565 if(this.shim && this.shim.isVisible()){
32566 this.shim.setBounds(x, y, w, h);
32571 adjustViewport : function(w, h){
32573 w = Roo.lib.Dom.getViewWidth();
32574 h = Roo.lib.Dom.getViewHeight();
32577 this.viewSize = [w, h];
32578 if(this.modal && this.mask.isVisible()){
32579 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32580 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32582 if(this.isVisible()){
32583 this.constrainXY();
32588 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32589 * shadow, proxy, mask, etc.) Also removes all event listeners.
32590 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32592 destroy : function(removeEl){
32593 if(this.isVisible()){
32594 this.animateTarget = null;
32597 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32599 this.tabs.destroy(removeEl);
32612 for(var i = 0, len = this.buttons.length; i < len; i++){
32613 this.buttons[i].destroy();
32616 this.el.removeAllListeners();
32617 if(removeEl === true){
32618 this.el.update("");
32621 Roo.DialogManager.unregister(this);
32625 startMove : function(){
32626 if(this.proxyDrag){
32629 if(this.constraintoviewport !== false){
32630 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32635 endMove : function(){
32636 if(!this.proxyDrag){
32637 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32639 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32642 this.refreshSize();
32643 this.adjustAssets();
32645 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32649 * Brings this dialog to the front of any other visible dialogs
32650 * @return {Roo.BasicDialog} this
32652 toFront : function(){
32653 Roo.DialogManager.bringToFront(this);
32658 * Sends this dialog to the back (under) of any other visible dialogs
32659 * @return {Roo.BasicDialog} this
32661 toBack : function(){
32662 Roo.DialogManager.sendToBack(this);
32667 * Centers this dialog in the viewport
32668 * @return {Roo.BasicDialog} this
32670 center : function(){
32671 var xy = this.el.getCenterXY(true);
32672 this.moveTo(xy[0], xy[1]);
32677 * Moves the dialog's top-left corner to the specified point
32678 * @param {Number} x
32679 * @param {Number} y
32680 * @return {Roo.BasicDialog} this
32682 moveTo : function(x, y){
32684 if(this.isVisible()){
32685 this.el.setXY(this.xy);
32686 this.adjustAssets();
32692 * Aligns the dialog to the specified element
32693 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32694 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32695 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32696 * @return {Roo.BasicDialog} this
32698 alignTo : function(element, position, offsets){
32699 this.xy = this.el.getAlignToXY(element, position, offsets);
32700 if(this.isVisible()){
32701 this.el.setXY(this.xy);
32702 this.adjustAssets();
32708 * Anchors an element to another element and realigns it when the window is resized.
32709 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32710 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32711 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32712 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32713 * is a number, it is used as the buffer delay (defaults to 50ms).
32714 * @return {Roo.BasicDialog} this
32716 anchorTo : function(el, alignment, offsets, monitorScroll){
32717 var action = function(){
32718 this.alignTo(el, alignment, offsets);
32720 Roo.EventManager.onWindowResize(action, this);
32721 var tm = typeof monitorScroll;
32722 if(tm != 'undefined'){
32723 Roo.EventManager.on(window, 'scroll', action, this,
32724 {buffer: tm == 'number' ? monitorScroll : 50});
32731 * Returns true if the dialog is visible
32732 * @return {Boolean}
32734 isVisible : function(){
32735 return this.el.isVisible();
32739 animHide : function(callback){
32740 var b = Roo.get(this.animateTarget).getBox();
32742 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32744 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32745 this.hideEl.createDelegate(this, [callback]));
32749 * Hides the dialog.
32750 * @param {Function} callback (optional) Function to call when the dialog is hidden
32751 * @return {Roo.BasicDialog} this
32753 hide : function(callback){
32754 if (this.fireEvent("beforehide", this) === false){
32758 this.shadow.hide();
32763 // sometimes animateTarget seems to get set.. causing problems...
32764 // this just double checks..
32765 if(this.animateTarget && Roo.get(this.animateTarget)) {
32766 this.animHide(callback);
32769 this.hideEl(callback);
32775 hideEl : function(callback){
32779 Roo.get(document.body).removeClass("x-body-masked");
32781 this.fireEvent("hide", this);
32782 if(typeof callback == "function"){
32788 hideAction : function(){
32789 this.setLeft("-10000px");
32790 this.setTop("-10000px");
32791 this.setStyle("visibility", "hidden");
32795 refreshSize : function(){
32796 this.size = this.el.getSize();
32797 this.xy = this.el.getXY();
32798 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32802 // z-index is managed by the DialogManager and may be overwritten at any time
32803 setZIndex : function(index){
32805 this.mask.setStyle("z-index", index);
32808 this.shim.setStyle("z-index", ++index);
32811 this.shadow.setZIndex(++index);
32813 this.el.setStyle("z-index", ++index);
32815 this.proxy.setStyle("z-index", ++index);
32818 this.resizer.proxy.setStyle("z-index", ++index);
32821 this.lastZIndex = index;
32825 * Returns the element for this dialog
32826 * @return {Roo.Element} The underlying dialog Element
32828 getEl : function(){
32834 * @class Roo.DialogManager
32835 * Provides global access to BasicDialogs that have been created and
32836 * support for z-indexing (layering) multiple open dialogs.
32838 Roo.DialogManager = function(){
32840 var accessList = [];
32844 var sortDialogs = function(d1, d2){
32845 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32849 var orderDialogs = function(){
32850 accessList.sort(sortDialogs);
32851 var seed = Roo.DialogManager.zseed;
32852 for(var i = 0, len = accessList.length; i < len; i++){
32853 var dlg = accessList[i];
32855 dlg.setZIndex(seed + (i*10));
32862 * The starting z-index for BasicDialogs (defaults to 9000)
32863 * @type Number The z-index value
32868 register : function(dlg){
32869 list[dlg.id] = dlg;
32870 accessList.push(dlg);
32874 unregister : function(dlg){
32875 delete list[dlg.id];
32878 if(!accessList.indexOf){
32879 for( i = 0, len = accessList.length; i < len; i++){
32880 if(accessList[i] == dlg){
32881 accessList.splice(i, 1);
32886 i = accessList.indexOf(dlg);
32888 accessList.splice(i, 1);
32894 * Gets a registered dialog by id
32895 * @param {String/Object} id The id of the dialog or a dialog
32896 * @return {Roo.BasicDialog} this
32898 get : function(id){
32899 return typeof id == "object" ? id : list[id];
32903 * Brings the specified dialog to the front
32904 * @param {String/Object} dlg The id of the dialog or a dialog
32905 * @return {Roo.BasicDialog} this
32907 bringToFront : function(dlg){
32908 dlg = this.get(dlg);
32911 dlg._lastAccess = new Date().getTime();
32918 * Sends the specified dialog to the back
32919 * @param {String/Object} dlg The id of the dialog or a dialog
32920 * @return {Roo.BasicDialog} this
32922 sendToBack : function(dlg){
32923 dlg = this.get(dlg);
32924 dlg._lastAccess = -(new Date().getTime());
32930 * Hides all dialogs
32932 hideAll : function(){
32933 for(var id in list){
32934 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32943 * @class Roo.LayoutDialog
32944 * @extends Roo.BasicDialog
32945 * Dialog which provides adjustments for working with a layout in a Dialog.
32946 * Add your necessary layout config options to the dialog's config.<br>
32947 * Example usage (including a nested layout):
32950 dialog = new Roo.LayoutDialog("download-dlg", {
32959 // layout config merges with the dialog config
32961 tabPosition: "top",
32962 alwaysShowTabs: true
32965 dialog.addKeyListener(27, dialog.hide, dialog);
32966 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32967 dialog.addButton("Build It!", this.getDownload, this);
32969 // we can even add nested layouts
32970 var innerLayout = new Roo.BorderLayout("dl-inner", {
32980 innerLayout.beginUpdate();
32981 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32982 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32983 innerLayout.endUpdate(true);
32985 var layout = dialog.getLayout();
32986 layout.beginUpdate();
32987 layout.add("center", new Roo.ContentPanel("standard-panel",
32988 {title: "Download the Source", fitToFrame:true}));
32989 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32990 {title: "Build your own roo.js"}));
32991 layout.getRegion("center").showPanel(sp);
32992 layout.endUpdate();
32996 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32997 * @param {Object} config configuration options
32999 Roo.LayoutDialog = function(el, cfg){
33002 if (typeof(cfg) == 'undefined') {
33003 config = Roo.apply({}, el);
33004 // not sure why we use documentElement here.. - it should always be body.
33005 // IE7 borks horribly if we use documentElement.
33006 // webkit also does not like documentElement - it creates a body element...
33007 el = Roo.get( document.body || document.documentElement ).createChild();
33008 //config.autoCreate = true;
33012 config.autoTabs = false;
33013 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33014 this.body.setStyle({overflow:"hidden", position:"relative"});
33015 this.layout = new Roo.BorderLayout(this.body.dom, config);
33016 this.layout.monitorWindowResize = false;
33017 this.el.addClass("x-dlg-auto-layout");
33018 // fix case when center region overwrites center function
33019 this.center = Roo.BasicDialog.prototype.center;
33020 this.on("show", this.layout.layout, this.layout, true);
33021 if (config.items) {
33022 var xitems = config.items;
33023 delete config.items;
33024 Roo.each(xitems, this.addxtype, this);
33029 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33031 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33034 endUpdate : function(){
33035 this.layout.endUpdate();
33039 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33042 beginUpdate : function(){
33043 this.layout.beginUpdate();
33047 * Get the BorderLayout for this dialog
33048 * @return {Roo.BorderLayout}
33050 getLayout : function(){
33051 return this.layout;
33054 showEl : function(){
33055 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33057 this.layout.layout();
33062 // Use the syncHeightBeforeShow config option to control this automatically
33063 syncBodyHeight : function(){
33064 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33065 if(this.layout){this.layout.layout();}
33069 * Add an xtype element (actually adds to the layout.)
33070 * @return {Object} xdata xtype object data.
33073 addxtype : function(c) {
33074 return this.layout.addxtype(c);
33078 * Ext JS Library 1.1.1
33079 * Copyright(c) 2006-2007, Ext JS, LLC.
33081 * Originally Released Under LGPL - original licence link has changed is not relivant.
33084 * <script type="text/javascript">
33088 * @class Roo.MessageBox
33089 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33093 Roo.Msg.alert('Status', 'Changes saved successfully.');
33095 // Prompt for user data:
33096 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33098 // process text value...
33102 // Show a dialog using config options:
33104 title:'Save Changes?',
33105 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33106 buttons: Roo.Msg.YESNOCANCEL,
33113 Roo.MessageBox = function(){
33114 var dlg, opt, mask, waitTimer;
33115 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33116 var buttons, activeTextEl, bwidth;
33119 var handleButton = function(button){
33121 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33125 var handleHide = function(){
33126 if(opt && opt.cls){
33127 dlg.el.removeClass(opt.cls);
33130 Roo.TaskMgr.stop(waitTimer);
33136 var updateButtons = function(b){
33139 buttons["ok"].hide();
33140 buttons["cancel"].hide();
33141 buttons["yes"].hide();
33142 buttons["no"].hide();
33143 dlg.footer.dom.style.display = 'none';
33146 dlg.footer.dom.style.display = '';
33147 for(var k in buttons){
33148 if(typeof buttons[k] != "function"){
33151 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33152 width += buttons[k].el.getWidth()+15;
33162 var handleEsc = function(d, k, e){
33163 if(opt && opt.closable !== false){
33173 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33174 * @return {Roo.BasicDialog} The BasicDialog element
33176 getDialog : function(){
33178 dlg = new Roo.BasicDialog("x-msg-box", {
33183 constraintoviewport:false,
33185 collapsible : false,
33188 width:400, height:100,
33189 buttonAlign:"center",
33190 closeClick : function(){
33191 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33192 handleButton("no");
33194 handleButton("cancel");
33198 dlg.on("hide", handleHide);
33200 dlg.addKeyListener(27, handleEsc);
33202 var bt = this.buttonText;
33203 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33204 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33205 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33206 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33207 bodyEl = dlg.body.createChild({
33209 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>'
33211 msgEl = bodyEl.dom.firstChild;
33212 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33213 textboxEl.enableDisplayMode();
33214 textboxEl.addKeyListener([10,13], function(){
33215 if(dlg.isVisible() && opt && opt.buttons){
33216 if(opt.buttons.ok){
33217 handleButton("ok");
33218 }else if(opt.buttons.yes){
33219 handleButton("yes");
33223 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33224 textareaEl.enableDisplayMode();
33225 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33226 progressEl.enableDisplayMode();
33227 var pf = progressEl.dom.firstChild;
33229 pp = Roo.get(pf.firstChild);
33230 pp.setHeight(pf.offsetHeight);
33238 * Updates the message box body text
33239 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33240 * the XHTML-compliant non-breaking space character '&#160;')
33241 * @return {Roo.MessageBox} This message box
33243 updateText : function(text){
33244 if(!dlg.isVisible() && !opt.width){
33245 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33247 msgEl.innerHTML = text || ' ';
33249 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33250 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33252 Math.min(opt.width || cw , this.maxWidth),
33253 Math.max(opt.minWidth || this.minWidth, bwidth)
33256 activeTextEl.setWidth(w);
33258 if(dlg.isVisible()){
33259 dlg.fixedcenter = false;
33261 // to big, make it scroll. = But as usual stupid IE does not support
33264 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33265 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33266 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33268 bodyEl.dom.style.height = '';
33269 bodyEl.dom.style.overflowY = '';
33272 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33274 bodyEl.dom.style.overflowX = '';
33277 dlg.setContentSize(w, bodyEl.getHeight());
33278 if(dlg.isVisible()){
33279 dlg.fixedcenter = true;
33285 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33286 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33287 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33288 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33289 * @return {Roo.MessageBox} This message box
33291 updateProgress : function(value, text){
33293 this.updateText(text);
33295 if (pp) { // weird bug on my firefox - for some reason this is not defined
33296 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33302 * Returns true if the message box is currently displayed
33303 * @return {Boolean} True if the message box is visible, else false
33305 isVisible : function(){
33306 return dlg && dlg.isVisible();
33310 * Hides the message box if it is displayed
33313 if(this.isVisible()){
33319 * Displays a new message box, or reinitializes an existing message box, based on the config options
33320 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33321 * The following config object properties are supported:
33323 Property Type Description
33324 ---------- --------------- ------------------------------------------------------------------------------------
33325 animEl String/Element An id or Element from which the message box should animate as it opens and
33326 closes (defaults to undefined)
33327 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33328 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33329 closable Boolean False to hide the top-right close button (defaults to true). Note that
33330 progress and wait dialogs will ignore this property and always hide the
33331 close button as they can only be closed programmatically.
33332 cls String A custom CSS class to apply to the message box element
33333 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33334 displayed (defaults to 75)
33335 fn Function A callback function to execute after closing the dialog. The arguments to the
33336 function will be btn (the name of the button that was clicked, if applicable,
33337 e.g. "ok"), and text (the value of the active text field, if applicable).
33338 Progress and wait dialogs will ignore this option since they do not respond to
33339 user actions and can only be closed programmatically, so any required function
33340 should be called by the same code after it closes the dialog.
33341 icon String A CSS class that provides a background image to be used as an icon for
33342 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33343 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33344 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33345 modal Boolean False to allow user interaction with the page while the message box is
33346 displayed (defaults to true)
33347 msg String A string that will replace the existing message box body text (defaults
33348 to the XHTML-compliant non-breaking space character ' ')
33349 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33350 progress Boolean True to display a progress bar (defaults to false)
33351 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33352 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33353 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33354 title String The title text
33355 value String The string value to set into the active textbox element if displayed
33356 wait Boolean True to display a progress bar (defaults to false)
33357 width Number The width of the dialog in pixels
33364 msg: 'Please enter your address:',
33366 buttons: Roo.MessageBox.OKCANCEL,
33369 animEl: 'addAddressBtn'
33372 * @param {Object} config Configuration options
33373 * @return {Roo.MessageBox} This message box
33375 show : function(options)
33378 // this causes nightmares if you show one dialog after another
33379 // especially on callbacks..
33381 if(this.isVisible()){
33384 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33385 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33386 Roo.log("New Dialog Message:" + options.msg )
33387 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33388 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33391 var d = this.getDialog();
33393 d.setTitle(opt.title || " ");
33394 d.close.setDisplayed(opt.closable !== false);
33395 activeTextEl = textboxEl;
33396 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33401 textareaEl.setHeight(typeof opt.multiline == "number" ?
33402 opt.multiline : this.defaultTextHeight);
33403 activeTextEl = textareaEl;
33412 progressEl.setDisplayed(opt.progress === true);
33413 this.updateProgress(0);
33414 activeTextEl.dom.value = opt.value || "";
33416 dlg.setDefaultButton(activeTextEl);
33418 var bs = opt.buttons;
33421 db = buttons["ok"];
33422 }else if(bs && bs.yes){
33423 db = buttons["yes"];
33425 dlg.setDefaultButton(db);
33427 bwidth = updateButtons(opt.buttons);
33428 this.updateText(opt.msg);
33430 d.el.addClass(opt.cls);
33432 d.proxyDrag = opt.proxyDrag === true;
33433 d.modal = opt.modal !== false;
33434 d.mask = opt.modal !== false ? mask : false;
33435 if(!d.isVisible()){
33436 // force it to the end of the z-index stack so it gets a cursor in FF
33437 document.body.appendChild(dlg.el.dom);
33438 d.animateTarget = null;
33439 d.show(options.animEl);
33445 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33446 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33447 * and closing the message box when the process is complete.
33448 * @param {String} title The title bar text
33449 * @param {String} msg The message box body text
33450 * @return {Roo.MessageBox} This message box
33452 progress : function(title, msg){
33459 minWidth: this.minProgressWidth,
33466 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33467 * If a callback function is passed it will be called after the user clicks the button, and the
33468 * id of the button that was clicked will be passed as the only parameter to the callback
33469 * (could also be the top-right close button).
33470 * @param {String} title The title bar text
33471 * @param {String} msg The message box body text
33472 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33473 * @param {Object} scope (optional) The scope of the callback function
33474 * @return {Roo.MessageBox} This message box
33476 alert : function(title, msg, fn, scope){
33489 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33490 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33491 * You are responsible for closing the message box when the process is complete.
33492 * @param {String} msg The message box body text
33493 * @param {String} title (optional) The title bar text
33494 * @return {Roo.MessageBox} This message box
33496 wait : function(msg, title){
33507 waitTimer = Roo.TaskMgr.start({
33509 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33517 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33518 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33519 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33520 * @param {String} title The title bar text
33521 * @param {String} msg The message box body text
33522 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33523 * @param {Object} scope (optional) The scope of the callback function
33524 * @return {Roo.MessageBox} This message box
33526 confirm : function(title, msg, fn, scope){
33530 buttons: this.YESNO,
33539 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33540 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33541 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33542 * (could also be the top-right close button) and the text that was entered will be passed as the two
33543 * parameters to the callback.
33544 * @param {String} title The title bar text
33545 * @param {String} msg The message box body text
33546 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33547 * @param {Object} scope (optional) The scope of the callback function
33548 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33549 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33550 * @return {Roo.MessageBox} This message box
33552 prompt : function(title, msg, fn, scope, multiline){
33556 buttons: this.OKCANCEL,
33561 multiline: multiline,
33568 * Button config that displays a single OK button
33573 * Button config that displays Yes and No buttons
33576 YESNO : {yes:true, no:true},
33578 * Button config that displays OK and Cancel buttons
33581 OKCANCEL : {ok:true, cancel:true},
33583 * Button config that displays Yes, No and Cancel buttons
33586 YESNOCANCEL : {yes:true, no:true, cancel:true},
33589 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33592 defaultTextHeight : 75,
33594 * The maximum width in pixels of the message box (defaults to 600)
33599 * The minimum width in pixels of the message box (defaults to 100)
33604 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33605 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33608 minProgressWidth : 250,
33610 * An object containing the default button text strings that can be overriden for localized language support.
33611 * Supported properties are: ok, cancel, yes and no.
33612 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33625 * Shorthand for {@link Roo.MessageBox}
33627 Roo.Msg = Roo.MessageBox;/*
33629 * Ext JS Library 1.1.1
33630 * Copyright(c) 2006-2007, Ext JS, LLC.
33632 * Originally Released Under LGPL - original licence link has changed is not relivant.
33635 * <script type="text/javascript">
33638 * @class Roo.QuickTips
33639 * Provides attractive and customizable tooltips for any element.
33642 Roo.QuickTips = function(){
33643 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33644 var ce, bd, xy, dd;
33645 var visible = false, disabled = true, inited = false;
33646 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33648 var onOver = function(e){
33652 var t = e.getTarget();
33653 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33656 if(ce && t == ce.el){
33657 clearTimeout(hideProc);
33660 if(t && tagEls[t.id]){
33661 tagEls[t.id].el = t;
33662 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33665 var ttp, et = Roo.fly(t);
33666 var ns = cfg.namespace;
33667 if(tm.interceptTitles && t.title){
33670 t.removeAttribute("title");
33671 e.preventDefault();
33673 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33676 showProc = show.defer(tm.showDelay, tm, [{
33678 text: ttp.replace(/\\n/g,'<br/>'),
33679 width: et.getAttributeNS(ns, cfg.width),
33680 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33681 title: et.getAttributeNS(ns, cfg.title),
33682 cls: et.getAttributeNS(ns, cfg.cls)
33687 var onOut = function(e){
33688 clearTimeout(showProc);
33689 var t = e.getTarget();
33690 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33691 hideProc = setTimeout(hide, tm.hideDelay);
33695 var onMove = function(e){
33701 if(tm.trackMouse && ce){
33706 var onDown = function(e){
33707 clearTimeout(showProc);
33708 clearTimeout(hideProc);
33710 if(tm.hideOnClick){
33713 tm.enable.defer(100, tm);
33718 var getPad = function(){
33719 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33722 var show = function(o){
33726 clearTimeout(dismissProc);
33728 if(removeCls){ // in case manually hidden
33729 el.removeClass(removeCls);
33733 el.addClass(ce.cls);
33734 removeCls = ce.cls;
33737 tipTitle.update(ce.title);
33740 tipTitle.update('');
33743 el.dom.style.width = tm.maxWidth+'px';
33744 //tipBody.dom.style.width = '';
33745 tipBodyText.update(o.text);
33746 var p = getPad(), w = ce.width;
33748 var td = tipBodyText.dom;
33749 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33750 if(aw > tm.maxWidth){
33752 }else if(aw < tm.minWidth){
33758 //tipBody.setWidth(w);
33759 el.setWidth(parseInt(w, 10) + p);
33760 if(ce.autoHide === false){
33761 close.setDisplayed(true);
33766 close.setDisplayed(false);
33772 el.avoidY = xy[1]-18;
33777 el.setStyle("visibility", "visible");
33778 el.fadeIn({callback: afterShow});
33784 var afterShow = function(){
33788 if(tm.autoDismiss && ce.autoHide !== false){
33789 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33794 var hide = function(noanim){
33795 clearTimeout(dismissProc);
33796 clearTimeout(hideProc);
33798 if(el.isVisible()){
33800 if(noanim !== true && tm.animate){
33801 el.fadeOut({callback: afterHide});
33808 var afterHide = function(){
33811 el.removeClass(removeCls);
33818 * @cfg {Number} minWidth
33819 * The minimum width of the quick tip (defaults to 40)
33823 * @cfg {Number} maxWidth
33824 * The maximum width of the quick tip (defaults to 300)
33828 * @cfg {Boolean} interceptTitles
33829 * True to automatically use the element's DOM title value if available (defaults to false)
33831 interceptTitles : false,
33833 * @cfg {Boolean} trackMouse
33834 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33836 trackMouse : false,
33838 * @cfg {Boolean} hideOnClick
33839 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33841 hideOnClick : true,
33843 * @cfg {Number} showDelay
33844 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33848 * @cfg {Number} hideDelay
33849 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33853 * @cfg {Boolean} autoHide
33854 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33855 * Used in conjunction with hideDelay.
33860 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33861 * (defaults to true). Used in conjunction with autoDismissDelay.
33863 autoDismiss : true,
33866 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33868 autoDismissDelay : 5000,
33870 * @cfg {Boolean} animate
33871 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33876 * @cfg {String} title
33877 * Title text to display (defaults to ''). This can be any valid HTML markup.
33881 * @cfg {String} text
33882 * Body text to display (defaults to ''). This can be any valid HTML markup.
33886 * @cfg {String} cls
33887 * A CSS class to apply to the base quick tip element (defaults to '').
33891 * @cfg {Number} width
33892 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33893 * minWidth or maxWidth.
33898 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33899 * or display QuickTips in a page.
33902 tm = Roo.QuickTips;
33903 cfg = tm.tagConfig;
33905 if(!Roo.isReady){ // allow calling of init() before onReady
33906 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33909 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33910 el.fxDefaults = {stopFx: true};
33911 // maximum custom styling
33912 //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>');
33913 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>');
33914 tipTitle = el.child('h3');
33915 tipTitle.enableDisplayMode("block");
33916 tipBody = el.child('div.x-tip-bd');
33917 tipBodyText = el.child('div.x-tip-bd-inner');
33918 //bdLeft = el.child('div.x-tip-bd-left');
33919 //bdRight = el.child('div.x-tip-bd-right');
33920 close = el.child('div.x-tip-close');
33921 close.enableDisplayMode("block");
33922 close.on("click", hide);
33923 var d = Roo.get(document);
33924 d.on("mousedown", onDown);
33925 d.on("mouseover", onOver);
33926 d.on("mouseout", onOut);
33927 d.on("mousemove", onMove);
33928 esc = d.addKeyListener(27, hide);
33931 dd = el.initDD("default", null, {
33932 onDrag : function(){
33936 dd.setHandleElId(tipTitle.id);
33945 * Configures a new quick tip instance and assigns it to a target element. The following config options
33948 Property Type Description
33949 ---------- --------------------- ------------------------------------------------------------------------
33950 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33952 * @param {Object} config The config object
33954 register : function(config){
33955 var cs = config instanceof Array ? config : arguments;
33956 for(var i = 0, len = cs.length; i < len; i++) {
33958 var target = c.target;
33960 if(target instanceof Array){
33961 for(var j = 0, jlen = target.length; j < jlen; j++){
33962 tagEls[target[j]] = c;
33965 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33972 * Removes this quick tip from its element and destroys it.
33973 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33975 unregister : function(el){
33976 delete tagEls[Roo.id(el)];
33980 * Enable this quick tip.
33982 enable : function(){
33983 if(inited && disabled){
33985 if(locks.length < 1){
33992 * Disable this quick tip.
33994 disable : function(){
33996 clearTimeout(showProc);
33997 clearTimeout(hideProc);
33998 clearTimeout(dismissProc);
34006 * Returns true if the quick tip is enabled, else false.
34008 isEnabled : function(){
34014 namespace : "roo", // was ext?? this may break..
34015 alt_namespace : "ext",
34016 attribute : "qtip",
34026 // backwards compat
34027 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34029 * Ext JS Library 1.1.1
34030 * Copyright(c) 2006-2007, Ext JS, LLC.
34032 * Originally Released Under LGPL - original licence link has changed is not relivant.
34035 * <script type="text/javascript">
34040 * @class Roo.tree.TreePanel
34041 * @extends Roo.data.Tree
34043 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34044 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34045 * @cfg {Boolean} enableDD true to enable drag and drop
34046 * @cfg {Boolean} enableDrag true to enable just drag
34047 * @cfg {Boolean} enableDrop true to enable just drop
34048 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34049 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34050 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34051 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34052 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34053 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34054 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34055 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34056 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34057 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34058 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34059 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34060 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34061 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34062 * @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>
34063 * @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>
34066 * @param {String/HTMLElement/Element} el The container element
34067 * @param {Object} config
34069 Roo.tree.TreePanel = function(el, config){
34071 var loader = false;
34073 root = config.root;
34074 delete config.root;
34076 if (config.loader) {
34077 loader = config.loader;
34078 delete config.loader;
34081 Roo.apply(this, config);
34082 Roo.tree.TreePanel.superclass.constructor.call(this);
34083 this.el = Roo.get(el);
34084 this.el.addClass('x-tree');
34085 //console.log(root);
34087 this.setRootNode( Roo.factory(root, Roo.tree));
34090 this.loader = Roo.factory(loader, Roo.tree);
34093 * Read-only. The id of the container element becomes this TreePanel's id.
34095 this.id = this.el.id;
34098 * @event beforeload
34099 * Fires before a node is loaded, return false to cancel
34100 * @param {Node} node The node being loaded
34102 "beforeload" : true,
34105 * Fires when a node is loaded
34106 * @param {Node} node The node that was loaded
34110 * @event textchange
34111 * Fires when the text for a node is changed
34112 * @param {Node} node The node
34113 * @param {String} text The new text
34114 * @param {String} oldText The old text
34116 "textchange" : true,
34118 * @event beforeexpand
34119 * Fires before a node is expanded, return false to cancel.
34120 * @param {Node} node The node
34121 * @param {Boolean} deep
34122 * @param {Boolean} anim
34124 "beforeexpand" : true,
34126 * @event beforecollapse
34127 * Fires before a node is collapsed, return false to cancel.
34128 * @param {Node} node The node
34129 * @param {Boolean} deep
34130 * @param {Boolean} anim
34132 "beforecollapse" : true,
34135 * Fires when a node is expanded
34136 * @param {Node} node The node
34140 * @event disabledchange
34141 * Fires when the disabled status of a node changes
34142 * @param {Node} node The node
34143 * @param {Boolean} disabled
34145 "disabledchange" : true,
34148 * Fires when a node is collapsed
34149 * @param {Node} node The node
34153 * @event beforeclick
34154 * Fires before click processing on a node. Return false to cancel the default action.
34155 * @param {Node} node The node
34156 * @param {Roo.EventObject} e The event object
34158 "beforeclick":true,
34160 * @event checkchange
34161 * Fires when a node with a checkbox's checked property changes
34162 * @param {Node} this This node
34163 * @param {Boolean} checked
34165 "checkchange":true,
34168 * Fires when a node is clicked
34169 * @param {Node} node The node
34170 * @param {Roo.EventObject} e The event object
34175 * Fires when a node is double clicked
34176 * @param {Node} node The node
34177 * @param {Roo.EventObject} e The event object
34181 * @event contextmenu
34182 * Fires when a node is right clicked
34183 * @param {Node} node The node
34184 * @param {Roo.EventObject} e The event object
34186 "contextmenu":true,
34188 * @event beforechildrenrendered
34189 * Fires right before the child nodes for a node are rendered
34190 * @param {Node} node The node
34192 "beforechildrenrendered":true,
34195 * Fires when a node starts being dragged
34196 * @param {Roo.tree.TreePanel} this
34197 * @param {Roo.tree.TreeNode} node
34198 * @param {event} e The raw browser event
34200 "startdrag" : true,
34203 * Fires when a drag operation is complete
34204 * @param {Roo.tree.TreePanel} this
34205 * @param {Roo.tree.TreeNode} node
34206 * @param {event} e The raw browser event
34211 * Fires when a dragged node is dropped on a valid DD target
34212 * @param {Roo.tree.TreePanel} this
34213 * @param {Roo.tree.TreeNode} node
34214 * @param {DD} dd The dd it was dropped on
34215 * @param {event} e The raw browser event
34219 * @event beforenodedrop
34220 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34221 * passed to handlers has the following properties:<br />
34222 * <ul style="padding:5px;padding-left:16px;">
34223 * <li>tree - The TreePanel</li>
34224 * <li>target - The node being targeted for the drop</li>
34225 * <li>data - The drag data from the drag source</li>
34226 * <li>point - The point of the drop - append, above or below</li>
34227 * <li>source - The drag source</li>
34228 * <li>rawEvent - Raw mouse event</li>
34229 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34230 * to be inserted by setting them on this object.</li>
34231 * <li>cancel - Set this to true to cancel the drop.</li>
34233 * @param {Object} dropEvent
34235 "beforenodedrop" : true,
34238 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34239 * passed to handlers has the following properties:<br />
34240 * <ul style="padding:5px;padding-left:16px;">
34241 * <li>tree - The TreePanel</li>
34242 * <li>target - The node being targeted for the drop</li>
34243 * <li>data - The drag data from the drag source</li>
34244 * <li>point - The point of the drop - append, above or below</li>
34245 * <li>source - The drag source</li>
34246 * <li>rawEvent - Raw mouse event</li>
34247 * <li>dropNode - Dropped node(s).</li>
34249 * @param {Object} dropEvent
34253 * @event nodedragover
34254 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34255 * passed to handlers has the following properties:<br />
34256 * <ul style="padding:5px;padding-left:16px;">
34257 * <li>tree - The TreePanel</li>
34258 * <li>target - The node being targeted for the drop</li>
34259 * <li>data - The drag data from the drag source</li>
34260 * <li>point - The point of the drop - append, above or below</li>
34261 * <li>source - The drag source</li>
34262 * <li>rawEvent - Raw mouse event</li>
34263 * <li>dropNode - Drop node(s) provided by the source.</li>
34264 * <li>cancel - Set this to true to signal drop not allowed.</li>
34266 * @param {Object} dragOverEvent
34268 "nodedragover" : true
34271 if(this.singleExpand){
34272 this.on("beforeexpand", this.restrictExpand, this);
34275 this.editor.tree = this;
34276 this.editor = Roo.factory(this.editor, Roo.tree);
34279 if (this.selModel) {
34280 this.selModel = Roo.factory(this.selModel, Roo.tree);
34284 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34285 rootVisible : true,
34286 animate: Roo.enableFx,
34289 hlDrop : Roo.enableFx,
34293 rendererTip: false,
34295 restrictExpand : function(node){
34296 var p = node.parentNode;
34298 if(p.expandedChild && p.expandedChild.parentNode == p){
34299 p.expandedChild.collapse();
34301 p.expandedChild = node;
34305 // private override
34306 setRootNode : function(node){
34307 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34308 if(!this.rootVisible){
34309 node.ui = new Roo.tree.RootTreeNodeUI(node);
34315 * Returns the container element for this TreePanel
34317 getEl : function(){
34322 * Returns the default TreeLoader for this TreePanel
34324 getLoader : function(){
34325 return this.loader;
34331 expandAll : function(){
34332 this.root.expand(true);
34336 * Collapse all nodes
34338 collapseAll : function(){
34339 this.root.collapse(true);
34343 * Returns the selection model used by this TreePanel
34345 getSelectionModel : function(){
34346 if(!this.selModel){
34347 this.selModel = new Roo.tree.DefaultSelectionModel();
34349 return this.selModel;
34353 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34354 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34355 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34358 getChecked : function(a, startNode){
34359 startNode = startNode || this.root;
34361 var f = function(){
34362 if(this.attributes.checked){
34363 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34366 startNode.cascade(f);
34371 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34372 * @param {String} path
34373 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34374 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34375 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34377 expandPath : function(path, attr, callback){
34378 attr = attr || "id";
34379 var keys = path.split(this.pathSeparator);
34380 var curNode = this.root;
34381 if(curNode.attributes[attr] != keys[1]){ // invalid root
34383 callback(false, null);
34388 var f = function(){
34389 if(++index == keys.length){
34391 callback(true, curNode);
34395 var c = curNode.findChild(attr, keys[index]);
34398 callback(false, curNode);
34403 c.expand(false, false, f);
34405 curNode.expand(false, false, f);
34409 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34410 * @param {String} path
34411 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34412 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34413 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34415 selectPath : function(path, attr, callback){
34416 attr = attr || "id";
34417 var keys = path.split(this.pathSeparator);
34418 var v = keys.pop();
34419 if(keys.length > 0){
34420 var f = function(success, node){
34421 if(success && node){
34422 var n = node.findChild(attr, v);
34428 }else if(callback){
34429 callback(false, n);
34433 callback(false, n);
34437 this.expandPath(keys.join(this.pathSeparator), attr, f);
34439 this.root.select();
34441 callback(true, this.root);
34446 getTreeEl : function(){
34451 * Trigger rendering of this TreePanel
34453 render : function(){
34454 if (this.innerCt) {
34455 return this; // stop it rendering more than once!!
34458 this.innerCt = this.el.createChild({tag:"ul",
34459 cls:"x-tree-root-ct " +
34460 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34462 if(this.containerScroll){
34463 Roo.dd.ScrollManager.register(this.el);
34465 if((this.enableDD || this.enableDrop) && !this.dropZone){
34467 * The dropZone used by this tree if drop is enabled
34468 * @type Roo.tree.TreeDropZone
34470 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34471 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34474 if((this.enableDD || this.enableDrag) && !this.dragZone){
34476 * The dragZone used by this tree if drag is enabled
34477 * @type Roo.tree.TreeDragZone
34479 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34480 ddGroup: this.ddGroup || "TreeDD",
34481 scroll: this.ddScroll
34484 this.getSelectionModel().init(this);
34486 Roo.log("ROOT not set in tree");
34489 this.root.render();
34490 if(!this.rootVisible){
34491 this.root.renderChildren();
34497 * Ext JS Library 1.1.1
34498 * Copyright(c) 2006-2007, Ext JS, LLC.
34500 * Originally Released Under LGPL - original licence link has changed is not relivant.
34503 * <script type="text/javascript">
34508 * @class Roo.tree.DefaultSelectionModel
34509 * @extends Roo.util.Observable
34510 * The default single selection for a TreePanel.
34511 * @param {Object} cfg Configuration
34513 Roo.tree.DefaultSelectionModel = function(cfg){
34514 this.selNode = null;
34520 * @event selectionchange
34521 * Fires when the selected node changes
34522 * @param {DefaultSelectionModel} this
34523 * @param {TreeNode} node the new selection
34525 "selectionchange" : true,
34528 * @event beforeselect
34529 * Fires before the selected node changes, return false to cancel the change
34530 * @param {DefaultSelectionModel} this
34531 * @param {TreeNode} node the new selection
34532 * @param {TreeNode} node the old selection
34534 "beforeselect" : true
34537 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34540 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34541 init : function(tree){
34543 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34544 tree.on("click", this.onNodeClick, this);
34547 onNodeClick : function(node, e){
34548 if (e.ctrlKey && this.selNode == node) {
34549 this.unselect(node);
34557 * @param {TreeNode} node The node to select
34558 * @return {TreeNode} The selected node
34560 select : function(node){
34561 var last = this.selNode;
34562 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34564 last.ui.onSelectedChange(false);
34566 this.selNode = node;
34567 node.ui.onSelectedChange(true);
34568 this.fireEvent("selectionchange", this, node, last);
34575 * @param {TreeNode} node The node to unselect
34577 unselect : function(node){
34578 if(this.selNode == node){
34579 this.clearSelections();
34584 * Clear all selections
34586 clearSelections : function(){
34587 var n = this.selNode;
34589 n.ui.onSelectedChange(false);
34590 this.selNode = null;
34591 this.fireEvent("selectionchange", this, null);
34597 * Get the selected node
34598 * @return {TreeNode} The selected node
34600 getSelectedNode : function(){
34601 return this.selNode;
34605 * Returns true if the node is selected
34606 * @param {TreeNode} node The node to check
34607 * @return {Boolean}
34609 isSelected : function(node){
34610 return this.selNode == node;
34614 * Selects the node above the selected node in the tree, intelligently walking the nodes
34615 * @return TreeNode The new selection
34617 selectPrevious : function(){
34618 var s = this.selNode || this.lastSelNode;
34622 var ps = s.previousSibling;
34624 if(!ps.isExpanded() || ps.childNodes.length < 1){
34625 return this.select(ps);
34627 var lc = ps.lastChild;
34628 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34631 return this.select(lc);
34633 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34634 return this.select(s.parentNode);
34640 * Selects the node above the selected node in the tree, intelligently walking the nodes
34641 * @return TreeNode The new selection
34643 selectNext : function(){
34644 var s = this.selNode || this.lastSelNode;
34648 if(s.firstChild && s.isExpanded()){
34649 return this.select(s.firstChild);
34650 }else if(s.nextSibling){
34651 return this.select(s.nextSibling);
34652 }else if(s.parentNode){
34654 s.parentNode.bubble(function(){
34655 if(this.nextSibling){
34656 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34665 onKeyDown : function(e){
34666 var s = this.selNode || this.lastSelNode;
34667 // undesirable, but required
34672 var k = e.getKey();
34680 this.selectPrevious();
34683 e.preventDefault();
34684 if(s.hasChildNodes()){
34685 if(!s.isExpanded()){
34687 }else if(s.firstChild){
34688 this.select(s.firstChild, e);
34693 e.preventDefault();
34694 if(s.hasChildNodes() && s.isExpanded()){
34696 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34697 this.select(s.parentNode, e);
34705 * @class Roo.tree.MultiSelectionModel
34706 * @extends Roo.util.Observable
34707 * Multi selection for a TreePanel.
34708 * @param {Object} cfg Configuration
34710 Roo.tree.MultiSelectionModel = function(){
34711 this.selNodes = [];
34715 * @event selectionchange
34716 * Fires when the selected nodes change
34717 * @param {MultiSelectionModel} this
34718 * @param {Array} nodes Array of the selected nodes
34720 "selectionchange" : true
34722 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34726 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34727 init : function(tree){
34729 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34730 tree.on("click", this.onNodeClick, this);
34733 onNodeClick : function(node, e){
34734 this.select(node, e, e.ctrlKey);
34739 * @param {TreeNode} node The node to select
34740 * @param {EventObject} e (optional) An event associated with the selection
34741 * @param {Boolean} keepExisting True to retain existing selections
34742 * @return {TreeNode} The selected node
34744 select : function(node, e, keepExisting){
34745 if(keepExisting !== true){
34746 this.clearSelections(true);
34748 if(this.isSelected(node)){
34749 this.lastSelNode = node;
34752 this.selNodes.push(node);
34753 this.selMap[node.id] = node;
34754 this.lastSelNode = node;
34755 node.ui.onSelectedChange(true);
34756 this.fireEvent("selectionchange", this, this.selNodes);
34762 * @param {TreeNode} node The node to unselect
34764 unselect : function(node){
34765 if(this.selMap[node.id]){
34766 node.ui.onSelectedChange(false);
34767 var sn = this.selNodes;
34770 index = sn.indexOf(node);
34772 for(var i = 0, len = sn.length; i < len; i++){
34780 this.selNodes.splice(index, 1);
34782 delete this.selMap[node.id];
34783 this.fireEvent("selectionchange", this, this.selNodes);
34788 * Clear all selections
34790 clearSelections : function(suppressEvent){
34791 var sn = this.selNodes;
34793 for(var i = 0, len = sn.length; i < len; i++){
34794 sn[i].ui.onSelectedChange(false);
34796 this.selNodes = [];
34798 if(suppressEvent !== true){
34799 this.fireEvent("selectionchange", this, this.selNodes);
34805 * Returns true if the node is selected
34806 * @param {TreeNode} node The node to check
34807 * @return {Boolean}
34809 isSelected : function(node){
34810 return this.selMap[node.id] ? true : false;
34814 * Returns an array of the selected nodes
34817 getSelectedNodes : function(){
34818 return this.selNodes;
34821 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34823 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34825 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34828 * Ext JS Library 1.1.1
34829 * Copyright(c) 2006-2007, Ext JS, LLC.
34831 * Originally Released Under LGPL - original licence link has changed is not relivant.
34834 * <script type="text/javascript">
34838 * @class Roo.tree.TreeNode
34839 * @extends Roo.data.Node
34840 * @cfg {String} text The text for this node
34841 * @cfg {Boolean} expanded true to start the node expanded
34842 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34843 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34844 * @cfg {Boolean} disabled true to start the node disabled
34845 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34846 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34847 * @cfg {String} cls A css class to be added to the node
34848 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34849 * @cfg {String} href URL of the link used for the node (defaults to #)
34850 * @cfg {String} hrefTarget target frame for the link
34851 * @cfg {String} qtip An Ext QuickTip for the node
34852 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34853 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34854 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34855 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34856 * (defaults to undefined with no checkbox rendered)
34858 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34860 Roo.tree.TreeNode = function(attributes){
34861 attributes = attributes || {};
34862 if(typeof attributes == "string"){
34863 attributes = {text: attributes};
34865 this.childrenRendered = false;
34866 this.rendered = false;
34867 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34868 this.expanded = attributes.expanded === true;
34869 this.isTarget = attributes.isTarget !== false;
34870 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34871 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34874 * Read-only. The text for this node. To change it use setText().
34877 this.text = attributes.text;
34879 * True if this node is disabled.
34882 this.disabled = attributes.disabled === true;
34886 * @event textchange
34887 * Fires when the text for this node is changed
34888 * @param {Node} this This node
34889 * @param {String} text The new text
34890 * @param {String} oldText The old text
34892 "textchange" : true,
34894 * @event beforeexpand
34895 * Fires before this node is expanded, return false to cancel.
34896 * @param {Node} this This node
34897 * @param {Boolean} deep
34898 * @param {Boolean} anim
34900 "beforeexpand" : true,
34902 * @event beforecollapse
34903 * Fires before this node is collapsed, return false to cancel.
34904 * @param {Node} this This node
34905 * @param {Boolean} deep
34906 * @param {Boolean} anim
34908 "beforecollapse" : true,
34911 * Fires when this node is expanded
34912 * @param {Node} this This node
34916 * @event disabledchange
34917 * Fires when the disabled status of this node changes
34918 * @param {Node} this This node
34919 * @param {Boolean} disabled
34921 "disabledchange" : true,
34924 * Fires when this node is collapsed
34925 * @param {Node} this This node
34929 * @event beforeclick
34930 * Fires before click processing. Return false to cancel the default action.
34931 * @param {Node} this This node
34932 * @param {Roo.EventObject} e The event object
34934 "beforeclick":true,
34936 * @event checkchange
34937 * Fires when a node with a checkbox's checked property changes
34938 * @param {Node} this This node
34939 * @param {Boolean} checked
34941 "checkchange":true,
34944 * Fires when this node is clicked
34945 * @param {Node} this This node
34946 * @param {Roo.EventObject} e The event object
34951 * Fires when this node is double clicked
34952 * @param {Node} this This node
34953 * @param {Roo.EventObject} e The event object
34957 * @event contextmenu
34958 * Fires when this node is right clicked
34959 * @param {Node} this This node
34960 * @param {Roo.EventObject} e The event object
34962 "contextmenu":true,
34964 * @event beforechildrenrendered
34965 * Fires right before the child nodes for this node are rendered
34966 * @param {Node} this This node
34968 "beforechildrenrendered":true
34971 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34974 * Read-only. The UI for this node
34977 this.ui = new uiClass(this);
34979 // finally support items[]
34980 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34985 Roo.each(this.attributes.items, function(c) {
34986 this.appendChild(Roo.factory(c,Roo.Tree));
34988 delete this.attributes.items;
34993 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34994 preventHScroll: true,
34996 * Returns true if this node is expanded
34997 * @return {Boolean}
34999 isExpanded : function(){
35000 return this.expanded;
35004 * Returns the UI object for this node
35005 * @return {TreeNodeUI}
35007 getUI : function(){
35011 // private override
35012 setFirstChild : function(node){
35013 var of = this.firstChild;
35014 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35015 if(this.childrenRendered && of && node != of){
35016 of.renderIndent(true, true);
35019 this.renderIndent(true, true);
35023 // private override
35024 setLastChild : function(node){
35025 var ol = this.lastChild;
35026 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35027 if(this.childrenRendered && ol && node != ol){
35028 ol.renderIndent(true, true);
35031 this.renderIndent(true, true);
35035 // these methods are overridden to provide lazy rendering support
35036 // private override
35037 appendChild : function()
35039 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35040 if(node && this.childrenRendered){
35043 this.ui.updateExpandIcon();
35047 // private override
35048 removeChild : function(node){
35049 this.ownerTree.getSelectionModel().unselect(node);
35050 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35051 // if it's been rendered remove dom node
35052 if(this.childrenRendered){
35055 if(this.childNodes.length < 1){
35056 this.collapse(false, false);
35058 this.ui.updateExpandIcon();
35060 if(!this.firstChild) {
35061 this.childrenRendered = false;
35066 // private override
35067 insertBefore : function(node, refNode){
35068 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35069 if(newNode && refNode && this.childrenRendered){
35072 this.ui.updateExpandIcon();
35077 * Sets the text for this node
35078 * @param {String} text
35080 setText : function(text){
35081 var oldText = this.text;
35083 this.attributes.text = text;
35084 if(this.rendered){ // event without subscribing
35085 this.ui.onTextChange(this, text, oldText);
35087 this.fireEvent("textchange", this, text, oldText);
35091 * Triggers selection of this node
35093 select : function(){
35094 this.getOwnerTree().getSelectionModel().select(this);
35098 * Triggers deselection of this node
35100 unselect : function(){
35101 this.getOwnerTree().getSelectionModel().unselect(this);
35105 * Returns true if this node is selected
35106 * @return {Boolean}
35108 isSelected : function(){
35109 return this.getOwnerTree().getSelectionModel().isSelected(this);
35113 * Expand this node.
35114 * @param {Boolean} deep (optional) True to expand all children as well
35115 * @param {Boolean} anim (optional) false to cancel the default animation
35116 * @param {Function} callback (optional) A callback to be called when
35117 * expanding this node completes (does not wait for deep expand to complete).
35118 * Called with 1 parameter, this node.
35120 expand : function(deep, anim, callback){
35121 if(!this.expanded){
35122 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35125 if(!this.childrenRendered){
35126 this.renderChildren();
35128 this.expanded = true;
35129 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35130 this.ui.animExpand(function(){
35131 this.fireEvent("expand", this);
35132 if(typeof callback == "function"){
35136 this.expandChildNodes(true);
35138 }.createDelegate(this));
35142 this.fireEvent("expand", this);
35143 if(typeof callback == "function"){
35148 if(typeof callback == "function"){
35153 this.expandChildNodes(true);
35157 isHiddenRoot : function(){
35158 return this.isRoot && !this.getOwnerTree().rootVisible;
35162 * Collapse this node.
35163 * @param {Boolean} deep (optional) True to collapse all children as well
35164 * @param {Boolean} anim (optional) false to cancel the default animation
35166 collapse : function(deep, anim){
35167 if(this.expanded && !this.isHiddenRoot()){
35168 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35171 this.expanded = false;
35172 if((this.getOwnerTree().animate && anim !== false) || anim){
35173 this.ui.animCollapse(function(){
35174 this.fireEvent("collapse", this);
35176 this.collapseChildNodes(true);
35178 }.createDelegate(this));
35181 this.ui.collapse();
35182 this.fireEvent("collapse", this);
35186 var cs = this.childNodes;
35187 for(var i = 0, len = cs.length; i < len; i++) {
35188 cs[i].collapse(true, false);
35194 delayedExpand : function(delay){
35195 if(!this.expandProcId){
35196 this.expandProcId = this.expand.defer(delay, this);
35201 cancelExpand : function(){
35202 if(this.expandProcId){
35203 clearTimeout(this.expandProcId);
35205 this.expandProcId = false;
35209 * Toggles expanded/collapsed state of the node
35211 toggle : function(){
35220 * Ensures all parent nodes are expanded
35222 ensureVisible : function(callback){
35223 var tree = this.getOwnerTree();
35224 tree.expandPath(this.parentNode.getPath(), false, function(){
35225 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35226 Roo.callback(callback);
35227 }.createDelegate(this));
35231 * Expand all child nodes
35232 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35234 expandChildNodes : function(deep){
35235 var cs = this.childNodes;
35236 for(var i = 0, len = cs.length; i < len; i++) {
35237 cs[i].expand(deep);
35242 * Collapse all child nodes
35243 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35245 collapseChildNodes : function(deep){
35246 var cs = this.childNodes;
35247 for(var i = 0, len = cs.length; i < len; i++) {
35248 cs[i].collapse(deep);
35253 * Disables this node
35255 disable : function(){
35256 this.disabled = true;
35258 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35259 this.ui.onDisableChange(this, true);
35261 this.fireEvent("disabledchange", this, true);
35265 * Enables this node
35267 enable : function(){
35268 this.disabled = false;
35269 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35270 this.ui.onDisableChange(this, false);
35272 this.fireEvent("disabledchange", this, false);
35276 renderChildren : function(suppressEvent){
35277 if(suppressEvent !== false){
35278 this.fireEvent("beforechildrenrendered", this);
35280 var cs = this.childNodes;
35281 for(var i = 0, len = cs.length; i < len; i++){
35282 cs[i].render(true);
35284 this.childrenRendered = true;
35288 sort : function(fn, scope){
35289 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35290 if(this.childrenRendered){
35291 var cs = this.childNodes;
35292 for(var i = 0, len = cs.length; i < len; i++){
35293 cs[i].render(true);
35299 render : function(bulkRender){
35300 this.ui.render(bulkRender);
35301 if(!this.rendered){
35302 this.rendered = true;
35304 this.expanded = false;
35305 this.expand(false, false);
35311 renderIndent : function(deep, refresh){
35313 this.ui.childIndent = null;
35315 this.ui.renderIndent();
35316 if(deep === true && this.childrenRendered){
35317 var cs = this.childNodes;
35318 for(var i = 0, len = cs.length; i < len; i++){
35319 cs[i].renderIndent(true, refresh);
35325 * Ext JS Library 1.1.1
35326 * Copyright(c) 2006-2007, Ext JS, LLC.
35328 * Originally Released Under LGPL - original licence link has changed is not relivant.
35331 * <script type="text/javascript">
35335 * @class Roo.tree.AsyncTreeNode
35336 * @extends Roo.tree.TreeNode
35337 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35339 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35341 Roo.tree.AsyncTreeNode = function(config){
35342 this.loaded = false;
35343 this.loading = false;
35344 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35346 * @event beforeload
35347 * Fires before this node is loaded, return false to cancel
35348 * @param {Node} this This node
35350 this.addEvents({'beforeload':true, 'load': true});
35353 * Fires when this node is loaded
35354 * @param {Node} this This node
35357 * The loader used by this node (defaults to using the tree's defined loader)
35362 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35363 expand : function(deep, anim, callback){
35364 if(this.loading){ // if an async load is already running, waiting til it's done
35366 var f = function(){
35367 if(!this.loading){ // done loading
35368 clearInterval(timer);
35369 this.expand(deep, anim, callback);
35371 }.createDelegate(this);
35372 timer = setInterval(f, 200);
35376 if(this.fireEvent("beforeload", this) === false){
35379 this.loading = true;
35380 this.ui.beforeLoad(this);
35381 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35383 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35387 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35391 * Returns true if this node is currently loading
35392 * @return {Boolean}
35394 isLoading : function(){
35395 return this.loading;
35398 loadComplete : function(deep, anim, callback){
35399 this.loading = false;
35400 this.loaded = true;
35401 this.ui.afterLoad(this);
35402 this.fireEvent("load", this);
35403 this.expand(deep, anim, callback);
35407 * Returns true if this node has been loaded
35408 * @return {Boolean}
35410 isLoaded : function(){
35411 return this.loaded;
35414 hasChildNodes : function(){
35415 if(!this.isLeaf() && !this.loaded){
35418 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35423 * Trigger a reload for this node
35424 * @param {Function} callback
35426 reload : function(callback){
35427 this.collapse(false, false);
35428 while(this.firstChild){
35429 this.removeChild(this.firstChild);
35431 this.childrenRendered = false;
35432 this.loaded = false;
35433 if(this.isHiddenRoot()){
35434 this.expanded = false;
35436 this.expand(false, false, callback);
35440 * Ext JS Library 1.1.1
35441 * Copyright(c) 2006-2007, Ext JS, LLC.
35443 * Originally Released Under LGPL - original licence link has changed is not relivant.
35446 * <script type="text/javascript">
35450 * @class Roo.tree.TreeNodeUI
35452 * @param {Object} node The node to render
35453 * The TreeNode UI implementation is separate from the
35454 * tree implementation. Unless you are customizing the tree UI,
35455 * you should never have to use this directly.
35457 Roo.tree.TreeNodeUI = function(node){
35459 this.rendered = false;
35460 this.animating = false;
35461 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35464 Roo.tree.TreeNodeUI.prototype = {
35465 removeChild : function(node){
35467 this.ctNode.removeChild(node.ui.getEl());
35471 beforeLoad : function(){
35472 this.addClass("x-tree-node-loading");
35475 afterLoad : function(){
35476 this.removeClass("x-tree-node-loading");
35479 onTextChange : function(node, text, oldText){
35481 this.textNode.innerHTML = text;
35485 onDisableChange : function(node, state){
35486 this.disabled = state;
35488 this.addClass("x-tree-node-disabled");
35490 this.removeClass("x-tree-node-disabled");
35494 onSelectedChange : function(state){
35497 this.addClass("x-tree-selected");
35500 this.removeClass("x-tree-selected");
35504 onMove : function(tree, node, oldParent, newParent, index, refNode){
35505 this.childIndent = null;
35507 var targetNode = newParent.ui.getContainer();
35508 if(!targetNode){//target not rendered
35509 this.holder = document.createElement("div");
35510 this.holder.appendChild(this.wrap);
35513 var insertBefore = refNode ? refNode.ui.getEl() : null;
35515 targetNode.insertBefore(this.wrap, insertBefore);
35517 targetNode.appendChild(this.wrap);
35519 this.node.renderIndent(true);
35523 addClass : function(cls){
35525 Roo.fly(this.elNode).addClass(cls);
35529 removeClass : function(cls){
35531 Roo.fly(this.elNode).removeClass(cls);
35535 remove : function(){
35537 this.holder = document.createElement("div");
35538 this.holder.appendChild(this.wrap);
35542 fireEvent : function(){
35543 return this.node.fireEvent.apply(this.node, arguments);
35546 initEvents : function(){
35547 this.node.on("move", this.onMove, this);
35548 var E = Roo.EventManager;
35549 var a = this.anchor;
35551 var el = Roo.fly(a, '_treeui');
35553 if(Roo.isOpera){ // opera render bug ignores the CSS
35554 el.setStyle("text-decoration", "none");
35557 el.on("click", this.onClick, this);
35558 el.on("dblclick", this.onDblClick, this);
35561 Roo.EventManager.on(this.checkbox,
35562 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35565 el.on("contextmenu", this.onContextMenu, this);
35567 var icon = Roo.fly(this.iconNode);
35568 icon.on("click", this.onClick, this);
35569 icon.on("dblclick", this.onDblClick, this);
35570 icon.on("contextmenu", this.onContextMenu, this);
35571 E.on(this.ecNode, "click", this.ecClick, this, true);
35573 if(this.node.disabled){
35574 this.addClass("x-tree-node-disabled");
35576 if(this.node.hidden){
35577 this.addClass("x-tree-node-disabled");
35579 var ot = this.node.getOwnerTree();
35580 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35581 if(dd && (!this.node.isRoot || ot.rootVisible)){
35582 Roo.dd.Registry.register(this.elNode, {
35584 handles: this.getDDHandles(),
35590 getDDHandles : function(){
35591 return [this.iconNode, this.textNode];
35596 this.wrap.style.display = "none";
35602 this.wrap.style.display = "";
35606 onContextMenu : function(e){
35607 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35608 e.preventDefault();
35610 this.fireEvent("contextmenu", this.node, e);
35614 onClick : function(e){
35619 if(this.fireEvent("beforeclick", this.node, e) !== false){
35620 if(!this.disabled && this.node.attributes.href){
35621 this.fireEvent("click", this.node, e);
35624 e.preventDefault();
35629 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35630 this.node.toggle();
35633 this.fireEvent("click", this.node, e);
35639 onDblClick : function(e){
35640 e.preventDefault();
35645 this.toggleCheck();
35647 if(!this.animating && this.node.hasChildNodes()){
35648 this.node.toggle();
35650 this.fireEvent("dblclick", this.node, e);
35653 onCheckChange : function(){
35654 var checked = this.checkbox.checked;
35655 this.node.attributes.checked = checked;
35656 this.fireEvent('checkchange', this.node, checked);
35659 ecClick : function(e){
35660 if(!this.animating && this.node.hasChildNodes()){
35661 this.node.toggle();
35665 startDrop : function(){
35666 this.dropping = true;
35669 // delayed drop so the click event doesn't get fired on a drop
35670 endDrop : function(){
35671 setTimeout(function(){
35672 this.dropping = false;
35673 }.createDelegate(this), 50);
35676 expand : function(){
35677 this.updateExpandIcon();
35678 this.ctNode.style.display = "";
35681 focus : function(){
35682 if(!this.node.preventHScroll){
35683 try{this.anchor.focus();
35685 }else if(!Roo.isIE){
35687 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35688 var l = noscroll.scrollLeft;
35689 this.anchor.focus();
35690 noscroll.scrollLeft = l;
35695 toggleCheck : function(value){
35696 var cb = this.checkbox;
35698 cb.checked = (value === undefined ? !cb.checked : value);
35704 this.anchor.blur();
35708 animExpand : function(callback){
35709 var ct = Roo.get(this.ctNode);
35711 if(!this.node.hasChildNodes()){
35712 this.updateExpandIcon();
35713 this.ctNode.style.display = "";
35714 Roo.callback(callback);
35717 this.animating = true;
35718 this.updateExpandIcon();
35721 callback : function(){
35722 this.animating = false;
35723 Roo.callback(callback);
35726 duration: this.node.ownerTree.duration || .25
35730 highlight : function(){
35731 var tree = this.node.getOwnerTree();
35732 Roo.fly(this.wrap).highlight(
35733 tree.hlColor || "C3DAF9",
35734 {endColor: tree.hlBaseColor}
35738 collapse : function(){
35739 this.updateExpandIcon();
35740 this.ctNode.style.display = "none";
35743 animCollapse : function(callback){
35744 var ct = Roo.get(this.ctNode);
35745 ct.enableDisplayMode('block');
35748 this.animating = true;
35749 this.updateExpandIcon();
35752 callback : function(){
35753 this.animating = false;
35754 Roo.callback(callback);
35757 duration: this.node.ownerTree.duration || .25
35761 getContainer : function(){
35762 return this.ctNode;
35765 getEl : function(){
35769 appendDDGhost : function(ghostNode){
35770 ghostNode.appendChild(this.elNode.cloneNode(true));
35773 getDDRepairXY : function(){
35774 return Roo.lib.Dom.getXY(this.iconNode);
35777 onRender : function(){
35781 render : function(bulkRender){
35782 var n = this.node, a = n.attributes;
35783 var targetNode = n.parentNode ?
35784 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35786 if(!this.rendered){
35787 this.rendered = true;
35789 this.renderElements(n, a, targetNode, bulkRender);
35792 if(this.textNode.setAttributeNS){
35793 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35795 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35798 this.textNode.setAttribute("ext:qtip", a.qtip);
35800 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35803 }else if(a.qtipCfg){
35804 a.qtipCfg.target = Roo.id(this.textNode);
35805 Roo.QuickTips.register(a.qtipCfg);
35808 if(!this.node.expanded){
35809 this.updateExpandIcon();
35812 if(bulkRender === true) {
35813 targetNode.appendChild(this.wrap);
35818 renderElements : function(n, a, targetNode, bulkRender)
35820 // add some indent caching, this helps performance when rendering a large tree
35821 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35822 var t = n.getOwnerTree();
35823 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35824 if (typeof(n.attributes.html) != 'undefined') {
35825 txt = n.attributes.html;
35827 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35828 var cb = typeof a.checked == 'boolean';
35829 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35830 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35831 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35832 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35833 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35834 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35835 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35836 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35837 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35838 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35841 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35842 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35843 n.nextSibling.ui.getEl(), buf.join(""));
35845 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35848 this.elNode = this.wrap.childNodes[0];
35849 this.ctNode = this.wrap.childNodes[1];
35850 var cs = this.elNode.childNodes;
35851 this.indentNode = cs[0];
35852 this.ecNode = cs[1];
35853 this.iconNode = cs[2];
35856 this.checkbox = cs[3];
35859 this.anchor = cs[index];
35860 this.textNode = cs[index].firstChild;
35863 getAnchor : function(){
35864 return this.anchor;
35867 getTextEl : function(){
35868 return this.textNode;
35871 getIconEl : function(){
35872 return this.iconNode;
35875 isChecked : function(){
35876 return this.checkbox ? this.checkbox.checked : false;
35879 updateExpandIcon : function(){
35881 var n = this.node, c1, c2;
35882 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35883 var hasChild = n.hasChildNodes();
35887 c1 = "x-tree-node-collapsed";
35888 c2 = "x-tree-node-expanded";
35891 c1 = "x-tree-node-expanded";
35892 c2 = "x-tree-node-collapsed";
35895 this.removeClass("x-tree-node-leaf");
35896 this.wasLeaf = false;
35898 if(this.c1 != c1 || this.c2 != c2){
35899 Roo.fly(this.elNode).replaceClass(c1, c2);
35900 this.c1 = c1; this.c2 = c2;
35903 // this changes non-leafs into leafs if they have no children.
35904 // it's not very rational behaviour..
35906 if(!this.wasLeaf && this.node.leaf){
35907 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35910 this.wasLeaf = true;
35913 var ecc = "x-tree-ec-icon "+cls;
35914 if(this.ecc != ecc){
35915 this.ecNode.className = ecc;
35921 getChildIndent : function(){
35922 if(!this.childIndent){
35926 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35928 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35930 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35935 this.childIndent = buf.join("");
35937 return this.childIndent;
35940 renderIndent : function(){
35943 var p = this.node.parentNode;
35945 indent = p.ui.getChildIndent();
35947 if(this.indentMarkup != indent){ // don't rerender if not required
35948 this.indentNode.innerHTML = indent;
35949 this.indentMarkup = indent;
35951 this.updateExpandIcon();
35956 Roo.tree.RootTreeNodeUI = function(){
35957 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35959 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35960 render : function(){
35961 if(!this.rendered){
35962 var targetNode = this.node.ownerTree.innerCt.dom;
35963 this.node.expanded = true;
35964 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35965 this.wrap = this.ctNode = targetNode.firstChild;
35968 collapse : function(){
35970 expand : function(){
35974 * Ext JS Library 1.1.1
35975 * Copyright(c) 2006-2007, Ext JS, LLC.
35977 * Originally Released Under LGPL - original licence link has changed is not relivant.
35980 * <script type="text/javascript">
35983 * @class Roo.tree.TreeLoader
35984 * @extends Roo.util.Observable
35985 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35986 * nodes from a specified URL. The response must be a javascript Array definition
35987 * who's elements are node definition objects. eg:
35992 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35993 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36000 * The old style respose with just an array is still supported, but not recommended.
36003 * A server request is sent, and child nodes are loaded only when a node is expanded.
36004 * The loading node's id is passed to the server under the parameter name "node" to
36005 * enable the server to produce the correct child nodes.
36007 * To pass extra parameters, an event handler may be attached to the "beforeload"
36008 * event, and the parameters specified in the TreeLoader's baseParams property:
36010 myTreeLoader.on("beforeload", function(treeLoader, node) {
36011 this.baseParams.category = node.attributes.category;
36014 * This would pass an HTTP parameter called "category" to the server containing
36015 * the value of the Node's "category" attribute.
36017 * Creates a new Treeloader.
36018 * @param {Object} config A config object containing config properties.
36020 Roo.tree.TreeLoader = function(config){
36021 this.baseParams = {};
36022 this.requestMethod = "POST";
36023 Roo.apply(this, config);
36028 * @event beforeload
36029 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36030 * @param {Object} This TreeLoader object.
36031 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36032 * @param {Object} callback The callback function specified in the {@link #load} call.
36037 * Fires when the node has been successfuly loaded.
36038 * @param {Object} This TreeLoader object.
36039 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36040 * @param {Object} response The response object containing the data from the server.
36044 * @event loadexception
36045 * Fires if the network request failed.
36046 * @param {Object} This TreeLoader object.
36047 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36048 * @param {Object} response The response object containing the data from the server.
36050 loadexception : true,
36053 * Fires before a node is created, enabling you to return custom Node types
36054 * @param {Object} This TreeLoader object.
36055 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36060 Roo.tree.TreeLoader.superclass.constructor.call(this);
36063 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36065 * @cfg {String} dataUrl The URL from which to request a Json string which
36066 * specifies an array of node definition object representing the child nodes
36070 * @cfg {String} requestMethod either GET or POST
36071 * defaults to POST (due to BC)
36075 * @cfg {Object} baseParams (optional) An object containing properties which
36076 * specify HTTP parameters to be passed to each request for child nodes.
36079 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36080 * created by this loader. If the attributes sent by the server have an attribute in this object,
36081 * they take priority.
36084 * @cfg {Object} uiProviders (optional) An object containing properties which
36086 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36087 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36088 * <i>uiProvider</i> attribute of a returned child node is a string rather
36089 * than a reference to a TreeNodeUI implementation, this that string value
36090 * is used as a property name in the uiProviders object. You can define the provider named
36091 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36096 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36097 * child nodes before loading.
36099 clearOnLoad : true,
36102 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36103 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36104 * Grid query { data : [ .....] }
36109 * @cfg {String} queryParam (optional)
36110 * Name of the query as it will be passed on the querystring (defaults to 'node')
36111 * eg. the request will be ?node=[id]
36118 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36119 * This is called automatically when a node is expanded, but may be used to reload
36120 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36121 * @param {Roo.tree.TreeNode} node
36122 * @param {Function} callback
36124 load : function(node, callback){
36125 if(this.clearOnLoad){
36126 while(node.firstChild){
36127 node.removeChild(node.firstChild);
36130 if(node.attributes.children){ // preloaded json children
36131 var cs = node.attributes.children;
36132 for(var i = 0, len = cs.length; i < len; i++){
36133 node.appendChild(this.createNode(cs[i]));
36135 if(typeof callback == "function"){
36138 }else if(this.dataUrl){
36139 this.requestData(node, callback);
36143 getParams: function(node){
36144 var buf = [], bp = this.baseParams;
36145 for(var key in bp){
36146 if(typeof bp[key] != "function"){
36147 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36150 var n = this.queryParam === false ? 'node' : this.queryParam;
36151 buf.push(n + "=", encodeURIComponent(node.id));
36152 return buf.join("");
36155 requestData : function(node, callback){
36156 if(this.fireEvent("beforeload", this, node, callback) !== false){
36157 this.transId = Roo.Ajax.request({
36158 method:this.requestMethod,
36159 url: this.dataUrl||this.url,
36160 success: this.handleResponse,
36161 failure: this.handleFailure,
36163 argument: {callback: callback, node: node},
36164 params: this.getParams(node)
36167 // if the load is cancelled, make sure we notify
36168 // the node that we are done
36169 if(typeof callback == "function"){
36175 isLoading : function(){
36176 return this.transId ? true : false;
36179 abort : function(){
36180 if(this.isLoading()){
36181 Roo.Ajax.abort(this.transId);
36186 createNode : function(attr)
36188 // apply baseAttrs, nice idea Corey!
36189 if(this.baseAttrs){
36190 Roo.applyIf(attr, this.baseAttrs);
36192 if(this.applyLoader !== false){
36193 attr.loader = this;
36195 // uiProvider = depreciated..
36197 if(typeof(attr.uiProvider) == 'string'){
36198 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36199 /** eval:var:attr */ eval(attr.uiProvider);
36201 if(typeof(this.uiProviders['default']) != 'undefined') {
36202 attr.uiProvider = this.uiProviders['default'];
36205 this.fireEvent('create', this, attr);
36207 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36209 new Roo.tree.TreeNode(attr) :
36210 new Roo.tree.AsyncTreeNode(attr));
36213 processResponse : function(response, node, callback)
36215 var json = response.responseText;
36218 var o = Roo.decode(json);
36220 if (this.root === false && typeof(o.success) != undefined) {
36221 this.root = 'data'; // the default behaviour for list like data..
36224 if (this.root !== false && !o.success) {
36225 // it's a failure condition.
36226 var a = response.argument;
36227 this.fireEvent("loadexception", this, a.node, response);
36228 Roo.log("Load failed - should have a handler really");
36234 if (this.root !== false) {
36238 for(var i = 0, len = o.length; i < len; i++){
36239 var n = this.createNode(o[i]);
36241 node.appendChild(n);
36244 if(typeof callback == "function"){
36245 callback(this, node);
36248 this.handleFailure(response);
36252 handleResponse : function(response){
36253 this.transId = false;
36254 var a = response.argument;
36255 this.processResponse(response, a.node, a.callback);
36256 this.fireEvent("load", this, a.node, response);
36259 handleFailure : function(response)
36261 // should handle failure better..
36262 this.transId = false;
36263 var a = response.argument;
36264 this.fireEvent("loadexception", this, a.node, response);
36265 if(typeof a.callback == "function"){
36266 a.callback(this, a.node);
36271 * Ext JS Library 1.1.1
36272 * Copyright(c) 2006-2007, Ext JS, LLC.
36274 * Originally Released Under LGPL - original licence link has changed is not relivant.
36277 * <script type="text/javascript">
36281 * @class Roo.tree.TreeFilter
36282 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36283 * @param {TreePanel} tree
36284 * @param {Object} config (optional)
36286 Roo.tree.TreeFilter = function(tree, config){
36288 this.filtered = {};
36289 Roo.apply(this, config);
36292 Roo.tree.TreeFilter.prototype = {
36299 * Filter the data by a specific attribute.
36300 * @param {String/RegExp} value Either string that the attribute value
36301 * should start with or a RegExp to test against the attribute
36302 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36303 * @param {TreeNode} startNode (optional) The node to start the filter at.
36305 filter : function(value, attr, startNode){
36306 attr = attr || "text";
36308 if(typeof value == "string"){
36309 var vlen = value.length;
36310 // auto clear empty filter
36311 if(vlen == 0 && this.clearBlank){
36315 value = value.toLowerCase();
36317 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36319 }else if(value.exec){ // regex?
36321 return value.test(n.attributes[attr]);
36324 throw 'Illegal filter type, must be string or regex';
36326 this.filterBy(f, null, startNode);
36330 * Filter by a function. The passed function will be called with each
36331 * node in the tree (or from the startNode). If the function returns true, the node is kept
36332 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36333 * @param {Function} fn The filter function
36334 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36336 filterBy : function(fn, scope, startNode){
36337 startNode = startNode || this.tree.root;
36338 if(this.autoClear){
36341 var af = this.filtered, rv = this.reverse;
36342 var f = function(n){
36343 if(n == startNode){
36349 var m = fn.call(scope || n, n);
36357 startNode.cascade(f);
36360 if(typeof id != "function"){
36362 if(n && n.parentNode){
36363 n.parentNode.removeChild(n);
36371 * Clears the current filter. Note: with the "remove" option
36372 * set a filter cannot be cleared.
36374 clear : function(){
36376 var af = this.filtered;
36378 if(typeof id != "function"){
36385 this.filtered = {};
36390 * Ext JS Library 1.1.1
36391 * Copyright(c) 2006-2007, Ext JS, LLC.
36393 * Originally Released Under LGPL - original licence link has changed is not relivant.
36396 * <script type="text/javascript">
36401 * @class Roo.tree.TreeSorter
36402 * Provides sorting of nodes in a TreePanel
36404 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36405 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36406 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36407 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36408 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36409 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36411 * @param {TreePanel} tree
36412 * @param {Object} config
36414 Roo.tree.TreeSorter = function(tree, config){
36415 Roo.apply(this, config);
36416 tree.on("beforechildrenrendered", this.doSort, this);
36417 tree.on("append", this.updateSort, this);
36418 tree.on("insert", this.updateSort, this);
36420 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36421 var p = this.property || "text";
36422 var sortType = this.sortType;
36423 var fs = this.folderSort;
36424 var cs = this.caseSensitive === true;
36425 var leafAttr = this.leafAttr || 'leaf';
36427 this.sortFn = function(n1, n2){
36429 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36432 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36436 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36437 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36439 return dsc ? +1 : -1;
36441 return dsc ? -1 : +1;
36448 Roo.tree.TreeSorter.prototype = {
36449 doSort : function(node){
36450 node.sort(this.sortFn);
36453 compareNodes : function(n1, n2){
36454 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36457 updateSort : function(tree, node){
36458 if(node.childrenRendered){
36459 this.doSort.defer(1, this, [node]);
36464 * Ext JS Library 1.1.1
36465 * Copyright(c) 2006-2007, Ext JS, LLC.
36467 * Originally Released Under LGPL - original licence link has changed is not relivant.
36470 * <script type="text/javascript">
36473 if(Roo.dd.DropZone){
36475 Roo.tree.TreeDropZone = function(tree, config){
36476 this.allowParentInsert = false;
36477 this.allowContainerDrop = false;
36478 this.appendOnly = false;
36479 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36481 this.lastInsertClass = "x-tree-no-status";
36482 this.dragOverData = {};
36485 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36486 ddGroup : "TreeDD",
36489 expandDelay : 1000,
36491 expandNode : function(node){
36492 if(node.hasChildNodes() && !node.isExpanded()){
36493 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36497 queueExpand : function(node){
36498 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36501 cancelExpand : function(){
36502 if(this.expandProcId){
36503 clearTimeout(this.expandProcId);
36504 this.expandProcId = false;
36508 isValidDropPoint : function(n, pt, dd, e, data){
36509 if(!n || !data){ return false; }
36510 var targetNode = n.node;
36511 var dropNode = data.node;
36512 // default drop rules
36513 if(!(targetNode && targetNode.isTarget && pt)){
36516 if(pt == "append" && targetNode.allowChildren === false){
36519 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36522 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36525 // reuse the object
36526 var overEvent = this.dragOverData;
36527 overEvent.tree = this.tree;
36528 overEvent.target = targetNode;
36529 overEvent.data = data;
36530 overEvent.point = pt;
36531 overEvent.source = dd;
36532 overEvent.rawEvent = e;
36533 overEvent.dropNode = dropNode;
36534 overEvent.cancel = false;
36535 var result = this.tree.fireEvent("nodedragover", overEvent);
36536 return overEvent.cancel === false && result !== false;
36539 getDropPoint : function(e, n, dd)
36543 return tn.allowChildren !== false ? "append" : false; // always append for root
36545 var dragEl = n.ddel;
36546 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36547 var y = Roo.lib.Event.getPageY(e);
36548 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36550 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36551 var noAppend = tn.allowChildren === false;
36552 if(this.appendOnly || tn.parentNode.allowChildren === false){
36553 return noAppend ? false : "append";
36555 var noBelow = false;
36556 if(!this.allowParentInsert){
36557 noBelow = tn.hasChildNodes() && tn.isExpanded();
36559 var q = (b - t) / (noAppend ? 2 : 3);
36560 if(y >= t && y < (t + q)){
36562 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36569 onNodeEnter : function(n, dd, e, data)
36571 this.cancelExpand();
36574 onNodeOver : function(n, dd, e, data)
36577 var pt = this.getDropPoint(e, n, dd);
36580 // auto node expand check
36581 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36582 this.queueExpand(node);
36583 }else if(pt != "append"){
36584 this.cancelExpand();
36587 // set the insert point style on the target node
36588 var returnCls = this.dropNotAllowed;
36589 if(this.isValidDropPoint(n, pt, dd, e, data)){
36594 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36595 cls = "x-tree-drag-insert-above";
36596 }else if(pt == "below"){
36597 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36598 cls = "x-tree-drag-insert-below";
36600 returnCls = "x-tree-drop-ok-append";
36601 cls = "x-tree-drag-append";
36603 if(this.lastInsertClass != cls){
36604 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36605 this.lastInsertClass = cls;
36612 onNodeOut : function(n, dd, e, data){
36614 this.cancelExpand();
36615 this.removeDropIndicators(n);
36618 onNodeDrop : function(n, dd, e, data){
36619 var point = this.getDropPoint(e, n, dd);
36620 var targetNode = n.node;
36621 targetNode.ui.startDrop();
36622 if(!this.isValidDropPoint(n, point, dd, e, data)){
36623 targetNode.ui.endDrop();
36626 // first try to find the drop node
36627 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36630 target: targetNode,
36635 dropNode: dropNode,
36638 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36639 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36640 targetNode.ui.endDrop();
36643 // allow target changing
36644 targetNode = dropEvent.target;
36645 if(point == "append" && !targetNode.isExpanded()){
36646 targetNode.expand(false, null, function(){
36647 this.completeDrop(dropEvent);
36648 }.createDelegate(this));
36650 this.completeDrop(dropEvent);
36655 completeDrop : function(de){
36656 var ns = de.dropNode, p = de.point, t = de.target;
36657 if(!(ns instanceof Array)){
36661 for(var i = 0, len = ns.length; i < len; i++){
36664 t.parentNode.insertBefore(n, t);
36665 }else if(p == "below"){
36666 t.parentNode.insertBefore(n, t.nextSibling);
36672 if(this.tree.hlDrop){
36676 this.tree.fireEvent("nodedrop", de);
36679 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36680 if(this.tree.hlDrop){
36681 dropNode.ui.focus();
36682 dropNode.ui.highlight();
36684 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36687 getTree : function(){
36691 removeDropIndicators : function(n){
36694 Roo.fly(el).removeClass([
36695 "x-tree-drag-insert-above",
36696 "x-tree-drag-insert-below",
36697 "x-tree-drag-append"]);
36698 this.lastInsertClass = "_noclass";
36702 beforeDragDrop : function(target, e, id){
36703 this.cancelExpand();
36707 afterRepair : function(data){
36708 if(data && Roo.enableFx){
36709 data.node.ui.highlight();
36719 * Ext JS Library 1.1.1
36720 * Copyright(c) 2006-2007, Ext JS, LLC.
36722 * Originally Released Under LGPL - original licence link has changed is not relivant.
36725 * <script type="text/javascript">
36729 if(Roo.dd.DragZone){
36730 Roo.tree.TreeDragZone = function(tree, config){
36731 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36735 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36736 ddGroup : "TreeDD",
36738 onBeforeDrag : function(data, e){
36740 return n && n.draggable && !n.disabled;
36744 onInitDrag : function(e){
36745 var data = this.dragData;
36746 this.tree.getSelectionModel().select(data.node);
36747 this.proxy.update("");
36748 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36749 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36752 getRepairXY : function(e, data){
36753 return data.node.ui.getDDRepairXY();
36756 onEndDrag : function(data, e){
36757 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36762 onValidDrop : function(dd, e, id){
36763 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36767 beforeInvalidDrop : function(e, id){
36768 // this scrolls the original position back into view
36769 var sm = this.tree.getSelectionModel();
36770 sm.clearSelections();
36771 sm.select(this.dragData.node);
36776 * Ext JS Library 1.1.1
36777 * Copyright(c) 2006-2007, Ext JS, LLC.
36779 * Originally Released Under LGPL - original licence link has changed is not relivant.
36782 * <script type="text/javascript">
36785 * @class Roo.tree.TreeEditor
36786 * @extends Roo.Editor
36787 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36788 * as the editor field.
36790 * @param {Object} config (used to be the tree panel.)
36791 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36793 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36794 * @cfg {Roo.form.TextField|Object} field The field configuration
36798 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36801 if (oldconfig) { // old style..
36802 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36805 tree = config.tree;
36806 config.field = config.field || {};
36807 config.field.xtype = 'TextField';
36808 field = Roo.factory(config.field, Roo.form);
36810 config = config || {};
36815 * @event beforenodeedit
36816 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36817 * false from the handler of this event.
36818 * @param {Editor} this
36819 * @param {Roo.tree.Node} node
36821 "beforenodeedit" : true
36825 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36829 tree.on('beforeclick', this.beforeNodeClick, this);
36830 tree.getTreeEl().on('mousedown', this.hide, this);
36831 this.on('complete', this.updateNode, this);
36832 this.on('beforestartedit', this.fitToTree, this);
36833 this.on('startedit', this.bindScroll, this, {delay:10});
36834 this.on('specialkey', this.onSpecialKey, this);
36837 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36839 * @cfg {String} alignment
36840 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36846 * @cfg {Boolean} hideEl
36847 * True to hide the bound element while the editor is displayed (defaults to false)
36851 * @cfg {String} cls
36852 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36854 cls: "x-small-editor x-tree-editor",
36856 * @cfg {Boolean} shim
36857 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36863 * @cfg {Number} maxWidth
36864 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36865 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36866 * scroll and client offsets into account prior to each edit.
36873 fitToTree : function(ed, el){
36874 var td = this.tree.getTreeEl().dom, nd = el.dom;
36875 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36876 td.scrollLeft = nd.offsetLeft;
36880 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36881 this.setSize(w, '');
36883 return this.fireEvent('beforenodeedit', this, this.editNode);
36888 triggerEdit : function(node){
36889 this.completeEdit();
36890 this.editNode = node;
36891 this.startEdit(node.ui.textNode, node.text);
36895 bindScroll : function(){
36896 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36900 beforeNodeClick : function(node, e){
36901 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36902 this.lastClick = new Date();
36903 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36905 this.triggerEdit(node);
36912 updateNode : function(ed, value){
36913 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36914 this.editNode.setText(value);
36918 onHide : function(){
36919 Roo.tree.TreeEditor.superclass.onHide.call(this);
36921 this.editNode.ui.focus();
36926 onSpecialKey : function(field, e){
36927 var k = e.getKey();
36931 }else if(k == e.ENTER && !e.hasModifier()){
36933 this.completeEdit();
36936 });//<Script type="text/javascript">
36939 * Ext JS Library 1.1.1
36940 * Copyright(c) 2006-2007, Ext JS, LLC.
36942 * Originally Released Under LGPL - original licence link has changed is not relivant.
36945 * <script type="text/javascript">
36949 * Not documented??? - probably should be...
36952 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36953 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36955 renderElements : function(n, a, targetNode, bulkRender){
36956 //consel.log("renderElements?");
36957 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36959 var t = n.getOwnerTree();
36960 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36962 var cols = t.columns;
36963 var bw = t.borderWidth;
36965 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36966 var cb = typeof a.checked == "boolean";
36967 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36968 var colcls = 'x-t-' + tid + '-c0';
36970 '<li class="x-tree-node">',
36973 '<div class="x-tree-node-el ', a.cls,'">',
36975 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36978 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36979 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36980 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36981 (a.icon ? ' x-tree-node-inline-icon' : ''),
36982 (a.iconCls ? ' '+a.iconCls : ''),
36983 '" unselectable="on" />',
36984 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36985 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36987 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36988 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36989 '<span unselectable="on" qtip="' + tx + '">',
36993 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36994 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36996 for(var i = 1, len = cols.length; i < len; i++){
36998 colcls = 'x-t-' + tid + '-c' +i;
36999 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37000 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37001 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37007 '<div class="x-clear"></div></div>',
37008 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37011 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37012 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37013 n.nextSibling.ui.getEl(), buf.join(""));
37015 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37017 var el = this.wrap.firstChild;
37019 this.elNode = el.firstChild;
37020 this.ranchor = el.childNodes[1];
37021 this.ctNode = this.wrap.childNodes[1];
37022 var cs = el.firstChild.childNodes;
37023 this.indentNode = cs[0];
37024 this.ecNode = cs[1];
37025 this.iconNode = cs[2];
37028 this.checkbox = cs[3];
37031 this.anchor = cs[index];
37033 this.textNode = cs[index].firstChild;
37035 //el.on("click", this.onClick, this);
37036 //el.on("dblclick", this.onDblClick, this);
37039 // console.log(this);
37041 initEvents : function(){
37042 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37045 var a = this.ranchor;
37047 var el = Roo.get(a);
37049 if(Roo.isOpera){ // opera render bug ignores the CSS
37050 el.setStyle("text-decoration", "none");
37053 el.on("click", this.onClick, this);
37054 el.on("dblclick", this.onDblClick, this);
37055 el.on("contextmenu", this.onContextMenu, this);
37059 /*onSelectedChange : function(state){
37062 this.addClass("x-tree-selected");
37065 this.removeClass("x-tree-selected");
37068 addClass : function(cls){
37070 Roo.fly(this.elRow).addClass(cls);
37076 removeClass : function(cls){
37078 Roo.fly(this.elRow).removeClass(cls);
37084 });//<Script type="text/javascript">
37088 * Ext JS Library 1.1.1
37089 * Copyright(c) 2006-2007, Ext JS, LLC.
37091 * Originally Released Under LGPL - original licence link has changed is not relivant.
37094 * <script type="text/javascript">
37099 * @class Roo.tree.ColumnTree
37100 * @extends Roo.data.TreePanel
37101 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37102 * @cfg {int} borderWidth compined right/left border allowance
37104 * @param {String/HTMLElement/Element} el The container element
37105 * @param {Object} config
37107 Roo.tree.ColumnTree = function(el, config)
37109 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37113 * Fire this event on a container when it resizes
37114 * @param {int} w Width
37115 * @param {int} h Height
37119 this.on('resize', this.onResize, this);
37122 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37126 borderWidth: Roo.isBorderBox ? 0 : 2,
37129 render : function(){
37130 // add the header.....
37132 Roo.tree.ColumnTree.superclass.render.apply(this);
37134 this.el.addClass('x-column-tree');
37136 this.headers = this.el.createChild(
37137 {cls:'x-tree-headers'},this.innerCt.dom);
37139 var cols = this.columns, c;
37140 var totalWidth = 0;
37142 var len = cols.length;
37143 for(var i = 0; i < len; i++){
37145 totalWidth += c.width;
37146 this.headEls.push(this.headers.createChild({
37147 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37149 cls:'x-tree-hd-text',
37152 style:'width:'+(c.width-this.borderWidth)+'px;'
37155 this.headers.createChild({cls:'x-clear'});
37156 // prevent floats from wrapping when clipped
37157 this.headers.setWidth(totalWidth);
37158 //this.innerCt.setWidth(totalWidth);
37159 this.innerCt.setStyle({ overflow: 'auto' });
37160 this.onResize(this.width, this.height);
37164 onResize : function(w,h)
37169 this.innerCt.setWidth(this.width);
37170 this.innerCt.setHeight(this.height-20);
37173 var cols = this.columns, c;
37174 var totalWidth = 0;
37176 var len = cols.length;
37177 for(var i = 0; i < len; i++){
37179 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37180 // it's the expander..
37181 expEl = this.headEls[i];
37184 totalWidth += c.width;
37188 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37190 this.headers.setWidth(w-20);
37199 * Ext JS Library 1.1.1
37200 * Copyright(c) 2006-2007, Ext JS, LLC.
37202 * Originally Released Under LGPL - original licence link has changed is not relivant.
37205 * <script type="text/javascript">
37209 * @class Roo.menu.Menu
37210 * @extends Roo.util.Observable
37211 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37212 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37214 * Creates a new Menu
37215 * @param {Object} config Configuration options
37217 Roo.menu.Menu = function(config){
37218 Roo.apply(this, config);
37219 this.id = this.id || Roo.id();
37222 * @event beforeshow
37223 * Fires before this menu is displayed
37224 * @param {Roo.menu.Menu} this
37228 * @event beforehide
37229 * Fires before this menu is hidden
37230 * @param {Roo.menu.Menu} this
37235 * Fires after this menu is displayed
37236 * @param {Roo.menu.Menu} this
37241 * Fires after this menu is hidden
37242 * @param {Roo.menu.Menu} this
37247 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37248 * @param {Roo.menu.Menu} this
37249 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37250 * @param {Roo.EventObject} e
37255 * Fires when the mouse is hovering over this menu
37256 * @param {Roo.menu.Menu} this
37257 * @param {Roo.EventObject} e
37258 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37263 * Fires when the mouse exits this menu
37264 * @param {Roo.menu.Menu} this
37265 * @param {Roo.EventObject} e
37266 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37271 * Fires when a menu item contained in this menu is clicked
37272 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37273 * @param {Roo.EventObject} e
37277 if (this.registerMenu) {
37278 Roo.menu.MenuMgr.register(this);
37281 var mis = this.items;
37282 this.items = new Roo.util.MixedCollection();
37284 this.add.apply(this, mis);
37288 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37290 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37294 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37295 * for bottom-right shadow (defaults to "sides")
37299 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37300 * this menu (defaults to "tl-tr?")
37302 subMenuAlign : "tl-tr?",
37304 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37305 * relative to its element of origin (defaults to "tl-bl?")
37307 defaultAlign : "tl-bl?",
37309 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37311 allowOtherMenus : false,
37313 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37315 registerMenu : true,
37320 render : function(){
37324 var el = this.el = new Roo.Layer({
37326 shadow:this.shadow,
37328 parentEl: this.parentEl || document.body,
37332 this.keyNav = new Roo.menu.MenuNav(this);
37335 el.addClass("x-menu-plain");
37338 el.addClass(this.cls);
37340 // generic focus element
37341 this.focusEl = el.createChild({
37342 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37344 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37345 //disabling touch- as it's causing issues ..
37346 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37347 ul.on('click' , this.onClick, this);
37350 ul.on("mouseover", this.onMouseOver, this);
37351 ul.on("mouseout", this.onMouseOut, this);
37352 this.items.each(function(item){
37357 var li = document.createElement("li");
37358 li.className = "x-menu-list-item";
37359 ul.dom.appendChild(li);
37360 item.render(li, this);
37367 autoWidth : function(){
37368 var el = this.el, ul = this.ul;
37372 var w = this.width;
37375 }else if(Roo.isIE){
37376 el.setWidth(this.minWidth);
37377 var t = el.dom.offsetWidth; // force recalc
37378 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37383 delayAutoWidth : function(){
37386 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37388 this.awTask.delay(20);
37393 findTargetItem : function(e){
37394 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37395 if(t && t.menuItemId){
37396 return this.items.get(t.menuItemId);
37401 onClick : function(e){
37402 Roo.log("menu.onClick");
37403 var t = this.findTargetItem(e);
37408 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37409 if(t == this.activeItem && t.shouldDeactivate(e)){
37410 this.activeItem.deactivate();
37411 delete this.activeItem;
37415 this.setActiveItem(t, true);
37423 this.fireEvent("click", this, t, e);
37427 setActiveItem : function(item, autoExpand){
37428 if(item != this.activeItem){
37429 if(this.activeItem){
37430 this.activeItem.deactivate();
37432 this.activeItem = item;
37433 item.activate(autoExpand);
37434 }else if(autoExpand){
37440 tryActivate : function(start, step){
37441 var items = this.items;
37442 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37443 var item = items.get(i);
37444 if(!item.disabled && item.canActivate){
37445 this.setActiveItem(item, false);
37453 onMouseOver : function(e){
37455 if(t = this.findTargetItem(e)){
37456 if(t.canActivate && !t.disabled){
37457 this.setActiveItem(t, true);
37460 this.fireEvent("mouseover", this, e, t);
37464 onMouseOut : function(e){
37466 if(t = this.findTargetItem(e)){
37467 if(t == this.activeItem && t.shouldDeactivate(e)){
37468 this.activeItem.deactivate();
37469 delete this.activeItem;
37472 this.fireEvent("mouseout", this, e, t);
37476 * Read-only. Returns true if the menu is currently displayed, else false.
37479 isVisible : function(){
37480 return this.el && !this.hidden;
37484 * Displays this menu relative to another element
37485 * @param {String/HTMLElement/Roo.Element} element The element to align to
37486 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37487 * the element (defaults to this.defaultAlign)
37488 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37490 show : function(el, pos, parentMenu){
37491 this.parentMenu = parentMenu;
37495 this.fireEvent("beforeshow", this);
37496 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37500 * Displays this menu at a specific xy position
37501 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37502 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37504 showAt : function(xy, parentMenu, /* private: */_e){
37505 this.parentMenu = parentMenu;
37510 this.fireEvent("beforeshow", this);
37511 xy = this.el.adjustForConstraints(xy);
37515 this.hidden = false;
37517 this.fireEvent("show", this);
37520 focus : function(){
37522 this.doFocus.defer(50, this);
37526 doFocus : function(){
37528 this.focusEl.focus();
37533 * Hides this menu and optionally all parent menus
37534 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37536 hide : function(deep){
37537 if(this.el && this.isVisible()){
37538 this.fireEvent("beforehide", this);
37539 if(this.activeItem){
37540 this.activeItem.deactivate();
37541 this.activeItem = null;
37544 this.hidden = true;
37545 this.fireEvent("hide", this);
37547 if(deep === true && this.parentMenu){
37548 this.parentMenu.hide(true);
37553 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37554 * Any of the following are valid:
37556 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37557 * <li>An HTMLElement object which will be converted to a menu item</li>
37558 * <li>A menu item config object that will be created as a new menu item</li>
37559 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37560 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37565 var menu = new Roo.menu.Menu();
37567 // Create a menu item to add by reference
37568 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37570 // Add a bunch of items at once using different methods.
37571 // Only the last item added will be returned.
37572 var item = menu.add(
37573 menuItem, // add existing item by ref
37574 'Dynamic Item', // new TextItem
37575 '-', // new separator
37576 { text: 'Config Item' } // new item by config
37579 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37580 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37583 var a = arguments, l = a.length, item;
37584 for(var i = 0; i < l; i++){
37586 if ((typeof(el) == "object") && el.xtype && el.xns) {
37587 el = Roo.factory(el, Roo.menu);
37590 if(el.render){ // some kind of Item
37591 item = this.addItem(el);
37592 }else if(typeof el == "string"){ // string
37593 if(el == "separator" || el == "-"){
37594 item = this.addSeparator();
37596 item = this.addText(el);
37598 }else if(el.tagName || el.el){ // element
37599 item = this.addElement(el);
37600 }else if(typeof el == "object"){ // must be menu item config?
37601 item = this.addMenuItem(el);
37608 * Returns this menu's underlying {@link Roo.Element} object
37609 * @return {Roo.Element} The element
37611 getEl : function(){
37619 * Adds a separator bar to the menu
37620 * @return {Roo.menu.Item} The menu item that was added
37622 addSeparator : function(){
37623 return this.addItem(new Roo.menu.Separator());
37627 * Adds an {@link Roo.Element} object to the menu
37628 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37629 * @return {Roo.menu.Item} The menu item that was added
37631 addElement : function(el){
37632 return this.addItem(new Roo.menu.BaseItem(el));
37636 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37637 * @param {Roo.menu.Item} item The menu item to add
37638 * @return {Roo.menu.Item} The menu item that was added
37640 addItem : function(item){
37641 this.items.add(item);
37643 var li = document.createElement("li");
37644 li.className = "x-menu-list-item";
37645 this.ul.dom.appendChild(li);
37646 item.render(li, this);
37647 this.delayAutoWidth();
37653 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37654 * @param {Object} config A MenuItem config object
37655 * @return {Roo.menu.Item} The menu item that was added
37657 addMenuItem : function(config){
37658 if(!(config instanceof Roo.menu.Item)){
37659 if(typeof config.checked == "boolean"){ // must be check menu item config?
37660 config = new Roo.menu.CheckItem(config);
37662 config = new Roo.menu.Item(config);
37665 return this.addItem(config);
37669 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37670 * @param {String} text The text to display in the menu item
37671 * @return {Roo.menu.Item} The menu item that was added
37673 addText : function(text){
37674 return this.addItem(new Roo.menu.TextItem({ text : text }));
37678 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37679 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37680 * @param {Roo.menu.Item} item The menu item to add
37681 * @return {Roo.menu.Item} The menu item that was added
37683 insert : function(index, item){
37684 this.items.insert(index, item);
37686 var li = document.createElement("li");
37687 li.className = "x-menu-list-item";
37688 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37689 item.render(li, this);
37690 this.delayAutoWidth();
37696 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37697 * @param {Roo.menu.Item} item The menu item to remove
37699 remove : function(item){
37700 this.items.removeKey(item.id);
37705 * Removes and destroys all items in the menu
37707 removeAll : function(){
37709 while(f = this.items.first()){
37715 // MenuNav is a private utility class used internally by the Menu
37716 Roo.menu.MenuNav = function(menu){
37717 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37718 this.scope = this.menu = menu;
37721 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37722 doRelay : function(e, h){
37723 var k = e.getKey();
37724 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37725 this.menu.tryActivate(0, 1);
37728 return h.call(this.scope || this, e, this.menu);
37731 up : function(e, m){
37732 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37733 m.tryActivate(m.items.length-1, -1);
37737 down : function(e, m){
37738 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37739 m.tryActivate(0, 1);
37743 right : function(e, m){
37745 m.activeItem.expandMenu(true);
37749 left : function(e, m){
37751 if(m.parentMenu && m.parentMenu.activeItem){
37752 m.parentMenu.activeItem.activate();
37756 enter : function(e, m){
37758 e.stopPropagation();
37759 m.activeItem.onClick(e);
37760 m.fireEvent("click", this, m.activeItem);
37766 * Ext JS Library 1.1.1
37767 * Copyright(c) 2006-2007, Ext JS, LLC.
37769 * Originally Released Under LGPL - original licence link has changed is not relivant.
37772 * <script type="text/javascript">
37776 * @class Roo.menu.MenuMgr
37777 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37780 Roo.menu.MenuMgr = function(){
37781 var menus, active, groups = {}, attached = false, lastShow = new Date();
37783 // private - called when first menu is created
37786 active = new Roo.util.MixedCollection();
37787 Roo.get(document).addKeyListener(27, function(){
37788 if(active.length > 0){
37795 function hideAll(){
37796 if(active && active.length > 0){
37797 var c = active.clone();
37798 c.each(function(m){
37805 function onHide(m){
37807 if(active.length < 1){
37808 Roo.get(document).un("mousedown", onMouseDown);
37814 function onShow(m){
37815 var last = active.last();
37816 lastShow = new Date();
37819 Roo.get(document).on("mousedown", onMouseDown);
37823 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37824 m.parentMenu.activeChild = m;
37825 }else if(last && last.isVisible()){
37826 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37831 function onBeforeHide(m){
37833 m.activeChild.hide();
37835 if(m.autoHideTimer){
37836 clearTimeout(m.autoHideTimer);
37837 delete m.autoHideTimer;
37842 function onBeforeShow(m){
37843 var pm = m.parentMenu;
37844 if(!pm && !m.allowOtherMenus){
37846 }else if(pm && pm.activeChild && active != m){
37847 pm.activeChild.hide();
37852 function onMouseDown(e){
37853 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37859 function onBeforeCheck(mi, state){
37861 var g = groups[mi.group];
37862 for(var i = 0, l = g.length; i < l; i++){
37864 g[i].setChecked(false);
37873 * Hides all menus that are currently visible
37875 hideAll : function(){
37880 register : function(menu){
37884 menus[menu.id] = menu;
37885 menu.on("beforehide", onBeforeHide);
37886 menu.on("hide", onHide);
37887 menu.on("beforeshow", onBeforeShow);
37888 menu.on("show", onShow);
37889 var g = menu.group;
37890 if(g && menu.events["checkchange"]){
37894 groups[g].push(menu);
37895 menu.on("checkchange", onCheck);
37900 * Returns a {@link Roo.menu.Menu} object
37901 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37902 * be used to generate and return a new Menu instance.
37904 get : function(menu){
37905 if(typeof menu == "string"){ // menu id
37906 return menus[menu];
37907 }else if(menu.events){ // menu instance
37909 }else if(typeof menu.length == 'number'){ // array of menu items?
37910 return new Roo.menu.Menu({items:menu});
37911 }else{ // otherwise, must be a config
37912 return new Roo.menu.Menu(menu);
37917 unregister : function(menu){
37918 delete menus[menu.id];
37919 menu.un("beforehide", onBeforeHide);
37920 menu.un("hide", onHide);
37921 menu.un("beforeshow", onBeforeShow);
37922 menu.un("show", onShow);
37923 var g = menu.group;
37924 if(g && menu.events["checkchange"]){
37925 groups[g].remove(menu);
37926 menu.un("checkchange", onCheck);
37931 registerCheckable : function(menuItem){
37932 var g = menuItem.group;
37937 groups[g].push(menuItem);
37938 menuItem.on("beforecheckchange", onBeforeCheck);
37943 unregisterCheckable : function(menuItem){
37944 var g = menuItem.group;
37946 groups[g].remove(menuItem);
37947 menuItem.un("beforecheckchange", onBeforeCheck);
37953 * Ext JS Library 1.1.1
37954 * Copyright(c) 2006-2007, Ext JS, LLC.
37956 * Originally Released Under LGPL - original licence link has changed is not relivant.
37959 * <script type="text/javascript">
37964 * @class Roo.menu.BaseItem
37965 * @extends Roo.Component
37966 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37967 * management and base configuration options shared by all menu components.
37969 * Creates a new BaseItem
37970 * @param {Object} config Configuration options
37972 Roo.menu.BaseItem = function(config){
37973 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37978 * Fires when this item is clicked
37979 * @param {Roo.menu.BaseItem} this
37980 * @param {Roo.EventObject} e
37985 * Fires when this item is activated
37986 * @param {Roo.menu.BaseItem} this
37990 * @event deactivate
37991 * Fires when this item is deactivated
37992 * @param {Roo.menu.BaseItem} this
37998 this.on("click", this.handler, this.scope, true);
38002 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38004 * @cfg {Function} handler
38005 * A function that will handle the click event of this menu item (defaults to undefined)
38008 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38010 canActivate : false,
38013 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38018 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38020 activeClass : "x-menu-item-active",
38022 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38024 hideOnClick : true,
38026 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38031 ctype: "Roo.menu.BaseItem",
38034 actionMode : "container",
38037 render : function(container, parentMenu){
38038 this.parentMenu = parentMenu;
38039 Roo.menu.BaseItem.superclass.render.call(this, container);
38040 this.container.menuItemId = this.id;
38044 onRender : function(container, position){
38045 this.el = Roo.get(this.el);
38046 container.dom.appendChild(this.el.dom);
38050 onClick : function(e){
38051 if(!this.disabled && this.fireEvent("click", this, e) !== false
38052 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38053 this.handleClick(e);
38060 activate : function(){
38064 var li = this.container;
38065 li.addClass(this.activeClass);
38066 this.region = li.getRegion().adjust(2, 2, -2, -2);
38067 this.fireEvent("activate", this);
38072 deactivate : function(){
38073 this.container.removeClass(this.activeClass);
38074 this.fireEvent("deactivate", this);
38078 shouldDeactivate : function(e){
38079 return !this.region || !this.region.contains(e.getPoint());
38083 handleClick : function(e){
38084 if(this.hideOnClick){
38085 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38090 expandMenu : function(autoActivate){
38095 hideMenu : function(){
38100 * Ext JS Library 1.1.1
38101 * Copyright(c) 2006-2007, Ext JS, LLC.
38103 * Originally Released Under LGPL - original licence link has changed is not relivant.
38106 * <script type="text/javascript">
38110 * @class Roo.menu.Adapter
38111 * @extends Roo.menu.BaseItem
38112 * 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.
38113 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38115 * Creates a new Adapter
38116 * @param {Object} config Configuration options
38118 Roo.menu.Adapter = function(component, config){
38119 Roo.menu.Adapter.superclass.constructor.call(this, config);
38120 this.component = component;
38122 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38124 canActivate : true,
38127 onRender : function(container, position){
38128 this.component.render(container);
38129 this.el = this.component.getEl();
38133 activate : function(){
38137 this.component.focus();
38138 this.fireEvent("activate", this);
38143 deactivate : function(){
38144 this.fireEvent("deactivate", this);
38148 disable : function(){
38149 this.component.disable();
38150 Roo.menu.Adapter.superclass.disable.call(this);
38154 enable : function(){
38155 this.component.enable();
38156 Roo.menu.Adapter.superclass.enable.call(this);
38160 * Ext JS Library 1.1.1
38161 * Copyright(c) 2006-2007, Ext JS, LLC.
38163 * Originally Released Under LGPL - original licence link has changed is not relivant.
38166 * <script type="text/javascript">
38170 * @class Roo.menu.TextItem
38171 * @extends Roo.menu.BaseItem
38172 * Adds a static text string to a menu, usually used as either a heading or group separator.
38173 * Note: old style constructor with text is still supported.
38176 * Creates a new TextItem
38177 * @param {Object} cfg Configuration
38179 Roo.menu.TextItem = function(cfg){
38180 if (typeof(cfg) == 'string') {
38183 Roo.apply(this,cfg);
38186 Roo.menu.TextItem.superclass.constructor.call(this);
38189 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38191 * @cfg {Boolean} text Text to show on item.
38196 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38198 hideOnClick : false,
38200 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38202 itemCls : "x-menu-text",
38205 onRender : function(){
38206 var s = document.createElement("span");
38207 s.className = this.itemCls;
38208 s.innerHTML = this.text;
38210 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38214 * Ext JS Library 1.1.1
38215 * Copyright(c) 2006-2007, Ext JS, LLC.
38217 * Originally Released Under LGPL - original licence link has changed is not relivant.
38220 * <script type="text/javascript">
38224 * @class Roo.menu.Separator
38225 * @extends Roo.menu.BaseItem
38226 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38227 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38229 * @param {Object} config Configuration options
38231 Roo.menu.Separator = function(config){
38232 Roo.menu.Separator.superclass.constructor.call(this, config);
38235 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38237 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38239 itemCls : "x-menu-sep",
38241 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38243 hideOnClick : false,
38246 onRender : function(li){
38247 var s = document.createElement("span");
38248 s.className = this.itemCls;
38249 s.innerHTML = " ";
38251 li.addClass("x-menu-sep-li");
38252 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38256 * Ext JS Library 1.1.1
38257 * Copyright(c) 2006-2007, Ext JS, LLC.
38259 * Originally Released Under LGPL - original licence link has changed is not relivant.
38262 * <script type="text/javascript">
38265 * @class Roo.menu.Item
38266 * @extends Roo.menu.BaseItem
38267 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38268 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38269 * activation and click handling.
38271 * Creates a new Item
38272 * @param {Object} config Configuration options
38274 Roo.menu.Item = function(config){
38275 Roo.menu.Item.superclass.constructor.call(this, config);
38277 this.menu = Roo.menu.MenuMgr.get(this.menu);
38280 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38283 * @cfg {String} text
38284 * The text to show on the menu item.
38288 * @cfg {String} HTML to render in menu
38289 * The text to show on the menu item (HTML version).
38293 * @cfg {String} icon
38294 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38298 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38300 itemCls : "x-menu-item",
38302 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38304 canActivate : true,
38306 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38309 // doc'd in BaseItem
38313 ctype: "Roo.menu.Item",
38316 onRender : function(container, position){
38317 var el = document.createElement("a");
38318 el.hideFocus = true;
38319 el.unselectable = "on";
38320 el.href = this.href || "#";
38321 if(this.hrefTarget){
38322 el.target = this.hrefTarget;
38324 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38326 var html = this.html.length ? this.html : String.format('{0}',this.text);
38328 el.innerHTML = String.format(
38329 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38330 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38332 Roo.menu.Item.superclass.onRender.call(this, container, position);
38336 * Sets the text to display in this menu item
38337 * @param {String} text The text to display
38338 * @param {Boolean} isHTML true to indicate text is pure html.
38340 setText : function(text, isHTML){
38348 var html = this.html.length ? this.html : String.format('{0}',this.text);
38350 this.el.update(String.format(
38351 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38352 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38353 this.parentMenu.autoWidth();
38358 handleClick : function(e){
38359 if(!this.href){ // if no link defined, stop the event automatically
38362 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38366 activate : function(autoExpand){
38367 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38377 shouldDeactivate : function(e){
38378 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38379 if(this.menu && this.menu.isVisible()){
38380 return !this.menu.getEl().getRegion().contains(e.getPoint());
38388 deactivate : function(){
38389 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38394 expandMenu : function(autoActivate){
38395 if(!this.disabled && this.menu){
38396 clearTimeout(this.hideTimer);
38397 delete this.hideTimer;
38398 if(!this.menu.isVisible() && !this.showTimer){
38399 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38400 }else if (this.menu.isVisible() && autoActivate){
38401 this.menu.tryActivate(0, 1);
38407 deferExpand : function(autoActivate){
38408 delete this.showTimer;
38409 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38411 this.menu.tryActivate(0, 1);
38416 hideMenu : function(){
38417 clearTimeout(this.showTimer);
38418 delete this.showTimer;
38419 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38420 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38425 deferHide : function(){
38426 delete this.hideTimer;
38431 * Ext JS Library 1.1.1
38432 * Copyright(c) 2006-2007, Ext JS, LLC.
38434 * Originally Released Under LGPL - original licence link has changed is not relivant.
38437 * <script type="text/javascript">
38441 * @class Roo.menu.CheckItem
38442 * @extends Roo.menu.Item
38443 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38445 * Creates a new CheckItem
38446 * @param {Object} config Configuration options
38448 Roo.menu.CheckItem = function(config){
38449 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38452 * @event beforecheckchange
38453 * Fires before the checked value is set, providing an opportunity to cancel if needed
38454 * @param {Roo.menu.CheckItem} this
38455 * @param {Boolean} checked The new checked value that will be set
38457 "beforecheckchange" : true,
38459 * @event checkchange
38460 * Fires after the checked value has been set
38461 * @param {Roo.menu.CheckItem} this
38462 * @param {Boolean} checked The checked value that was set
38464 "checkchange" : true
38466 if(this.checkHandler){
38467 this.on('checkchange', this.checkHandler, this.scope);
38470 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38472 * @cfg {String} group
38473 * All check items with the same group name will automatically be grouped into a single-select
38474 * radio button group (defaults to '')
38477 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38479 itemCls : "x-menu-item x-menu-check-item",
38481 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38483 groupClass : "x-menu-group-item",
38486 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38487 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38488 * initialized with checked = true will be rendered as checked.
38493 ctype: "Roo.menu.CheckItem",
38496 onRender : function(c){
38497 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38499 this.el.addClass(this.groupClass);
38501 Roo.menu.MenuMgr.registerCheckable(this);
38503 this.checked = false;
38504 this.setChecked(true, true);
38509 destroy : function(){
38511 Roo.menu.MenuMgr.unregisterCheckable(this);
38513 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38517 * Set the checked state of this item
38518 * @param {Boolean} checked The new checked value
38519 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38521 setChecked : function(state, suppressEvent){
38522 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38523 if(this.container){
38524 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38526 this.checked = state;
38527 if(suppressEvent !== true){
38528 this.fireEvent("checkchange", this, state);
38534 handleClick : function(e){
38535 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38536 this.setChecked(!this.checked);
38538 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38542 * Ext JS Library 1.1.1
38543 * Copyright(c) 2006-2007, Ext JS, LLC.
38545 * Originally Released Under LGPL - original licence link has changed is not relivant.
38548 * <script type="text/javascript">
38552 * @class Roo.menu.DateItem
38553 * @extends Roo.menu.Adapter
38554 * A menu item that wraps the {@link Roo.DatPicker} component.
38556 * Creates a new DateItem
38557 * @param {Object} config Configuration options
38559 Roo.menu.DateItem = function(config){
38560 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38561 /** The Roo.DatePicker object @type Roo.DatePicker */
38562 this.picker = this.component;
38563 this.addEvents({select: true});
38565 this.picker.on("render", function(picker){
38566 picker.getEl().swallowEvent("click");
38567 picker.container.addClass("x-menu-date-item");
38570 this.picker.on("select", this.onSelect, this);
38573 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38575 onSelect : function(picker, date){
38576 this.fireEvent("select", this, date, picker);
38577 Roo.menu.DateItem.superclass.handleClick.call(this);
38581 * Ext JS Library 1.1.1
38582 * Copyright(c) 2006-2007, Ext JS, LLC.
38584 * Originally Released Under LGPL - original licence link has changed is not relivant.
38587 * <script type="text/javascript">
38591 * @class Roo.menu.ColorItem
38592 * @extends Roo.menu.Adapter
38593 * A menu item that wraps the {@link Roo.ColorPalette} component.
38595 * Creates a new ColorItem
38596 * @param {Object} config Configuration options
38598 Roo.menu.ColorItem = function(config){
38599 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38600 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38601 this.palette = this.component;
38602 this.relayEvents(this.palette, ["select"]);
38603 if(this.selectHandler){
38604 this.on('select', this.selectHandler, this.scope);
38607 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38609 * Ext JS Library 1.1.1
38610 * Copyright(c) 2006-2007, Ext JS, LLC.
38612 * Originally Released Under LGPL - original licence link has changed is not relivant.
38615 * <script type="text/javascript">
38620 * @class Roo.menu.DateMenu
38621 * @extends Roo.menu.Menu
38622 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38624 * Creates a new DateMenu
38625 * @param {Object} config Configuration options
38627 Roo.menu.DateMenu = function(config){
38628 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38630 var di = new Roo.menu.DateItem(config);
38633 * The {@link Roo.DatePicker} instance for this DateMenu
38636 this.picker = di.picker;
38639 * @param {DatePicker} picker
38640 * @param {Date} date
38642 this.relayEvents(di, ["select"]);
38643 this.on('beforeshow', function(){
38645 this.picker.hideMonthPicker(false);
38649 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38653 * Ext JS Library 1.1.1
38654 * Copyright(c) 2006-2007, Ext JS, LLC.
38656 * Originally Released Under LGPL - original licence link has changed is not relivant.
38659 * <script type="text/javascript">
38664 * @class Roo.menu.ColorMenu
38665 * @extends Roo.menu.Menu
38666 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38668 * Creates a new ColorMenu
38669 * @param {Object} config Configuration options
38671 Roo.menu.ColorMenu = function(config){
38672 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38674 var ci = new Roo.menu.ColorItem(config);
38677 * The {@link Roo.ColorPalette} instance for this ColorMenu
38678 * @type ColorPalette
38680 this.palette = ci.palette;
38683 * @param {ColorPalette} palette
38684 * @param {String} color
38686 this.relayEvents(ci, ["select"]);
38688 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38690 * Ext JS Library 1.1.1
38691 * Copyright(c) 2006-2007, Ext JS, LLC.
38693 * Originally Released Under LGPL - original licence link has changed is not relivant.
38696 * <script type="text/javascript">
38700 * @class Roo.form.Field
38701 * @extends Roo.BoxComponent
38702 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38704 * Creates a new Field
38705 * @param {Object} config Configuration options
38707 Roo.form.Field = function(config){
38708 Roo.form.Field.superclass.constructor.call(this, config);
38711 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38713 * @cfg {String} fieldLabel Label to use when rendering a form.
38716 * @cfg {String} qtip Mouse over tip
38720 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38722 invalidClass : "x-form-invalid",
38724 * @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")
38726 invalidText : "The value in this field is invalid",
38728 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38730 focusClass : "x-form-focus",
38732 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38733 automatic validation (defaults to "keyup").
38735 validationEvent : "keyup",
38737 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38739 validateOnBlur : true,
38741 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38743 validationDelay : 250,
38745 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38746 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38748 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38750 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38752 fieldClass : "x-form-field",
38754 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38757 ----------- ----------------------------------------------------------------------
38758 qtip Display a quick tip when the user hovers over the field
38759 title Display a default browser title attribute popup
38760 under Add a block div beneath the field containing the error text
38761 side Add an error icon to the right of the field with a popup on hover
38762 [element id] Add the error text directly to the innerHTML of the specified element
38765 msgTarget : 'qtip',
38767 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38772 * @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.
38777 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38782 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38784 inputType : undefined,
38787 * @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).
38789 tabIndex : undefined,
38792 isFormField : true,
38797 * @property {Roo.Element} fieldEl
38798 * Element Containing the rendered Field (with label etc.)
38801 * @cfg {Mixed} value A value to initialize this field with.
38806 * @cfg {String} name The field's HTML name attribute.
38809 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38812 loadedValue : false,
38816 initComponent : function(){
38817 Roo.form.Field.superclass.initComponent.call(this);
38821 * Fires when this field receives input focus.
38822 * @param {Roo.form.Field} this
38827 * Fires when this field loses input focus.
38828 * @param {Roo.form.Field} this
38832 * @event specialkey
38833 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38834 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38835 * @param {Roo.form.Field} this
38836 * @param {Roo.EventObject} e The event object
38841 * Fires just before the field blurs if the field value has changed.
38842 * @param {Roo.form.Field} this
38843 * @param {Mixed} newValue The new value
38844 * @param {Mixed} oldValue The original value
38849 * Fires after the field has been marked as invalid.
38850 * @param {Roo.form.Field} this
38851 * @param {String} msg The validation message
38856 * Fires after the field has been validated with no errors.
38857 * @param {Roo.form.Field} this
38862 * Fires after the key up
38863 * @param {Roo.form.Field} this
38864 * @param {Roo.EventObject} e The event Object
38871 * Returns the name attribute of the field if available
38872 * @return {String} name The field name
38874 getName: function(){
38875 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38879 onRender : function(ct, position){
38880 Roo.form.Field.superclass.onRender.call(this, ct, position);
38882 var cfg = this.getAutoCreate();
38884 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38886 if (!cfg.name.length) {
38889 if(this.inputType){
38890 cfg.type = this.inputType;
38892 this.el = ct.createChild(cfg, position);
38894 var type = this.el.dom.type;
38896 if(type == 'password'){
38899 this.el.addClass('x-form-'+type);
38902 this.el.dom.readOnly = true;
38904 if(this.tabIndex !== undefined){
38905 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38908 this.el.addClass([this.fieldClass, this.cls]);
38913 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38914 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38915 * @return {Roo.form.Field} this
38917 applyTo : function(target){
38918 this.allowDomMove = false;
38919 this.el = Roo.get(target);
38920 this.render(this.el.dom.parentNode);
38925 initValue : function(){
38926 if(this.value !== undefined){
38927 this.setValue(this.value);
38928 }else if(this.el.dom.value.length > 0){
38929 this.setValue(this.el.dom.value);
38934 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38935 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38937 isDirty : function() {
38938 if(this.disabled) {
38941 return String(this.getValue()) !== String(this.originalValue);
38945 * stores the current value in loadedValue
38947 resetHasChanged : function()
38949 this.loadedValue = String(this.getValue());
38952 * checks the current value against the 'loaded' value.
38953 * Note - will return false if 'resetHasChanged' has not been called first.
38955 hasChanged : function()
38957 if(this.disabled || this.readOnly) {
38960 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38966 afterRender : function(){
38967 Roo.form.Field.superclass.afterRender.call(this);
38972 fireKey : function(e){
38973 //Roo.log('field ' + e.getKey());
38974 if(e.isNavKeyPress()){
38975 this.fireEvent("specialkey", this, e);
38980 * Resets the current field value to the originally loaded value and clears any validation messages
38982 reset : function(){
38983 this.setValue(this.resetValue);
38984 this.originalValue = this.getValue();
38985 this.clearInvalid();
38989 initEvents : function(){
38990 // safari killled keypress - so keydown is now used..
38991 this.el.on("keydown" , this.fireKey, this);
38992 this.el.on("focus", this.onFocus, this);
38993 this.el.on("blur", this.onBlur, this);
38994 this.el.relayEvent('keyup', this);
38996 // reference to original value for reset
38997 this.originalValue = this.getValue();
38998 this.resetValue = this.getValue();
39002 onFocus : function(){
39003 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39004 this.el.addClass(this.focusClass);
39006 if(!this.hasFocus){
39007 this.hasFocus = true;
39008 this.startValue = this.getValue();
39009 this.fireEvent("focus", this);
39013 beforeBlur : Roo.emptyFn,
39016 onBlur : function(){
39018 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39019 this.el.removeClass(this.focusClass);
39021 this.hasFocus = false;
39022 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39025 var v = this.getValue();
39026 if(String(v) !== String(this.startValue)){
39027 this.fireEvent('change', this, v, this.startValue);
39029 this.fireEvent("blur", this);
39033 * Returns whether or not the field value is currently valid
39034 * @param {Boolean} preventMark True to disable marking the field invalid
39035 * @return {Boolean} True if the value is valid, else false
39037 isValid : function(preventMark){
39041 var restore = this.preventMark;
39042 this.preventMark = preventMark === true;
39043 var v = this.validateValue(this.processValue(this.getRawValue()));
39044 this.preventMark = restore;
39049 * Validates the field value
39050 * @return {Boolean} True if the value is valid, else false
39052 validate : function(){
39053 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39054 this.clearInvalid();
39060 processValue : function(value){
39065 // Subclasses should provide the validation implementation by overriding this
39066 validateValue : function(value){
39071 * Mark this field as invalid
39072 * @param {String} msg The validation message
39074 markInvalid : function(msg){
39075 if(!this.rendered || this.preventMark){ // not rendered
39079 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39081 obj.el.addClass(this.invalidClass);
39082 msg = msg || this.invalidText;
39083 switch(this.msgTarget){
39085 obj.el.dom.qtip = msg;
39086 obj.el.dom.qclass = 'x-form-invalid-tip';
39087 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39088 Roo.QuickTips.enable();
39092 this.el.dom.title = msg;
39096 var elp = this.el.findParent('.x-form-element', 5, true);
39097 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39098 this.errorEl.setWidth(elp.getWidth(true)-20);
39100 this.errorEl.update(msg);
39101 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39104 if(!this.errorIcon){
39105 var elp = this.el.findParent('.x-form-element', 5, true);
39106 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39108 this.alignErrorIcon();
39109 this.errorIcon.dom.qtip = msg;
39110 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39111 this.errorIcon.show();
39112 this.on('resize', this.alignErrorIcon, this);
39115 var t = Roo.getDom(this.msgTarget);
39117 t.style.display = this.msgDisplay;
39120 this.fireEvent('invalid', this, msg);
39124 alignErrorIcon : function(){
39125 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39129 * Clear any invalid styles/messages for this field
39131 clearInvalid : function(){
39132 if(!this.rendered || this.preventMark){ // not rendered
39135 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39137 obj.el.removeClass(this.invalidClass);
39138 switch(this.msgTarget){
39140 obj.el.dom.qtip = '';
39143 this.el.dom.title = '';
39147 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39151 if(this.errorIcon){
39152 this.errorIcon.dom.qtip = '';
39153 this.errorIcon.hide();
39154 this.un('resize', this.alignErrorIcon, this);
39158 var t = Roo.getDom(this.msgTarget);
39160 t.style.display = 'none';
39163 this.fireEvent('valid', this);
39167 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39168 * @return {Mixed} value The field value
39170 getRawValue : function(){
39171 var v = this.el.getValue();
39177 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39178 * @return {Mixed} value The field value
39180 getValue : function(){
39181 var v = this.el.getValue();
39187 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39188 * @param {Mixed} value The value to set
39190 setRawValue : function(v){
39191 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39195 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39196 * @param {Mixed} value The value to set
39198 setValue : function(v){
39201 this.el.dom.value = (v === null || v === undefined ? '' : v);
39206 adjustSize : function(w, h){
39207 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39208 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39212 adjustWidth : function(tag, w){
39213 tag = tag.toLowerCase();
39214 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39215 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39216 if(tag == 'input'){
39219 if(tag == 'textarea'){
39222 }else if(Roo.isOpera){
39223 if(tag == 'input'){
39226 if(tag == 'textarea'){
39236 // anything other than normal should be considered experimental
39237 Roo.form.Field.msgFx = {
39239 show: function(msgEl, f){
39240 msgEl.setDisplayed('block');
39243 hide : function(msgEl, f){
39244 msgEl.setDisplayed(false).update('');
39249 show: function(msgEl, f){
39250 msgEl.slideIn('t', {stopFx:true});
39253 hide : function(msgEl, f){
39254 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39259 show: function(msgEl, f){
39260 msgEl.fixDisplay();
39261 msgEl.alignTo(f.el, 'tl-tr');
39262 msgEl.slideIn('l', {stopFx:true});
39265 hide : function(msgEl, f){
39266 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39271 * Ext JS Library 1.1.1
39272 * Copyright(c) 2006-2007, Ext JS, LLC.
39274 * Originally Released Under LGPL - original licence link has changed is not relivant.
39277 * <script type="text/javascript">
39282 * @class Roo.form.TextField
39283 * @extends Roo.form.Field
39284 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39285 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39287 * Creates a new TextField
39288 * @param {Object} config Configuration options
39290 Roo.form.TextField = function(config){
39291 Roo.form.TextField.superclass.constructor.call(this, config);
39295 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39296 * according to the default logic, but this event provides a hook for the developer to apply additional
39297 * logic at runtime to resize the field if needed.
39298 * @param {Roo.form.Field} this This text field
39299 * @param {Number} width The new field width
39305 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39307 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39311 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39315 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39319 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39323 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39327 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39329 disableKeyFilter : false,
39331 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39335 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39339 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39341 maxLength : Number.MAX_VALUE,
39343 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39345 minLengthText : "The minimum length for this field is {0}",
39347 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39349 maxLengthText : "The maximum length for this field is {0}",
39351 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39353 selectOnFocus : false,
39355 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39357 blankText : "This field is required",
39359 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39360 * If available, this function will be called only after the basic validators all return true, and will be passed the
39361 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39365 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39366 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39367 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39371 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39375 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39381 initEvents : function()
39383 if (this.emptyText) {
39384 this.el.attr('placeholder', this.emptyText);
39387 Roo.form.TextField.superclass.initEvents.call(this);
39388 if(this.validationEvent == 'keyup'){
39389 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39390 this.el.on('keyup', this.filterValidation, this);
39392 else if(this.validationEvent !== false){
39393 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39396 if(this.selectOnFocus){
39397 this.on("focus", this.preFocus, this);
39400 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39401 this.el.on("keypress", this.filterKeys, this);
39404 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39405 this.el.on("click", this.autoSize, this);
39407 if(this.el.is('input[type=password]') && Roo.isSafari){
39408 this.el.on('keydown', this.SafariOnKeyDown, this);
39412 processValue : function(value){
39413 if(this.stripCharsRe){
39414 var newValue = value.replace(this.stripCharsRe, '');
39415 if(newValue !== value){
39416 this.setRawValue(newValue);
39423 filterValidation : function(e){
39424 if(!e.isNavKeyPress()){
39425 this.validationTask.delay(this.validationDelay);
39430 onKeyUp : function(e){
39431 if(!e.isNavKeyPress()){
39437 * Resets the current field value to the originally-loaded value and clears any validation messages.
39440 reset : function(){
39441 Roo.form.TextField.superclass.reset.call(this);
39447 preFocus : function(){
39449 if(this.selectOnFocus){
39450 this.el.dom.select();
39456 filterKeys : function(e){
39457 var k = e.getKey();
39458 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39461 var c = e.getCharCode(), cc = String.fromCharCode(c);
39462 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39465 if(!this.maskRe.test(cc)){
39470 setValue : function(v){
39472 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39478 * Validates a value according to the field's validation rules and marks the field as invalid
39479 * if the validation fails
39480 * @param {Mixed} value The value to validate
39481 * @return {Boolean} True if the value is valid, else false
39483 validateValue : function(value){
39484 if(value.length < 1) { // if it's blank
39485 if(this.allowBlank){
39486 this.clearInvalid();
39489 this.markInvalid(this.blankText);
39493 if(value.length < this.minLength){
39494 this.markInvalid(String.format(this.minLengthText, this.minLength));
39497 if(value.length > this.maxLength){
39498 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39502 var vt = Roo.form.VTypes;
39503 if(!vt[this.vtype](value, this)){
39504 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39508 if(typeof this.validator == "function"){
39509 var msg = this.validator(value);
39511 this.markInvalid(msg);
39515 if(this.regex && !this.regex.test(value)){
39516 this.markInvalid(this.regexText);
39523 * Selects text in this field
39524 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39525 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39527 selectText : function(start, end){
39528 var v = this.getRawValue();
39530 start = start === undefined ? 0 : start;
39531 end = end === undefined ? v.length : end;
39532 var d = this.el.dom;
39533 if(d.setSelectionRange){
39534 d.setSelectionRange(start, end);
39535 }else if(d.createTextRange){
39536 var range = d.createTextRange();
39537 range.moveStart("character", start);
39538 range.moveEnd("character", v.length-end);
39545 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39546 * This only takes effect if grow = true, and fires the autosize event.
39548 autoSize : function(){
39549 if(!this.grow || !this.rendered){
39553 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39556 var v = el.dom.value;
39557 var d = document.createElement('div');
39558 d.appendChild(document.createTextNode(v));
39562 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39563 this.el.setWidth(w);
39564 this.fireEvent("autosize", this, w);
39568 SafariOnKeyDown : function(event)
39570 // this is a workaround for a password hang bug on chrome/ webkit.
39572 var isSelectAll = false;
39574 if(this.el.dom.selectionEnd > 0){
39575 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39577 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39578 event.preventDefault();
39583 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39585 event.preventDefault();
39586 // this is very hacky as keydown always get's upper case.
39588 var cc = String.fromCharCode(event.getCharCode());
39591 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39599 * Ext JS Library 1.1.1
39600 * Copyright(c) 2006-2007, Ext JS, LLC.
39602 * Originally Released Under LGPL - original licence link has changed is not relivant.
39605 * <script type="text/javascript">
39609 * @class Roo.form.Hidden
39610 * @extends Roo.form.TextField
39611 * Simple Hidden element used on forms
39613 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39616 * Creates a new Hidden form element.
39617 * @param {Object} config Configuration options
39622 // easy hidden field...
39623 Roo.form.Hidden = function(config){
39624 Roo.form.Hidden.superclass.constructor.call(this, config);
39627 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39629 inputType: 'hidden',
39632 labelSeparator: '',
39634 itemCls : 'x-form-item-display-none'
39642 * Ext JS Library 1.1.1
39643 * Copyright(c) 2006-2007, Ext JS, LLC.
39645 * Originally Released Under LGPL - original licence link has changed is not relivant.
39648 * <script type="text/javascript">
39652 * @class Roo.form.TriggerField
39653 * @extends Roo.form.TextField
39654 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39655 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39656 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39657 * for which you can provide a custom implementation. For example:
39659 var trigger = new Roo.form.TriggerField();
39660 trigger.onTriggerClick = myTriggerFn;
39661 trigger.applyTo('my-field');
39664 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39665 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39666 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39667 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39669 * Create a new TriggerField.
39670 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39671 * to the base TextField)
39673 Roo.form.TriggerField = function(config){
39674 this.mimicing = false;
39675 Roo.form.TriggerField.superclass.constructor.call(this, config);
39678 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39680 * @cfg {String} triggerClass A CSS class to apply to the trigger
39683 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39684 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39686 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39688 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39692 /** @cfg {Boolean} grow @hide */
39693 /** @cfg {Number} growMin @hide */
39694 /** @cfg {Number} growMax @hide */
39700 autoSize: Roo.emptyFn,
39704 deferHeight : true,
39707 actionMode : 'wrap',
39709 onResize : function(w, h){
39710 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39711 if(typeof w == 'number'){
39712 var x = w - this.trigger.getWidth();
39713 this.el.setWidth(this.adjustWidth('input', x));
39714 this.trigger.setStyle('left', x+'px');
39719 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39722 getResizeEl : function(){
39727 getPositionEl : function(){
39732 alignErrorIcon : function(){
39733 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39737 onRender : function(ct, position){
39738 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39739 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39740 this.trigger = this.wrap.createChild(this.triggerConfig ||
39741 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39742 if(this.hideTrigger){
39743 this.trigger.setDisplayed(false);
39745 this.initTrigger();
39747 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39752 initTrigger : function(){
39753 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39754 this.trigger.addClassOnOver('x-form-trigger-over');
39755 this.trigger.addClassOnClick('x-form-trigger-click');
39759 onDestroy : function(){
39761 this.trigger.removeAllListeners();
39762 this.trigger.remove();
39765 this.wrap.remove();
39767 Roo.form.TriggerField.superclass.onDestroy.call(this);
39771 onFocus : function(){
39772 Roo.form.TriggerField.superclass.onFocus.call(this);
39773 if(!this.mimicing){
39774 this.wrap.addClass('x-trigger-wrap-focus');
39775 this.mimicing = true;
39776 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39777 if(this.monitorTab){
39778 this.el.on("keydown", this.checkTab, this);
39784 checkTab : function(e){
39785 if(e.getKey() == e.TAB){
39786 this.triggerBlur();
39791 onBlur : function(){
39796 mimicBlur : function(e, t){
39797 if(!this.wrap.contains(t) && this.validateBlur()){
39798 this.triggerBlur();
39803 triggerBlur : function(){
39804 this.mimicing = false;
39805 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39806 if(this.monitorTab){
39807 this.el.un("keydown", this.checkTab, this);
39809 this.wrap.removeClass('x-trigger-wrap-focus');
39810 Roo.form.TriggerField.superclass.onBlur.call(this);
39814 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39815 validateBlur : function(e, t){
39820 onDisable : function(){
39821 Roo.form.TriggerField.superclass.onDisable.call(this);
39823 this.wrap.addClass('x-item-disabled');
39828 onEnable : function(){
39829 Roo.form.TriggerField.superclass.onEnable.call(this);
39831 this.wrap.removeClass('x-item-disabled');
39836 onShow : function(){
39837 var ae = this.getActionEl();
39840 ae.dom.style.display = '';
39841 ae.dom.style.visibility = 'visible';
39847 onHide : function(){
39848 var ae = this.getActionEl();
39849 ae.dom.style.display = 'none';
39853 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39854 * by an implementing function.
39856 * @param {EventObject} e
39858 onTriggerClick : Roo.emptyFn
39861 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39862 // to be extended by an implementing class. For an example of implementing this class, see the custom
39863 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39864 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39865 initComponent : function(){
39866 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39868 this.triggerConfig = {
39869 tag:'span', cls:'x-form-twin-triggers', cn:[
39870 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39871 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39875 getTrigger : function(index){
39876 return this.triggers[index];
39879 initTrigger : function(){
39880 var ts = this.trigger.select('.x-form-trigger', true);
39881 this.wrap.setStyle('overflow', 'hidden');
39882 var triggerField = this;
39883 ts.each(function(t, all, index){
39884 t.hide = function(){
39885 var w = triggerField.wrap.getWidth();
39886 this.dom.style.display = 'none';
39887 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39889 t.show = function(){
39890 var w = triggerField.wrap.getWidth();
39891 this.dom.style.display = '';
39892 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39894 var triggerIndex = 'Trigger'+(index+1);
39896 if(this['hide'+triggerIndex]){
39897 t.dom.style.display = 'none';
39899 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39900 t.addClassOnOver('x-form-trigger-over');
39901 t.addClassOnClick('x-form-trigger-click');
39903 this.triggers = ts.elements;
39906 onTrigger1Click : Roo.emptyFn,
39907 onTrigger2Click : Roo.emptyFn
39910 * Ext JS Library 1.1.1
39911 * Copyright(c) 2006-2007, Ext JS, LLC.
39913 * Originally Released Under LGPL - original licence link has changed is not relivant.
39916 * <script type="text/javascript">
39920 * @class Roo.form.TextArea
39921 * @extends Roo.form.TextField
39922 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39923 * support for auto-sizing.
39925 * Creates a new TextArea
39926 * @param {Object} config Configuration options
39928 Roo.form.TextArea = function(config){
39929 Roo.form.TextArea.superclass.constructor.call(this, config);
39930 // these are provided exchanges for backwards compat
39931 // minHeight/maxHeight were replaced by growMin/growMax to be
39932 // compatible with TextField growing config values
39933 if(this.minHeight !== undefined){
39934 this.growMin = this.minHeight;
39936 if(this.maxHeight !== undefined){
39937 this.growMax = this.maxHeight;
39941 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39943 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39947 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39951 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39952 * in the field (equivalent to setting overflow: hidden, defaults to false)
39954 preventScrollbars: false,
39956 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39957 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39961 onRender : function(ct, position){
39963 this.defaultAutoCreate = {
39965 style:"width:300px;height:60px;",
39966 autocomplete: "new-password"
39969 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39971 this.textSizeEl = Roo.DomHelper.append(document.body, {
39972 tag: "pre", cls: "x-form-grow-sizer"
39974 if(this.preventScrollbars){
39975 this.el.setStyle("overflow", "hidden");
39977 this.el.setHeight(this.growMin);
39981 onDestroy : function(){
39982 if(this.textSizeEl){
39983 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39985 Roo.form.TextArea.superclass.onDestroy.call(this);
39989 onKeyUp : function(e){
39990 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39996 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39997 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39999 autoSize : function(){
40000 if(!this.grow || !this.textSizeEl){
40004 var v = el.dom.value;
40005 var ts = this.textSizeEl;
40008 ts.appendChild(document.createTextNode(v));
40011 Roo.fly(ts).setWidth(this.el.getWidth());
40013 v = "  ";
40016 v = v.replace(/\n/g, '<p> </p>');
40018 v += " \n ";
40021 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40022 if(h != this.lastHeight){
40023 this.lastHeight = h;
40024 this.el.setHeight(h);
40025 this.fireEvent("autosize", this, h);
40030 * Ext JS Library 1.1.1
40031 * Copyright(c) 2006-2007, Ext JS, LLC.
40033 * Originally Released Under LGPL - original licence link has changed is not relivant.
40036 * <script type="text/javascript">
40041 * @class Roo.form.NumberField
40042 * @extends Roo.form.TextField
40043 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40045 * Creates a new NumberField
40046 * @param {Object} config Configuration options
40048 Roo.form.NumberField = function(config){
40049 Roo.form.NumberField.superclass.constructor.call(this, config);
40052 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40054 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40056 fieldClass: "x-form-field x-form-num-field",
40058 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40060 allowDecimals : true,
40062 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40064 decimalSeparator : ".",
40066 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40068 decimalPrecision : 2,
40070 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40072 allowNegative : true,
40074 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40076 minValue : Number.NEGATIVE_INFINITY,
40078 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40080 maxValue : Number.MAX_VALUE,
40082 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40084 minText : "The minimum value for this field is {0}",
40086 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40088 maxText : "The maximum value for this field is {0}",
40090 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40091 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40093 nanText : "{0} is not a valid number",
40096 initEvents : function(){
40097 Roo.form.NumberField.superclass.initEvents.call(this);
40098 var allowed = "0123456789";
40099 if(this.allowDecimals){
40100 allowed += this.decimalSeparator;
40102 if(this.allowNegative){
40105 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40106 var keyPress = function(e){
40107 var k = e.getKey();
40108 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40111 var c = e.getCharCode();
40112 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40116 this.el.on("keypress", keyPress, this);
40120 validateValue : function(value){
40121 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40124 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40127 var num = this.parseValue(value);
40129 this.markInvalid(String.format(this.nanText, value));
40132 if(num < this.minValue){
40133 this.markInvalid(String.format(this.minText, this.minValue));
40136 if(num > this.maxValue){
40137 this.markInvalid(String.format(this.maxText, this.maxValue));
40143 getValue : function(){
40144 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40148 parseValue : function(value){
40149 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40150 return isNaN(value) ? '' : value;
40154 fixPrecision : function(value){
40155 var nan = isNaN(value);
40156 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40157 return nan ? '' : value;
40159 return parseFloat(value).toFixed(this.decimalPrecision);
40162 setValue : function(v){
40163 v = this.fixPrecision(v);
40164 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40168 decimalPrecisionFcn : function(v){
40169 return Math.floor(v);
40172 beforeBlur : function(){
40173 var v = this.parseValue(this.getRawValue());
40180 * Ext JS Library 1.1.1
40181 * Copyright(c) 2006-2007, Ext JS, LLC.
40183 * Originally Released Under LGPL - original licence link has changed is not relivant.
40186 * <script type="text/javascript">
40190 * @class Roo.form.DateField
40191 * @extends Roo.form.TriggerField
40192 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40194 * Create a new DateField
40195 * @param {Object} config
40197 Roo.form.DateField = function(config){
40198 Roo.form.DateField.superclass.constructor.call(this, config);
40204 * Fires when a date is selected
40205 * @param {Roo.form.DateField} combo This combo box
40206 * @param {Date} date The date selected
40213 if(typeof this.minValue == "string") {
40214 this.minValue = this.parseDate(this.minValue);
40216 if(typeof this.maxValue == "string") {
40217 this.maxValue = this.parseDate(this.maxValue);
40219 this.ddMatch = null;
40220 if(this.disabledDates){
40221 var dd = this.disabledDates;
40223 for(var i = 0; i < dd.length; i++){
40225 if(i != dd.length-1) {
40229 this.ddMatch = new RegExp(re + ")");
40233 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40235 * @cfg {String} format
40236 * The default date format string which can be overriden for localization support. The format must be
40237 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40241 * @cfg {String} altFormats
40242 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40243 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40245 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40247 * @cfg {Array} disabledDays
40248 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40250 disabledDays : null,
40252 * @cfg {String} disabledDaysText
40253 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40255 disabledDaysText : "Disabled",
40257 * @cfg {Array} disabledDates
40258 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40259 * expression so they are very powerful. Some examples:
40261 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40262 * <li>["03/08", "09/16"] would disable those days for every year</li>
40263 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40264 * <li>["03/../2006"] would disable every day in March 2006</li>
40265 * <li>["^03"] would disable every day in every March</li>
40267 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40268 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40270 disabledDates : null,
40272 * @cfg {String} disabledDatesText
40273 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40275 disabledDatesText : "Disabled",
40277 * @cfg {Date/String} minValue
40278 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40279 * valid format (defaults to null).
40283 * @cfg {Date/String} maxValue
40284 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40285 * valid format (defaults to null).
40289 * @cfg {String} minText
40290 * The error text to display when the date in the cell is before minValue (defaults to
40291 * 'The date in this field must be after {minValue}').
40293 minText : "The date in this field must be equal to or after {0}",
40295 * @cfg {String} maxText
40296 * The error text to display when the date in the cell is after maxValue (defaults to
40297 * 'The date in this field must be before {maxValue}').
40299 maxText : "The date in this field must be equal to or before {0}",
40301 * @cfg {String} invalidText
40302 * The error text to display when the date in the field is invalid (defaults to
40303 * '{value} is not a valid date - it must be in the format {format}').
40305 invalidText : "{0} is not a valid date - it must be in the format {1}",
40307 * @cfg {String} triggerClass
40308 * An additional CSS class used to style the trigger button. The trigger will always get the
40309 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40310 * which displays a calendar icon).
40312 triggerClass : 'x-form-date-trigger',
40316 * @cfg {Boolean} useIso
40317 * if enabled, then the date field will use a hidden field to store the
40318 * real value as iso formated date. default (false)
40322 * @cfg {String/Object} autoCreate
40323 * A DomHelper element spec, or true for a default element spec (defaults to
40324 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40327 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40330 hiddenField: false,
40332 onRender : function(ct, position)
40334 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40336 //this.el.dom.removeAttribute('name');
40337 Roo.log("Changing name?");
40338 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40339 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40341 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40342 // prevent input submission
40343 this.hiddenName = this.name;
40350 validateValue : function(value)
40352 value = this.formatDate(value);
40353 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40354 Roo.log('super failed');
40357 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40360 var svalue = value;
40361 value = this.parseDate(value);
40363 Roo.log('parse date failed' + svalue);
40364 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40367 var time = value.getTime();
40368 if(this.minValue && time < this.minValue.getTime()){
40369 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40372 if(this.maxValue && time > this.maxValue.getTime()){
40373 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40376 if(this.disabledDays){
40377 var day = value.getDay();
40378 for(var i = 0; i < this.disabledDays.length; i++) {
40379 if(day === this.disabledDays[i]){
40380 this.markInvalid(this.disabledDaysText);
40385 var fvalue = this.formatDate(value);
40386 if(this.ddMatch && this.ddMatch.test(fvalue)){
40387 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40394 // Provides logic to override the default TriggerField.validateBlur which just returns true
40395 validateBlur : function(){
40396 return !this.menu || !this.menu.isVisible();
40399 getName: function()
40401 // returns hidden if it's set..
40402 if (!this.rendered) {return ''};
40403 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40408 * Returns the current date value of the date field.
40409 * @return {Date} The date value
40411 getValue : function(){
40413 return this.hiddenField ?
40414 this.hiddenField.value :
40415 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40419 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40420 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40421 * (the default format used is "m/d/y").
40424 //All of these calls set the same date value (May 4, 2006)
40426 //Pass a date object:
40427 var dt = new Date('5/4/06');
40428 dateField.setValue(dt);
40430 //Pass a date string (default format):
40431 dateField.setValue('5/4/06');
40433 //Pass a date string (custom format):
40434 dateField.format = 'Y-m-d';
40435 dateField.setValue('2006-5-4');
40437 * @param {String/Date} date The date or valid date string
40439 setValue : function(date){
40440 if (this.hiddenField) {
40441 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40443 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40444 // make sure the value field is always stored as a date..
40445 this.value = this.parseDate(date);
40451 parseDate : function(value){
40452 if(!value || value instanceof Date){
40455 var v = Date.parseDate(value, this.format);
40456 if (!v && this.useIso) {
40457 v = Date.parseDate(value, 'Y-m-d');
40459 if(!v && this.altFormats){
40460 if(!this.altFormatsArray){
40461 this.altFormatsArray = this.altFormats.split("|");
40463 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40464 v = Date.parseDate(value, this.altFormatsArray[i]);
40471 formatDate : function(date, fmt){
40472 return (!date || !(date instanceof Date)) ?
40473 date : date.dateFormat(fmt || this.format);
40478 select: function(m, d){
40481 this.fireEvent('select', this, d);
40483 show : function(){ // retain focus styling
40487 this.focus.defer(10, this);
40488 var ml = this.menuListeners;
40489 this.menu.un("select", ml.select, this);
40490 this.menu.un("show", ml.show, this);
40491 this.menu.un("hide", ml.hide, this);
40496 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40497 onTriggerClick : function(){
40501 if(this.menu == null){
40502 this.menu = new Roo.menu.DateMenu();
40504 Roo.apply(this.menu.picker, {
40505 showClear: this.allowBlank,
40506 minDate : this.minValue,
40507 maxDate : this.maxValue,
40508 disabledDatesRE : this.ddMatch,
40509 disabledDatesText : this.disabledDatesText,
40510 disabledDays : this.disabledDays,
40511 disabledDaysText : this.disabledDaysText,
40512 format : this.useIso ? 'Y-m-d' : this.format,
40513 minText : String.format(this.minText, this.formatDate(this.minValue)),
40514 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40516 this.menu.on(Roo.apply({}, this.menuListeners, {
40519 this.menu.picker.setValue(this.getValue() || new Date());
40520 this.menu.show(this.el, "tl-bl?");
40523 beforeBlur : function(){
40524 var v = this.parseDate(this.getRawValue());
40534 isDirty : function() {
40535 if(this.disabled) {
40539 if(typeof(this.startValue) === 'undefined'){
40543 return String(this.getValue()) !== String(this.startValue);
40548 * Ext JS Library 1.1.1
40549 * Copyright(c) 2006-2007, Ext JS, LLC.
40551 * Originally Released Under LGPL - original licence link has changed is not relivant.
40554 * <script type="text/javascript">
40558 * @class Roo.form.MonthField
40559 * @extends Roo.form.TriggerField
40560 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40562 * Create a new MonthField
40563 * @param {Object} config
40565 Roo.form.MonthField = function(config){
40567 Roo.form.MonthField.superclass.constructor.call(this, config);
40573 * Fires when a date is selected
40574 * @param {Roo.form.MonthFieeld} combo This combo box
40575 * @param {Date} date The date selected
40582 if(typeof this.minValue == "string") {
40583 this.minValue = this.parseDate(this.minValue);
40585 if(typeof this.maxValue == "string") {
40586 this.maxValue = this.parseDate(this.maxValue);
40588 this.ddMatch = null;
40589 if(this.disabledDates){
40590 var dd = this.disabledDates;
40592 for(var i = 0; i < dd.length; i++){
40594 if(i != dd.length-1) {
40598 this.ddMatch = new RegExp(re + ")");
40602 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40604 * @cfg {String} format
40605 * The default date format string which can be overriden for localization support. The format must be
40606 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40610 * @cfg {String} altFormats
40611 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40612 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40614 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40616 * @cfg {Array} disabledDays
40617 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40619 disabledDays : [0,1,2,3,4,5,6],
40621 * @cfg {String} disabledDaysText
40622 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40624 disabledDaysText : "Disabled",
40626 * @cfg {Array} disabledDates
40627 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40628 * expression so they are very powerful. Some examples:
40630 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40631 * <li>["03/08", "09/16"] would disable those days for every year</li>
40632 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40633 * <li>["03/../2006"] would disable every day in March 2006</li>
40634 * <li>["^03"] would disable every day in every March</li>
40636 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40637 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40639 disabledDates : null,
40641 * @cfg {String} disabledDatesText
40642 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40644 disabledDatesText : "Disabled",
40646 * @cfg {Date/String} minValue
40647 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40648 * valid format (defaults to null).
40652 * @cfg {Date/String} maxValue
40653 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40654 * valid format (defaults to null).
40658 * @cfg {String} minText
40659 * The error text to display when the date in the cell is before minValue (defaults to
40660 * 'The date in this field must be after {minValue}').
40662 minText : "The date in this field must be equal to or after {0}",
40664 * @cfg {String} maxTextf
40665 * The error text to display when the date in the cell is after maxValue (defaults to
40666 * 'The date in this field must be before {maxValue}').
40668 maxText : "The date in this field must be equal to or before {0}",
40670 * @cfg {String} invalidText
40671 * The error text to display when the date in the field is invalid (defaults to
40672 * '{value} is not a valid date - it must be in the format {format}').
40674 invalidText : "{0} is not a valid date - it must be in the format {1}",
40676 * @cfg {String} triggerClass
40677 * An additional CSS class used to style the trigger button. The trigger will always get the
40678 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40679 * which displays a calendar icon).
40681 triggerClass : 'x-form-date-trigger',
40685 * @cfg {Boolean} useIso
40686 * if enabled, then the date field will use a hidden field to store the
40687 * real value as iso formated date. default (true)
40691 * @cfg {String/Object} autoCreate
40692 * A DomHelper element spec, or true for a default element spec (defaults to
40693 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40696 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40699 hiddenField: false,
40701 hideMonthPicker : false,
40703 onRender : function(ct, position)
40705 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40707 this.el.dom.removeAttribute('name');
40708 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40710 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40711 // prevent input submission
40712 this.hiddenName = this.name;
40719 validateValue : function(value)
40721 value = this.formatDate(value);
40722 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40725 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40728 var svalue = value;
40729 value = this.parseDate(value);
40731 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40734 var time = value.getTime();
40735 if(this.minValue && time < this.minValue.getTime()){
40736 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40739 if(this.maxValue && time > this.maxValue.getTime()){
40740 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40743 /*if(this.disabledDays){
40744 var day = value.getDay();
40745 for(var i = 0; i < this.disabledDays.length; i++) {
40746 if(day === this.disabledDays[i]){
40747 this.markInvalid(this.disabledDaysText);
40753 var fvalue = this.formatDate(value);
40754 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40755 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40763 // Provides logic to override the default TriggerField.validateBlur which just returns true
40764 validateBlur : function(){
40765 return !this.menu || !this.menu.isVisible();
40769 * Returns the current date value of the date field.
40770 * @return {Date} The date value
40772 getValue : function(){
40776 return this.hiddenField ?
40777 this.hiddenField.value :
40778 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40782 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40783 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40784 * (the default format used is "m/d/y").
40787 //All of these calls set the same date value (May 4, 2006)
40789 //Pass a date object:
40790 var dt = new Date('5/4/06');
40791 monthField.setValue(dt);
40793 //Pass a date string (default format):
40794 monthField.setValue('5/4/06');
40796 //Pass a date string (custom format):
40797 monthField.format = 'Y-m-d';
40798 monthField.setValue('2006-5-4');
40800 * @param {String/Date} date The date or valid date string
40802 setValue : function(date){
40803 Roo.log('month setValue' + date);
40804 // can only be first of month..
40806 var val = this.parseDate(date);
40808 if (this.hiddenField) {
40809 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40811 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40812 this.value = this.parseDate(date);
40816 parseDate : function(value){
40817 if(!value || value instanceof Date){
40818 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40821 var v = Date.parseDate(value, this.format);
40822 if (!v && this.useIso) {
40823 v = Date.parseDate(value, 'Y-m-d');
40827 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40831 if(!v && this.altFormats){
40832 if(!this.altFormatsArray){
40833 this.altFormatsArray = this.altFormats.split("|");
40835 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40836 v = Date.parseDate(value, this.altFormatsArray[i]);
40843 formatDate : function(date, fmt){
40844 return (!date || !(date instanceof Date)) ?
40845 date : date.dateFormat(fmt || this.format);
40850 select: function(m, d){
40852 this.fireEvent('select', this, d);
40854 show : function(){ // retain focus styling
40858 this.focus.defer(10, this);
40859 var ml = this.menuListeners;
40860 this.menu.un("select", ml.select, this);
40861 this.menu.un("show", ml.show, this);
40862 this.menu.un("hide", ml.hide, this);
40866 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40867 onTriggerClick : function(){
40871 if(this.menu == null){
40872 this.menu = new Roo.menu.DateMenu();
40876 Roo.apply(this.menu.picker, {
40878 showClear: this.allowBlank,
40879 minDate : this.minValue,
40880 maxDate : this.maxValue,
40881 disabledDatesRE : this.ddMatch,
40882 disabledDatesText : this.disabledDatesText,
40884 format : this.useIso ? 'Y-m-d' : this.format,
40885 minText : String.format(this.minText, this.formatDate(this.minValue)),
40886 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40889 this.menu.on(Roo.apply({}, this.menuListeners, {
40897 // hide month picker get's called when we called by 'before hide';
40899 var ignorehide = true;
40900 p.hideMonthPicker = function(disableAnim){
40904 if(this.monthPicker){
40905 Roo.log("hideMonthPicker called");
40906 if(disableAnim === true){
40907 this.monthPicker.hide();
40909 this.monthPicker.slideOut('t', {duration:.2});
40910 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40911 p.fireEvent("select", this, this.value);
40917 Roo.log('picker set value');
40918 Roo.log(this.getValue());
40919 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40920 m.show(this.el, 'tl-bl?');
40921 ignorehide = false;
40922 // this will trigger hideMonthPicker..
40925 // hidden the day picker
40926 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40932 p.showMonthPicker.defer(100, p);
40938 beforeBlur : function(){
40939 var v = this.parseDate(this.getRawValue());
40945 /** @cfg {Boolean} grow @hide */
40946 /** @cfg {Number} growMin @hide */
40947 /** @cfg {Number} growMax @hide */
40954 * Ext JS Library 1.1.1
40955 * Copyright(c) 2006-2007, Ext JS, LLC.
40957 * Originally Released Under LGPL - original licence link has changed is not relivant.
40960 * <script type="text/javascript">
40965 * @class Roo.form.ComboBox
40966 * @extends Roo.form.TriggerField
40967 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40969 * Create a new ComboBox.
40970 * @param {Object} config Configuration options
40972 Roo.form.ComboBox = function(config){
40973 Roo.form.ComboBox.superclass.constructor.call(this, config);
40977 * Fires when the dropdown list is expanded
40978 * @param {Roo.form.ComboBox} combo This combo box
40983 * Fires when the dropdown list is collapsed
40984 * @param {Roo.form.ComboBox} combo This combo box
40988 * @event beforeselect
40989 * Fires before a list item is selected. Return false to cancel the selection.
40990 * @param {Roo.form.ComboBox} combo This combo box
40991 * @param {Roo.data.Record} record The data record returned from the underlying store
40992 * @param {Number} index The index of the selected item in the dropdown list
40994 'beforeselect' : true,
40997 * Fires when a list item is selected
40998 * @param {Roo.form.ComboBox} combo This combo box
40999 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41000 * @param {Number} index The index of the selected item in the dropdown list
41004 * @event beforequery
41005 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41006 * The event object passed has these properties:
41007 * @param {Roo.form.ComboBox} combo This combo box
41008 * @param {String} query The query
41009 * @param {Boolean} forceAll true to force "all" query
41010 * @param {Boolean} cancel true to cancel the query
41011 * @param {Object} e The query event object
41013 'beforequery': true,
41016 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41017 * @param {Roo.form.ComboBox} combo This combo box
41022 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41023 * @param {Roo.form.ComboBox} combo This combo box
41024 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41030 if(this.transform){
41031 this.allowDomMove = false;
41032 var s = Roo.getDom(this.transform);
41033 if(!this.hiddenName){
41034 this.hiddenName = s.name;
41037 this.mode = 'local';
41038 var d = [], opts = s.options;
41039 for(var i = 0, len = opts.length;i < len; i++){
41041 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41043 this.value = value;
41045 d.push([value, o.text]);
41047 this.store = new Roo.data.SimpleStore({
41049 fields: ['value', 'text'],
41052 this.valueField = 'value';
41053 this.displayField = 'text';
41055 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41056 if(!this.lazyRender){
41057 this.target = true;
41058 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41059 s.parentNode.removeChild(s); // remove it
41060 this.render(this.el.parentNode);
41062 s.parentNode.removeChild(s); // remove it
41067 this.store = Roo.factory(this.store, Roo.data);
41070 this.selectedIndex = -1;
41071 if(this.mode == 'local'){
41072 if(config.queryDelay === undefined){
41073 this.queryDelay = 10;
41075 if(config.minChars === undefined){
41081 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41083 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41086 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41087 * rendering into an Roo.Editor, defaults to false)
41090 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41091 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41094 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41097 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41098 * the dropdown list (defaults to undefined, with no header element)
41102 * @cfg {String/Roo.Template} tpl The template to use to render the output
41106 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41108 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41110 listWidth: undefined,
41112 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41113 * mode = 'remote' or 'text' if mode = 'local')
41115 displayField: undefined,
41117 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41118 * mode = 'remote' or 'value' if mode = 'local').
41119 * Note: use of a valueField requires the user make a selection
41120 * in order for a value to be mapped.
41122 valueField: undefined,
41126 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41127 * field's data value (defaults to the underlying DOM element's name)
41129 hiddenName: undefined,
41131 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41135 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41137 selectedClass: 'x-combo-selected',
41139 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41140 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41141 * which displays a downward arrow icon).
41143 triggerClass : 'x-form-arrow-trigger',
41145 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41149 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41150 * anchor positions (defaults to 'tl-bl')
41152 listAlign: 'tl-bl?',
41154 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41158 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41159 * query specified by the allQuery config option (defaults to 'query')
41161 triggerAction: 'query',
41163 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41164 * (defaults to 4, does not apply if editable = false)
41168 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41169 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41173 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41174 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41178 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41179 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41183 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41184 * when editable = true (defaults to false)
41186 selectOnFocus:false,
41188 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41190 queryParam: 'query',
41192 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41193 * when mode = 'remote' (defaults to 'Loading...')
41195 loadingText: 'Loading...',
41197 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41201 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41205 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41206 * traditional select (defaults to true)
41210 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41214 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41218 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41219 * listWidth has a higher value)
41223 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41224 * allow the user to set arbitrary text into the field (defaults to false)
41226 forceSelection:false,
41228 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41229 * if typeAhead = true (defaults to 250)
41231 typeAheadDelay : 250,
41233 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41234 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41236 valueNotFoundText : undefined,
41238 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41240 blockFocus : false,
41243 * @cfg {Boolean} disableClear Disable showing of clear button.
41245 disableClear : false,
41247 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41249 alwaysQuery : false,
41255 // element that contains real text value.. (when hidden is used..)
41258 onRender : function(ct, position){
41259 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41260 if(this.hiddenName){
41261 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41263 this.hiddenField.value =
41264 this.hiddenValue !== undefined ? this.hiddenValue :
41265 this.value !== undefined ? this.value : '';
41267 // prevent input submission
41268 this.el.dom.removeAttribute('name');
41273 this.el.dom.setAttribute('autocomplete', 'off');
41276 var cls = 'x-combo-list';
41278 this.list = new Roo.Layer({
41279 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41282 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41283 this.list.setWidth(lw);
41284 this.list.swallowEvent('mousewheel');
41285 this.assetHeight = 0;
41288 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41289 this.assetHeight += this.header.getHeight();
41292 this.innerList = this.list.createChild({cls:cls+'-inner'});
41293 this.innerList.on('mouseover', this.onViewOver, this);
41294 this.innerList.on('mousemove', this.onViewMove, this);
41295 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41297 if(this.allowBlank && !this.pageSize && !this.disableClear){
41298 this.footer = this.list.createChild({cls:cls+'-ft'});
41299 this.pageTb = new Roo.Toolbar(this.footer);
41303 this.footer = this.list.createChild({cls:cls+'-ft'});
41304 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41305 {pageSize: this.pageSize});
41309 if (this.pageTb && this.allowBlank && !this.disableClear) {
41311 this.pageTb.add(new Roo.Toolbar.Fill(), {
41312 cls: 'x-btn-icon x-btn-clear',
41314 handler: function()
41317 _this.clearValue();
41318 _this.onSelect(false, -1);
41323 this.assetHeight += this.footer.getHeight();
41328 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41331 this.view = new Roo.View(this.innerList, this.tpl, {
41332 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41335 this.view.on('click', this.onViewClick, this);
41337 this.store.on('beforeload', this.onBeforeLoad, this);
41338 this.store.on('load', this.onLoad, this);
41339 this.store.on('loadexception', this.onLoadException, this);
41341 if(this.resizable){
41342 this.resizer = new Roo.Resizable(this.list, {
41343 pinned:true, handles:'se'
41345 this.resizer.on('resize', function(r, w, h){
41346 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41347 this.listWidth = w;
41348 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41349 this.restrictHeight();
41351 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41353 if(!this.editable){
41354 this.editable = true;
41355 this.setEditable(false);
41359 if (typeof(this.events.add.listeners) != 'undefined') {
41361 this.addicon = this.wrap.createChild(
41362 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41364 this.addicon.on('click', function(e) {
41365 this.fireEvent('add', this);
41368 if (typeof(this.events.edit.listeners) != 'undefined') {
41370 this.editicon = this.wrap.createChild(
41371 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41372 if (this.addicon) {
41373 this.editicon.setStyle('margin-left', '40px');
41375 this.editicon.on('click', function(e) {
41377 // we fire even if inothing is selected..
41378 this.fireEvent('edit', this, this.lastData );
41388 initEvents : function(){
41389 Roo.form.ComboBox.superclass.initEvents.call(this);
41391 this.keyNav = new Roo.KeyNav(this.el, {
41392 "up" : function(e){
41393 this.inKeyMode = true;
41397 "down" : function(e){
41398 if(!this.isExpanded()){
41399 this.onTriggerClick();
41401 this.inKeyMode = true;
41406 "enter" : function(e){
41407 this.onViewClick();
41411 "esc" : function(e){
41415 "tab" : function(e){
41416 this.onViewClick(false);
41417 this.fireEvent("specialkey", this, e);
41423 doRelay : function(foo, bar, hname){
41424 if(hname == 'down' || this.scope.isExpanded()){
41425 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41432 this.queryDelay = Math.max(this.queryDelay || 10,
41433 this.mode == 'local' ? 10 : 250);
41434 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41435 if(this.typeAhead){
41436 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41438 if(this.editable !== false){
41439 this.el.on("keyup", this.onKeyUp, this);
41441 if(this.forceSelection){
41442 this.on('blur', this.doForce, this);
41446 onDestroy : function(){
41448 this.view.setStore(null);
41449 this.view.el.removeAllListeners();
41450 this.view.el.remove();
41451 this.view.purgeListeners();
41454 this.list.destroy();
41457 this.store.un('beforeload', this.onBeforeLoad, this);
41458 this.store.un('load', this.onLoad, this);
41459 this.store.un('loadexception', this.onLoadException, this);
41461 Roo.form.ComboBox.superclass.onDestroy.call(this);
41465 fireKey : function(e){
41466 if(e.isNavKeyPress() && !this.list.isVisible()){
41467 this.fireEvent("specialkey", this, e);
41472 onResize: function(w, h){
41473 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41475 if(typeof w != 'number'){
41476 // we do not handle it!?!?
41479 var tw = this.trigger.getWidth();
41480 tw += this.addicon ? this.addicon.getWidth() : 0;
41481 tw += this.editicon ? this.editicon.getWidth() : 0;
41483 this.el.setWidth( this.adjustWidth('input', x));
41485 this.trigger.setStyle('left', x+'px');
41487 if(this.list && this.listWidth === undefined){
41488 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41489 this.list.setWidth(lw);
41490 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41498 * Allow or prevent the user from directly editing the field text. If false is passed,
41499 * the user will only be able to select from the items defined in the dropdown list. This method
41500 * is the runtime equivalent of setting the 'editable' config option at config time.
41501 * @param {Boolean} value True to allow the user to directly edit the field text
41503 setEditable : function(value){
41504 if(value == this.editable){
41507 this.editable = value;
41509 this.el.dom.setAttribute('readOnly', true);
41510 this.el.on('mousedown', this.onTriggerClick, this);
41511 this.el.addClass('x-combo-noedit');
41513 this.el.dom.setAttribute('readOnly', false);
41514 this.el.un('mousedown', this.onTriggerClick, this);
41515 this.el.removeClass('x-combo-noedit');
41520 onBeforeLoad : function(){
41521 if(!this.hasFocus){
41524 this.innerList.update(this.loadingText ?
41525 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41526 this.restrictHeight();
41527 this.selectedIndex = -1;
41531 onLoad : function(){
41532 if(!this.hasFocus){
41535 if(this.store.getCount() > 0){
41537 this.restrictHeight();
41538 if(this.lastQuery == this.allQuery){
41540 this.el.dom.select();
41542 if(!this.selectByValue(this.value, true)){
41543 this.select(0, true);
41547 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41548 this.taTask.delay(this.typeAheadDelay);
41552 this.onEmptyResults();
41557 onLoadException : function()
41560 Roo.log(this.store.reader.jsonData);
41561 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41562 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41568 onTypeAhead : function(){
41569 if(this.store.getCount() > 0){
41570 var r = this.store.getAt(0);
41571 var newValue = r.data[this.displayField];
41572 var len = newValue.length;
41573 var selStart = this.getRawValue().length;
41574 if(selStart != len){
41575 this.setRawValue(newValue);
41576 this.selectText(selStart, newValue.length);
41582 onSelect : function(record, index){
41583 if(this.fireEvent('beforeselect', this, record, index) !== false){
41584 this.setFromData(index > -1 ? record.data : false);
41586 this.fireEvent('select', this, record, index);
41591 * Returns the currently selected field value or empty string if no value is set.
41592 * @return {String} value The selected value
41594 getValue : function(){
41595 if(this.valueField){
41596 return typeof this.value != 'undefined' ? this.value : '';
41598 return Roo.form.ComboBox.superclass.getValue.call(this);
41602 * Clears any text/value currently set in the field
41604 clearValue : function(){
41605 if(this.hiddenField){
41606 this.hiddenField.value = '';
41609 this.setRawValue('');
41610 this.lastSelectionText = '';
41615 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41616 * will be displayed in the field. If the value does not match the data value of an existing item,
41617 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41618 * Otherwise the field will be blank (although the value will still be set).
41619 * @param {String} value The value to match
41621 setValue : function(v){
41623 if(this.valueField){
41624 var r = this.findRecord(this.valueField, v);
41626 text = r.data[this.displayField];
41627 }else if(this.valueNotFoundText !== undefined){
41628 text = this.valueNotFoundText;
41631 this.lastSelectionText = text;
41632 if(this.hiddenField){
41633 this.hiddenField.value = v;
41635 Roo.form.ComboBox.superclass.setValue.call(this, text);
41639 * @property {Object} the last set data for the element
41644 * Sets the value of the field based on a object which is related to the record format for the store.
41645 * @param {Object} value the value to set as. or false on reset?
41647 setFromData : function(o){
41648 var dv = ''; // display value
41649 var vv = ''; // value value..
41651 if (this.displayField) {
41652 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41654 // this is an error condition!!!
41655 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41658 if(this.valueField){
41659 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41661 if(this.hiddenField){
41662 this.hiddenField.value = vv;
41664 this.lastSelectionText = dv;
41665 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41669 // no hidden field.. - we store the value in 'value', but still display
41670 // display field!!!!
41671 this.lastSelectionText = dv;
41672 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41678 reset : function(){
41679 // overridden so that last data is reset..
41680 this.setValue(this.resetValue);
41681 this.originalValue = this.getValue();
41682 this.clearInvalid();
41683 this.lastData = false;
41685 this.view.clearSelections();
41689 findRecord : function(prop, value){
41691 if(this.store.getCount() > 0){
41692 this.store.each(function(r){
41693 if(r.data[prop] == value){
41703 getName: function()
41705 // returns hidden if it's set..
41706 if (!this.rendered) {return ''};
41707 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41711 onViewMove : function(e, t){
41712 this.inKeyMode = false;
41716 onViewOver : function(e, t){
41717 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41720 var item = this.view.findItemFromChild(t);
41722 var index = this.view.indexOf(item);
41723 this.select(index, false);
41728 onViewClick : function(doFocus)
41730 var index = this.view.getSelectedIndexes()[0];
41731 var r = this.store.getAt(index);
41733 this.onSelect(r, index);
41735 if(doFocus !== false && !this.blockFocus){
41741 restrictHeight : function(){
41742 this.innerList.dom.style.height = '';
41743 var inner = this.innerList.dom;
41744 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41745 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41746 this.list.beginUpdate();
41747 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41748 this.list.alignTo(this.el, this.listAlign);
41749 this.list.endUpdate();
41753 onEmptyResults : function(){
41758 * Returns true if the dropdown list is expanded, else false.
41760 isExpanded : function(){
41761 return this.list.isVisible();
41765 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41766 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41767 * @param {String} value The data value of the item to select
41768 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41769 * selected item if it is not currently in view (defaults to true)
41770 * @return {Boolean} True if the value matched an item in the list, else false
41772 selectByValue : function(v, scrollIntoView){
41773 if(v !== undefined && v !== null){
41774 var r = this.findRecord(this.valueField || this.displayField, v);
41776 this.select(this.store.indexOf(r), scrollIntoView);
41784 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41785 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41786 * @param {Number} index The zero-based index of the list item to select
41787 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41788 * selected item if it is not currently in view (defaults to true)
41790 select : function(index, scrollIntoView){
41791 this.selectedIndex = index;
41792 this.view.select(index);
41793 if(scrollIntoView !== false){
41794 var el = this.view.getNode(index);
41796 this.innerList.scrollChildIntoView(el, false);
41802 selectNext : function(){
41803 var ct = this.store.getCount();
41805 if(this.selectedIndex == -1){
41807 }else if(this.selectedIndex < ct-1){
41808 this.select(this.selectedIndex+1);
41814 selectPrev : function(){
41815 var ct = this.store.getCount();
41817 if(this.selectedIndex == -1){
41819 }else if(this.selectedIndex != 0){
41820 this.select(this.selectedIndex-1);
41826 onKeyUp : function(e){
41827 if(this.editable !== false && !e.isSpecialKey()){
41828 this.lastKey = e.getKey();
41829 this.dqTask.delay(this.queryDelay);
41834 validateBlur : function(){
41835 return !this.list || !this.list.isVisible();
41839 initQuery : function(){
41840 this.doQuery(this.getRawValue());
41844 doForce : function(){
41845 if(this.el.dom.value.length > 0){
41846 this.el.dom.value =
41847 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41853 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41854 * query allowing the query action to be canceled if needed.
41855 * @param {String} query The SQL query to execute
41856 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41857 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41858 * saved in the current store (defaults to false)
41860 doQuery : function(q, forceAll){
41861 if(q === undefined || q === null){
41866 forceAll: forceAll,
41870 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41874 forceAll = qe.forceAll;
41875 if(forceAll === true || (q.length >= this.minChars)){
41876 if(this.lastQuery != q || this.alwaysQuery){
41877 this.lastQuery = q;
41878 if(this.mode == 'local'){
41879 this.selectedIndex = -1;
41881 this.store.clearFilter();
41883 this.store.filter(this.displayField, q);
41887 this.store.baseParams[this.queryParam] = q;
41889 params: this.getParams(q)
41894 this.selectedIndex = -1;
41901 getParams : function(q){
41903 //p[this.queryParam] = q;
41906 p.limit = this.pageSize;
41912 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41914 collapse : function(){
41915 if(!this.isExpanded()){
41919 Roo.get(document).un('mousedown', this.collapseIf, this);
41920 Roo.get(document).un('mousewheel', this.collapseIf, this);
41921 if (!this.editable) {
41922 Roo.get(document).un('keydown', this.listKeyPress, this);
41924 this.fireEvent('collapse', this);
41928 collapseIf : function(e){
41929 if(!e.within(this.wrap) && !e.within(this.list)){
41935 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41937 expand : function(){
41938 if(this.isExpanded() || !this.hasFocus){
41941 this.list.alignTo(this.el, this.listAlign);
41943 Roo.get(document).on('mousedown', this.collapseIf, this);
41944 Roo.get(document).on('mousewheel', this.collapseIf, this);
41945 if (!this.editable) {
41946 Roo.get(document).on('keydown', this.listKeyPress, this);
41949 this.fireEvent('expand', this);
41953 // Implements the default empty TriggerField.onTriggerClick function
41954 onTriggerClick : function(){
41958 if(this.isExpanded()){
41960 if (!this.blockFocus) {
41965 this.hasFocus = true;
41966 if(this.triggerAction == 'all') {
41967 this.doQuery(this.allQuery, true);
41969 this.doQuery(this.getRawValue());
41971 if (!this.blockFocus) {
41976 listKeyPress : function(e)
41978 //Roo.log('listkeypress');
41979 // scroll to first matching element based on key pres..
41980 if (e.isSpecialKey()) {
41983 var k = String.fromCharCode(e.getKey()).toUpperCase();
41986 var csel = this.view.getSelectedNodes();
41987 var cselitem = false;
41989 var ix = this.view.indexOf(csel[0]);
41990 cselitem = this.store.getAt(ix);
41991 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41997 this.store.each(function(v) {
41999 // start at existing selection.
42000 if (cselitem.id == v.id) {
42006 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42007 match = this.store.indexOf(v);
42012 if (match === false) {
42013 return true; // no more action?
42016 this.view.select(match);
42017 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42018 sn.scrollIntoView(sn.dom.parentNode, false);
42022 * @cfg {Boolean} grow
42026 * @cfg {Number} growMin
42030 * @cfg {Number} growMax
42038 * Copyright(c) 2010-2012, Roo J Solutions Limited
42045 * @class Roo.form.ComboBoxArray
42046 * @extends Roo.form.TextField
42047 * A facebook style adder... for lists of email / people / countries etc...
42048 * pick multiple items from a combo box, and shows each one.
42050 * Fred [x] Brian [x] [Pick another |v]
42053 * For this to work: it needs various extra information
42054 * - normal combo problay has
42056 * + displayField, valueField
42058 * For our purpose...
42061 * If we change from 'extends' to wrapping...
42068 * Create a new ComboBoxArray.
42069 * @param {Object} config Configuration options
42073 Roo.form.ComboBoxArray = function(config)
42077 * @event beforeremove
42078 * Fires before remove the value from the list
42079 * @param {Roo.form.ComboBoxArray} _self This combo box array
42080 * @param {Roo.form.ComboBoxArray.Item} item removed item
42082 'beforeremove' : true,
42085 * Fires when remove the value from the list
42086 * @param {Roo.form.ComboBoxArray} _self This combo box array
42087 * @param {Roo.form.ComboBoxArray.Item} item removed item
42094 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42096 this.items = new Roo.util.MixedCollection(false);
42098 // construct the child combo...
42108 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42111 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42116 // behavies liek a hiddne field
42117 inputType: 'hidden',
42119 * @cfg {Number} width The width of the box that displays the selected element
42126 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42130 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42132 hiddenName : false,
42135 // private the array of items that are displayed..
42137 // private - the hidden field el.
42139 // private - the filed el..
42142 //validateValue : function() { return true; }, // all values are ok!
42143 //onAddClick: function() { },
42145 onRender : function(ct, position)
42148 // create the standard hidden element
42149 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42152 // give fake names to child combo;
42153 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42154 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42156 this.combo = Roo.factory(this.combo, Roo.form);
42157 this.combo.onRender(ct, position);
42158 if (typeof(this.combo.width) != 'undefined') {
42159 this.combo.onResize(this.combo.width,0);
42162 this.combo.initEvents();
42164 // assigned so form know we need to do this..
42165 this.store = this.combo.store;
42166 this.valueField = this.combo.valueField;
42167 this.displayField = this.combo.displayField ;
42170 this.combo.wrap.addClass('x-cbarray-grp');
42172 var cbwrap = this.combo.wrap.createChild(
42173 {tag: 'div', cls: 'x-cbarray-cb'},
42178 this.hiddenEl = this.combo.wrap.createChild({
42179 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42181 this.el = this.combo.wrap.createChild({
42182 tag: 'input', type:'hidden' , name: this.name, value : ''
42184 // this.el.dom.removeAttribute("name");
42187 this.outerWrap = this.combo.wrap;
42188 this.wrap = cbwrap;
42190 this.outerWrap.setWidth(this.width);
42191 this.outerWrap.dom.removeChild(this.el.dom);
42193 this.wrap.dom.appendChild(this.el.dom);
42194 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42195 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42197 this.combo.trigger.setStyle('position','relative');
42198 this.combo.trigger.setStyle('left', '0px');
42199 this.combo.trigger.setStyle('top', '2px');
42201 this.combo.el.setStyle('vertical-align', 'text-bottom');
42203 //this.trigger.setStyle('vertical-align', 'top');
42205 // this should use the code from combo really... on('add' ....)
42209 this.adder = this.outerWrap.createChild(
42210 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42212 this.adder.on('click', function(e) {
42213 _t.fireEvent('adderclick', this, e);
42217 //this.adder.on('click', this.onAddClick, _t);
42220 this.combo.on('select', function(cb, rec, ix) {
42221 this.addItem(rec.data);
42224 cb.el.dom.value = '';
42225 //cb.lastData = rec.data;
42234 getName: function()
42236 // returns hidden if it's set..
42237 if (!this.rendered) {return ''};
42238 return this.hiddenName ? this.hiddenName : this.name;
42243 onResize: function(w, h){
42246 // not sure if this is needed..
42247 //this.combo.onResize(w,h);
42249 if(typeof w != 'number'){
42250 // we do not handle it!?!?
42253 var tw = this.combo.trigger.getWidth();
42254 tw += this.addicon ? this.addicon.getWidth() : 0;
42255 tw += this.editicon ? this.editicon.getWidth() : 0;
42257 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42259 this.combo.trigger.setStyle('left', '0px');
42261 if(this.list && this.listWidth === undefined){
42262 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42263 this.list.setWidth(lw);
42264 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42271 addItem: function(rec)
42273 var valueField = this.combo.valueField;
42274 var displayField = this.combo.displayField;
42275 if (this.items.indexOfKey(rec[valueField]) > -1) {
42276 //console.log("GOT " + rec.data.id);
42280 var x = new Roo.form.ComboBoxArray.Item({
42281 //id : rec[this.idField],
42283 displayField : displayField ,
42284 tipField : displayField ,
42288 this.items.add(rec[valueField],x);
42289 // add it before the element..
42290 this.updateHiddenEl();
42291 x.render(this.outerWrap, this.wrap.dom);
42292 // add the image handler..
42295 updateHiddenEl : function()
42298 if (!this.hiddenEl) {
42302 var idField = this.combo.valueField;
42304 this.items.each(function(f) {
42305 ar.push(f.data[idField]);
42308 this.hiddenEl.dom.value = ar.join(',');
42314 this.items.clear();
42316 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42320 this.el.dom.value = '';
42321 if (this.hiddenEl) {
42322 this.hiddenEl.dom.value = '';
42326 getValue: function()
42328 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42330 setValue: function(v) // not a valid action - must use addItems..
42337 if (this.store.isLocal && (typeof(v) == 'string')) {
42338 // then we can use the store to find the values..
42339 // comma seperated at present.. this needs to allow JSON based encoding..
42340 this.hiddenEl.value = v;
42342 Roo.each(v.split(','), function(k) {
42343 Roo.log("CHECK " + this.valueField + ',' + k);
42344 var li = this.store.query(this.valueField, k);
42349 add[this.valueField] = k;
42350 add[this.displayField] = li.item(0).data[this.displayField];
42356 if (typeof(v) == 'object' ) {
42357 // then let's assume it's an array of objects..
42358 Roo.each(v, function(l) {
42366 setFromData: function(v)
42368 // this recieves an object, if setValues is called.
42370 this.el.dom.value = v[this.displayField];
42371 this.hiddenEl.dom.value = v[this.valueField];
42372 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42375 var kv = v[this.valueField];
42376 var dv = v[this.displayField];
42377 kv = typeof(kv) != 'string' ? '' : kv;
42378 dv = typeof(dv) != 'string' ? '' : dv;
42381 var keys = kv.split(',');
42382 var display = dv.split(',');
42383 for (var i = 0 ; i < keys.length; i++) {
42386 add[this.valueField] = keys[i];
42387 add[this.displayField] = display[i];
42395 * Validates the combox array value
42396 * @return {Boolean} True if the value is valid, else false
42398 validate : function(){
42399 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42400 this.clearInvalid();
42406 validateValue : function(value){
42407 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42415 isDirty : function() {
42416 if(this.disabled) {
42421 var d = Roo.decode(String(this.originalValue));
42423 return String(this.getValue()) !== String(this.originalValue);
42426 var originalValue = [];
42428 for (var i = 0; i < d.length; i++){
42429 originalValue.push(d[i][this.valueField]);
42432 return String(this.getValue()) !== String(originalValue.join(','));
42441 * @class Roo.form.ComboBoxArray.Item
42442 * @extends Roo.BoxComponent
42443 * A selected item in the list
42444 * Fred [x] Brian [x] [Pick another |v]
42447 * Create a new item.
42448 * @param {Object} config Configuration options
42451 Roo.form.ComboBoxArray.Item = function(config) {
42452 config.id = Roo.id();
42453 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42456 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42459 displayField : false,
42463 defaultAutoCreate : {
42465 cls: 'x-cbarray-item',
42472 src : Roo.BLANK_IMAGE_URL ,
42480 onRender : function(ct, position)
42482 Roo.form.Field.superclass.onRender.call(this, ct, position);
42485 var cfg = this.getAutoCreate();
42486 this.el = ct.createChild(cfg, position);
42489 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42491 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42492 this.cb.renderer(this.data) :
42493 String.format('{0}',this.data[this.displayField]);
42496 this.el.child('div').dom.setAttribute('qtip',
42497 String.format('{0}',this.data[this.tipField])
42500 this.el.child('img').on('click', this.remove, this);
42504 remove : function()
42506 if(this.cb.disabled){
42510 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42511 this.cb.items.remove(this);
42512 this.el.child('img').un('click', this.remove, this);
42514 this.cb.updateHiddenEl();
42516 this.cb.fireEvent('remove', this.cb, this);
42522 * Ext JS Library 1.1.1
42523 * Copyright(c) 2006-2007, Ext JS, LLC.
42525 * Originally Released Under LGPL - original licence link has changed is not relivant.
42528 * <script type="text/javascript">
42531 * @class Roo.form.Checkbox
42532 * @extends Roo.form.Field
42533 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42535 * Creates a new Checkbox
42536 * @param {Object} config Configuration options
42538 Roo.form.Checkbox = function(config){
42539 Roo.form.Checkbox.superclass.constructor.call(this, config);
42543 * Fires when the checkbox is checked or unchecked.
42544 * @param {Roo.form.Checkbox} this This checkbox
42545 * @param {Boolean} checked The new checked value
42551 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42553 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42555 focusClass : undefined,
42557 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42559 fieldClass: "x-form-field",
42561 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42565 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42566 * {tag: "input", type: "checkbox", autocomplete: "off"})
42568 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42570 * @cfg {String} boxLabel The text that appears beside the checkbox
42574 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42578 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42580 valueOff: '0', // value when not checked..
42582 actionMode : 'viewEl',
42585 itemCls : 'x-menu-check-item x-form-item',
42586 groupClass : 'x-menu-group-item',
42587 inputType : 'hidden',
42590 inSetChecked: false, // check that we are not calling self...
42592 inputElement: false, // real input element?
42593 basedOn: false, // ????
42595 isFormField: true, // not sure where this is needed!!!!
42597 onResize : function(){
42598 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42599 if(!this.boxLabel){
42600 this.el.alignTo(this.wrap, 'c-c');
42604 initEvents : function(){
42605 Roo.form.Checkbox.superclass.initEvents.call(this);
42606 this.el.on("click", this.onClick, this);
42607 this.el.on("change", this.onClick, this);
42611 getResizeEl : function(){
42615 getPositionEl : function(){
42620 onRender : function(ct, position){
42621 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42623 if(this.inputValue !== undefined){
42624 this.el.dom.value = this.inputValue;
42627 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42628 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42629 var viewEl = this.wrap.createChild({
42630 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42631 this.viewEl = viewEl;
42632 this.wrap.on('click', this.onClick, this);
42634 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42635 this.el.on('propertychange', this.setFromHidden, this); //ie
42640 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42641 // viewEl.on('click', this.onClick, this);
42643 //if(this.checked){
42644 this.setChecked(this.checked);
42646 //this.checked = this.el.dom;
42652 initValue : Roo.emptyFn,
42655 * Returns the checked state of the checkbox.
42656 * @return {Boolean} True if checked, else false
42658 getValue : function(){
42660 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42662 return this.valueOff;
42667 onClick : function(){
42668 if (this.disabled) {
42671 this.setChecked(!this.checked);
42673 //if(this.el.dom.checked != this.checked){
42674 // this.setValue(this.el.dom.checked);
42679 * Sets the checked state of the checkbox.
42680 * On is always based on a string comparison between inputValue and the param.
42681 * @param {Boolean/String} value - the value to set
42682 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42684 setValue : function(v,suppressEvent){
42687 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42688 //if(this.el && this.el.dom){
42689 // this.el.dom.checked = this.checked;
42690 // this.el.dom.defaultChecked = this.checked;
42692 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42693 //this.fireEvent("check", this, this.checked);
42696 setChecked : function(state,suppressEvent)
42698 if (this.inSetChecked) {
42699 this.checked = state;
42705 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42707 this.checked = state;
42708 if(suppressEvent !== true){
42709 this.fireEvent('check', this, state);
42711 this.inSetChecked = true;
42712 this.el.dom.value = state ? this.inputValue : this.valueOff;
42713 this.inSetChecked = false;
42716 // handle setting of hidden value by some other method!!?!?
42717 setFromHidden: function()
42722 //console.log("SET FROM HIDDEN");
42723 //alert('setFrom hidden');
42724 this.setValue(this.el.dom.value);
42727 onDestroy : function()
42730 Roo.get(this.viewEl).remove();
42733 Roo.form.Checkbox.superclass.onDestroy.call(this);
42736 setBoxLabel : function(str)
42738 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42743 * Ext JS Library 1.1.1
42744 * Copyright(c) 2006-2007, Ext JS, LLC.
42746 * Originally Released Under LGPL - original licence link has changed is not relivant.
42749 * <script type="text/javascript">
42753 * @class Roo.form.Radio
42754 * @extends Roo.form.Checkbox
42755 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42756 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42758 * Creates a new Radio
42759 * @param {Object} config Configuration options
42761 Roo.form.Radio = function(){
42762 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42764 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42765 inputType: 'radio',
42768 * If this radio is part of a group, it will return the selected value
42771 getGroupValue : function(){
42772 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42776 onRender : function(ct, position){
42777 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42779 if(this.inputValue !== undefined){
42780 this.el.dom.value = this.inputValue;
42783 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42784 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42785 //var viewEl = this.wrap.createChild({
42786 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42787 //this.viewEl = viewEl;
42788 //this.wrap.on('click', this.onClick, this);
42790 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42791 //this.el.on('propertychange', this.setFromHidden, this); //ie
42796 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42797 // viewEl.on('click', this.onClick, this);
42800 this.el.dom.checked = 'checked' ;
42806 });//<script type="text/javascript">
42809 * Based Ext JS Library 1.1.1
42810 * Copyright(c) 2006-2007, Ext JS, LLC.
42816 * @class Roo.HtmlEditorCore
42817 * @extends Roo.Component
42818 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42820 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42823 Roo.HtmlEditorCore = function(config){
42826 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42831 * @event initialize
42832 * Fires when the editor is fully initialized (including the iframe)
42833 * @param {Roo.HtmlEditorCore} this
42838 * Fires when the editor is first receives the focus. Any insertion must wait
42839 * until after this event.
42840 * @param {Roo.HtmlEditorCore} this
42844 * @event beforesync
42845 * Fires before the textarea is updated with content from the editor iframe. Return false
42846 * to cancel the sync.
42847 * @param {Roo.HtmlEditorCore} this
42848 * @param {String} html
42852 * @event beforepush
42853 * Fires before the iframe editor is updated with content from the textarea. Return false
42854 * to cancel the push.
42855 * @param {Roo.HtmlEditorCore} this
42856 * @param {String} html
42861 * Fires when the textarea is updated with content from the editor iframe.
42862 * @param {Roo.HtmlEditorCore} this
42863 * @param {String} html
42868 * Fires when the iframe editor is updated with content from the textarea.
42869 * @param {Roo.HtmlEditorCore} this
42870 * @param {String} html
42875 * @event editorevent
42876 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42877 * @param {Roo.HtmlEditorCore} this
42883 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42885 // defaults : white / black...
42886 this.applyBlacklists();
42893 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42897 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42903 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42908 * @cfg {Number} height (in pixels)
42912 * @cfg {Number} width (in pixels)
42917 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42920 stylesheets: false,
42925 // private properties
42926 validationEvent : false,
42928 initialized : false,
42930 sourceEditMode : false,
42931 onFocus : Roo.emptyFn,
42933 hideMode:'offsets',
42937 // blacklist + whitelisted elements..
42944 * Protected method that will not generally be called directly. It
42945 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42946 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42948 getDocMarkup : function(){
42952 // inherit styels from page...??
42953 if (this.stylesheets === false) {
42955 Roo.get(document.head).select('style').each(function(node) {
42956 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42959 Roo.get(document.head).select('link').each(function(node) {
42960 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42963 } else if (!this.stylesheets.length) {
42965 st = '<style type="text/css">' +
42966 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42969 st = '<style type="text/css">' +
42974 st += '<style type="text/css">' +
42975 'IMG { cursor: pointer } ' +
42978 var cls = 'roo-htmleditor-body';
42980 if(this.bodyCls.length){
42981 cls += ' ' + this.bodyCls;
42984 return '<html><head>' + st +
42985 //<style type="text/css">' +
42986 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42988 ' </head><body class="' + cls + '"></body></html>';
42992 onRender : function(ct, position)
42995 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42996 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42999 this.el.dom.style.border = '0 none';
43000 this.el.dom.setAttribute('tabIndex', -1);
43001 this.el.addClass('x-hidden hide');
43005 if(Roo.isIE){ // fix IE 1px bogus margin
43006 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43010 this.frameId = Roo.id();
43014 var iframe = this.owner.wrap.createChild({
43016 cls: 'form-control', // bootstrap..
43018 name: this.frameId,
43019 frameBorder : 'no',
43020 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43025 this.iframe = iframe.dom;
43027 this.assignDocWin();
43029 this.doc.designMode = 'on';
43032 this.doc.write(this.getDocMarkup());
43036 var task = { // must defer to wait for browser to be ready
43038 //console.log("run task?" + this.doc.readyState);
43039 this.assignDocWin();
43040 if(this.doc.body || this.doc.readyState == 'complete'){
43042 this.doc.designMode="on";
43046 Roo.TaskMgr.stop(task);
43047 this.initEditor.defer(10, this);
43054 Roo.TaskMgr.start(task);
43059 onResize : function(w, h)
43061 Roo.log('resize: ' +w + ',' + h );
43062 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43066 if(typeof w == 'number'){
43068 this.iframe.style.width = w + 'px';
43070 if(typeof h == 'number'){
43072 this.iframe.style.height = h + 'px';
43074 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43081 * Toggles the editor between standard and source edit mode.
43082 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43084 toggleSourceEdit : function(sourceEditMode){
43086 this.sourceEditMode = sourceEditMode === true;
43088 if(this.sourceEditMode){
43090 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43093 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43094 //this.iframe.className = '';
43097 //this.setSize(this.owner.wrap.getSize());
43098 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43105 * Protected method that will not generally be called directly. If you need/want
43106 * custom HTML cleanup, this is the method you should override.
43107 * @param {String} html The HTML to be cleaned
43108 * return {String} The cleaned HTML
43110 cleanHtml : function(html){
43111 html = String(html);
43112 if(html.length > 5){
43113 if(Roo.isSafari){ // strip safari nonsense
43114 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43117 if(html == ' '){
43124 * HTML Editor -> Textarea
43125 * Protected method that will not generally be called directly. Syncs the contents
43126 * of the editor iframe with the textarea.
43128 syncValue : function(){
43129 if(this.initialized){
43130 var bd = (this.doc.body || this.doc.documentElement);
43131 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43132 var html = bd.innerHTML;
43134 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43135 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43137 html = '<div style="'+m[0]+'">' + html + '</div>';
43140 html = this.cleanHtml(html);
43141 // fix up the special chars.. normaly like back quotes in word...
43142 // however we do not want to do this with chinese..
43143 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43144 var cc = b.charCodeAt();
43146 (cc >= 0x4E00 && cc < 0xA000 ) ||
43147 (cc >= 0x3400 && cc < 0x4E00 ) ||
43148 (cc >= 0xf900 && cc < 0xfb00 )
43154 if(this.owner.fireEvent('beforesync', this, html) !== false){
43155 this.el.dom.value = html;
43156 this.owner.fireEvent('sync', this, html);
43162 * Protected method that will not generally be called directly. Pushes the value of the textarea
43163 * into the iframe editor.
43165 pushValue : function(){
43166 if(this.initialized){
43167 var v = this.el.dom.value.trim();
43169 // if(v.length < 1){
43173 if(this.owner.fireEvent('beforepush', this, v) !== false){
43174 var d = (this.doc.body || this.doc.documentElement);
43176 this.cleanUpPaste();
43177 this.el.dom.value = d.innerHTML;
43178 this.owner.fireEvent('push', this, v);
43184 deferFocus : function(){
43185 this.focus.defer(10, this);
43189 focus : function(){
43190 if(this.win && !this.sourceEditMode){
43197 assignDocWin: function()
43199 var iframe = this.iframe;
43202 this.doc = iframe.contentWindow.document;
43203 this.win = iframe.contentWindow;
43205 // if (!Roo.get(this.frameId)) {
43208 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43209 // this.win = Roo.get(this.frameId).dom.contentWindow;
43211 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43215 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43216 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43221 initEditor : function(){
43222 //console.log("INIT EDITOR");
43223 this.assignDocWin();
43227 this.doc.designMode="on";
43229 this.doc.write(this.getDocMarkup());
43232 var dbody = (this.doc.body || this.doc.documentElement);
43233 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43234 // this copies styles from the containing element into thsi one..
43235 // not sure why we need all of this..
43236 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43238 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43239 //ss['background-attachment'] = 'fixed'; // w3c
43240 dbody.bgProperties = 'fixed'; // ie
43241 //Roo.DomHelper.applyStyles(dbody, ss);
43242 Roo.EventManager.on(this.doc, {
43243 //'mousedown': this.onEditorEvent,
43244 'mouseup': this.onEditorEvent,
43245 'dblclick': this.onEditorEvent,
43246 'click': this.onEditorEvent,
43247 'keyup': this.onEditorEvent,
43252 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43254 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43255 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43257 this.initialized = true;
43259 this.owner.fireEvent('initialize', this);
43264 onDestroy : function(){
43270 //for (var i =0; i < this.toolbars.length;i++) {
43271 // // fixme - ask toolbars for heights?
43272 // this.toolbars[i].onDestroy();
43275 //this.wrap.dom.innerHTML = '';
43276 //this.wrap.remove();
43281 onFirstFocus : function(){
43283 this.assignDocWin();
43286 this.activated = true;
43289 if(Roo.isGecko){ // prevent silly gecko errors
43291 var s = this.win.getSelection();
43292 if(!s.focusNode || s.focusNode.nodeType != 3){
43293 var r = s.getRangeAt(0);
43294 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43299 this.execCmd('useCSS', true);
43300 this.execCmd('styleWithCSS', false);
43303 this.owner.fireEvent('activate', this);
43307 adjustFont: function(btn){
43308 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43309 //if(Roo.isSafari){ // safari
43312 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43313 if(Roo.isSafari){ // safari
43314 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43315 v = (v < 10) ? 10 : v;
43316 v = (v > 48) ? 48 : v;
43317 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43322 v = Math.max(1, v+adjust);
43324 this.execCmd('FontSize', v );
43327 onEditorEvent : function(e)
43329 this.owner.fireEvent('editorevent', this, e);
43330 // this.updateToolbar();
43331 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43334 insertTag : function(tg)
43336 // could be a bit smarter... -> wrap the current selected tRoo..
43337 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43339 range = this.createRange(this.getSelection());
43340 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43341 wrappingNode.appendChild(range.extractContents());
43342 range.insertNode(wrappingNode);
43349 this.execCmd("formatblock", tg);
43353 insertText : function(txt)
43357 var range = this.createRange();
43358 range.deleteContents();
43359 //alert(Sender.getAttribute('label'));
43361 range.insertNode(this.doc.createTextNode(txt));
43367 * Executes a Midas editor command on the editor document and performs necessary focus and
43368 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43369 * @param {String} cmd The Midas command
43370 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43372 relayCmd : function(cmd, value){
43374 this.execCmd(cmd, value);
43375 this.owner.fireEvent('editorevent', this);
43376 //this.updateToolbar();
43377 this.owner.deferFocus();
43381 * Executes a Midas editor command directly on the editor document.
43382 * For visual commands, you should use {@link #relayCmd} instead.
43383 * <b>This should only be called after the editor is initialized.</b>
43384 * @param {String} cmd The Midas command
43385 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43387 execCmd : function(cmd, value){
43388 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43395 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43397 * @param {String} text | dom node..
43399 insertAtCursor : function(text)
43402 if(!this.activated){
43408 var r = this.doc.selection.createRange();
43419 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43423 // from jquery ui (MIT licenced)
43425 var win = this.win;
43427 if (win.getSelection && win.getSelection().getRangeAt) {
43428 range = win.getSelection().getRangeAt(0);
43429 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43430 range.insertNode(node);
43431 } else if (win.document.selection && win.document.selection.createRange) {
43432 // no firefox support
43433 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43434 win.document.selection.createRange().pasteHTML(txt);
43436 // no firefox support
43437 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43438 this.execCmd('InsertHTML', txt);
43447 mozKeyPress : function(e){
43449 var c = e.getCharCode(), cmd;
43452 c = String.fromCharCode(c).toLowerCase();
43466 this.cleanUpPaste.defer(100, this);
43474 e.preventDefault();
43482 fixKeys : function(){ // load time branching for fastest keydown performance
43484 return function(e){
43485 var k = e.getKey(), r;
43488 r = this.doc.selection.createRange();
43491 r.pasteHTML('    ');
43498 r = this.doc.selection.createRange();
43500 var target = r.parentElement();
43501 if(!target || target.tagName.toLowerCase() != 'li'){
43503 r.pasteHTML('<br />');
43509 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43510 this.cleanUpPaste.defer(100, this);
43516 }else if(Roo.isOpera){
43517 return function(e){
43518 var k = e.getKey();
43522 this.execCmd('InsertHTML','    ');
43525 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43526 this.cleanUpPaste.defer(100, this);
43531 }else if(Roo.isSafari){
43532 return function(e){
43533 var k = e.getKey();
43537 this.execCmd('InsertText','\t');
43541 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43542 this.cleanUpPaste.defer(100, this);
43550 getAllAncestors: function()
43552 var p = this.getSelectedNode();
43555 a.push(p); // push blank onto stack..
43556 p = this.getParentElement();
43560 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43564 a.push(this.doc.body);
43568 lastSelNode : false,
43571 getSelection : function()
43573 this.assignDocWin();
43574 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43577 getSelectedNode: function()
43579 // this may only work on Gecko!!!
43581 // should we cache this!!!!
43586 var range = this.createRange(this.getSelection()).cloneRange();
43589 var parent = range.parentElement();
43591 var testRange = range.duplicate();
43592 testRange.moveToElementText(parent);
43593 if (testRange.inRange(range)) {
43596 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43599 parent = parent.parentElement;
43604 // is ancestor a text element.
43605 var ac = range.commonAncestorContainer;
43606 if (ac.nodeType == 3) {
43607 ac = ac.parentNode;
43610 var ar = ac.childNodes;
43613 var other_nodes = [];
43614 var has_other_nodes = false;
43615 for (var i=0;i<ar.length;i++) {
43616 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43619 // fullly contained node.
43621 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43626 // probably selected..
43627 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43628 other_nodes.push(ar[i]);
43632 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43637 has_other_nodes = true;
43639 if (!nodes.length && other_nodes.length) {
43640 nodes= other_nodes;
43642 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43648 createRange: function(sel)
43650 // this has strange effects when using with
43651 // top toolbar - not sure if it's a great idea.
43652 //this.editor.contentWindow.focus();
43653 if (typeof sel != "undefined") {
43655 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43657 return this.doc.createRange();
43660 return this.doc.createRange();
43663 getParentElement: function()
43666 this.assignDocWin();
43667 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43669 var range = this.createRange(sel);
43672 var p = range.commonAncestorContainer;
43673 while (p.nodeType == 3) { // text node
43684 * Range intersection.. the hard stuff...
43688 * [ -- selected range --- ]
43692 * if end is before start or hits it. fail.
43693 * if start is after end or hits it fail.
43695 * if either hits (but other is outside. - then it's not
43701 // @see http://www.thismuchiknow.co.uk/?p=64.
43702 rangeIntersectsNode : function(range, node)
43704 var nodeRange = node.ownerDocument.createRange();
43706 nodeRange.selectNode(node);
43708 nodeRange.selectNodeContents(node);
43711 var rangeStartRange = range.cloneRange();
43712 rangeStartRange.collapse(true);
43714 var rangeEndRange = range.cloneRange();
43715 rangeEndRange.collapse(false);
43717 var nodeStartRange = nodeRange.cloneRange();
43718 nodeStartRange.collapse(true);
43720 var nodeEndRange = nodeRange.cloneRange();
43721 nodeEndRange.collapse(false);
43723 return rangeStartRange.compareBoundaryPoints(
43724 Range.START_TO_START, nodeEndRange) == -1 &&
43725 rangeEndRange.compareBoundaryPoints(
43726 Range.START_TO_START, nodeStartRange) == 1;
43730 rangeCompareNode : function(range, node)
43732 var nodeRange = node.ownerDocument.createRange();
43734 nodeRange.selectNode(node);
43736 nodeRange.selectNodeContents(node);
43740 range.collapse(true);
43742 nodeRange.collapse(true);
43744 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43745 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43747 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43749 var nodeIsBefore = ss == 1;
43750 var nodeIsAfter = ee == -1;
43752 if (nodeIsBefore && nodeIsAfter) {
43755 if (!nodeIsBefore && nodeIsAfter) {
43756 return 1; //right trailed.
43759 if (nodeIsBefore && !nodeIsAfter) {
43760 return 2; // left trailed.
43766 // private? - in a new class?
43767 cleanUpPaste : function()
43769 // cleans up the whole document..
43770 Roo.log('cleanuppaste');
43772 this.cleanUpChildren(this.doc.body);
43773 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43774 if (clean != this.doc.body.innerHTML) {
43775 this.doc.body.innerHTML = clean;
43780 cleanWordChars : function(input) {// change the chars to hex code
43781 var he = Roo.HtmlEditorCore;
43783 var output = input;
43784 Roo.each(he.swapCodes, function(sw) {
43785 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43787 output = output.replace(swapper, sw[1]);
43794 cleanUpChildren : function (n)
43796 if (!n.childNodes.length) {
43799 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43800 this.cleanUpChild(n.childNodes[i]);
43807 cleanUpChild : function (node)
43810 //console.log(node);
43811 if (node.nodeName == "#text") {
43812 // clean up silly Windows -- stuff?
43815 if (node.nodeName == "#comment") {
43816 node.parentNode.removeChild(node);
43817 // clean up silly Windows -- stuff?
43820 var lcname = node.tagName.toLowerCase();
43821 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43822 // whitelist of tags..
43824 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43826 node.parentNode.removeChild(node);
43831 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43833 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43834 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43836 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43837 // remove_keep_children = true;
43840 if (remove_keep_children) {
43841 this.cleanUpChildren(node);
43842 // inserts everything just before this node...
43843 while (node.childNodes.length) {
43844 var cn = node.childNodes[0];
43845 node.removeChild(cn);
43846 node.parentNode.insertBefore(cn, node);
43848 node.parentNode.removeChild(node);
43852 if (!node.attributes || !node.attributes.length) {
43853 this.cleanUpChildren(node);
43857 function cleanAttr(n,v)
43860 if (v.match(/^\./) || v.match(/^\//)) {
43863 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
43866 if (v.match(/^#/)) {
43869 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43870 node.removeAttribute(n);
43874 var cwhite = this.cwhite;
43875 var cblack = this.cblack;
43877 function cleanStyle(n,v)
43879 if (v.match(/expression/)) { //XSS?? should we even bother..
43880 node.removeAttribute(n);
43884 var parts = v.split(/;/);
43887 Roo.each(parts, function(p) {
43888 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43892 var l = p.split(':').shift().replace(/\s+/g,'');
43893 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43895 if ( cwhite.length && cblack.indexOf(l) > -1) {
43896 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43897 //node.removeAttribute(n);
43901 // only allow 'c whitelisted system attributes'
43902 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43903 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43904 //node.removeAttribute(n);
43914 if (clean.length) {
43915 node.setAttribute(n, clean.join(';'));
43917 node.removeAttribute(n);
43923 for (var i = node.attributes.length-1; i > -1 ; i--) {
43924 var a = node.attributes[i];
43927 if (a.name.toLowerCase().substr(0,2)=='on') {
43928 node.removeAttribute(a.name);
43931 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43932 node.removeAttribute(a.name);
43935 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43936 cleanAttr(a.name,a.value); // fixme..
43939 if (a.name == 'style') {
43940 cleanStyle(a.name,a.value);
43943 /// clean up MS crap..
43944 // tecnically this should be a list of valid class'es..
43947 if (a.name == 'class') {
43948 if (a.value.match(/^Mso/)) {
43949 node.className = '';
43952 if (a.value.match(/^body$/)) {
43953 node.className = '';
43964 this.cleanUpChildren(node);
43970 * Clean up MS wordisms...
43972 cleanWord : function(node)
43977 this.cleanWord(this.doc.body);
43980 if (node.nodeName == "#text") {
43981 // clean up silly Windows -- stuff?
43984 if (node.nodeName == "#comment") {
43985 node.parentNode.removeChild(node);
43986 // clean up silly Windows -- stuff?
43990 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43991 node.parentNode.removeChild(node);
43995 // remove - but keep children..
43996 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43997 while (node.childNodes.length) {
43998 var cn = node.childNodes[0];
43999 node.removeChild(cn);
44000 node.parentNode.insertBefore(cn, node);
44002 node.parentNode.removeChild(node);
44003 this.iterateChildren(node, this.cleanWord);
44007 if (node.className.length) {
44009 var cn = node.className.split(/\W+/);
44011 Roo.each(cn, function(cls) {
44012 if (cls.match(/Mso[a-zA-Z]+/)) {
44017 node.className = cna.length ? cna.join(' ') : '';
44019 node.removeAttribute("class");
44023 if (node.hasAttribute("lang")) {
44024 node.removeAttribute("lang");
44027 if (node.hasAttribute("style")) {
44029 var styles = node.getAttribute("style").split(";");
44031 Roo.each(styles, function(s) {
44032 if (!s.match(/:/)) {
44035 var kv = s.split(":");
44036 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44039 // what ever is left... we allow.
44042 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44043 if (!nstyle.length) {
44044 node.removeAttribute('style');
44047 this.iterateChildren(node, this.cleanWord);
44053 * iterateChildren of a Node, calling fn each time, using this as the scole..
44054 * @param {DomNode} node node to iterate children of.
44055 * @param {Function} fn method of this class to call on each item.
44057 iterateChildren : function(node, fn)
44059 if (!node.childNodes.length) {
44062 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44063 fn.call(this, node.childNodes[i])
44069 * cleanTableWidths.
44071 * Quite often pasting from word etc.. results in tables with column and widths.
44072 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44075 cleanTableWidths : function(node)
44080 this.cleanTableWidths(this.doc.body);
44085 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44088 Roo.log(node.tagName);
44089 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44090 this.iterateChildren(node, this.cleanTableWidths);
44093 if (node.hasAttribute('width')) {
44094 node.removeAttribute('width');
44098 if (node.hasAttribute("style")) {
44101 var styles = node.getAttribute("style").split(";");
44103 Roo.each(styles, function(s) {
44104 if (!s.match(/:/)) {
44107 var kv = s.split(":");
44108 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44111 // what ever is left... we allow.
44114 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44115 if (!nstyle.length) {
44116 node.removeAttribute('style');
44120 this.iterateChildren(node, this.cleanTableWidths);
44128 domToHTML : function(currentElement, depth, nopadtext) {
44130 depth = depth || 0;
44131 nopadtext = nopadtext || false;
44133 if (!currentElement) {
44134 return this.domToHTML(this.doc.body);
44137 //Roo.log(currentElement);
44139 var allText = false;
44140 var nodeName = currentElement.nodeName;
44141 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44143 if (nodeName == '#text') {
44145 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44150 if (nodeName != 'BODY') {
44153 // Prints the node tagName, such as <A>, <IMG>, etc
44156 for(i = 0; i < currentElement.attributes.length;i++) {
44158 var aname = currentElement.attributes.item(i).name;
44159 if (!currentElement.attributes.item(i).value.length) {
44162 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44165 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44174 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44177 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44182 // Traverse the tree
44184 var currentElementChild = currentElement.childNodes.item(i);
44185 var allText = true;
44186 var innerHTML = '';
44188 while (currentElementChild) {
44189 // Formatting code (indent the tree so it looks nice on the screen)
44190 var nopad = nopadtext;
44191 if (lastnode == 'SPAN') {
44195 if (currentElementChild.nodeName == '#text') {
44196 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44197 toadd = nopadtext ? toadd : toadd.trim();
44198 if (!nopad && toadd.length > 80) {
44199 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44201 innerHTML += toadd;
44204 currentElementChild = currentElement.childNodes.item(i);
44210 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44212 // Recursively traverse the tree structure of the child node
44213 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44214 lastnode = currentElementChild.nodeName;
44216 currentElementChild=currentElement.childNodes.item(i);
44222 // The remaining code is mostly for formatting the tree
44223 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44228 ret+= "</"+tagName+">";
44234 applyBlacklists : function()
44236 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44237 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44241 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44242 if (b.indexOf(tag) > -1) {
44245 this.white.push(tag);
44249 Roo.each(w, function(tag) {
44250 if (b.indexOf(tag) > -1) {
44253 if (this.white.indexOf(tag) > -1) {
44256 this.white.push(tag);
44261 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44262 if (w.indexOf(tag) > -1) {
44265 this.black.push(tag);
44269 Roo.each(b, function(tag) {
44270 if (w.indexOf(tag) > -1) {
44273 if (this.black.indexOf(tag) > -1) {
44276 this.black.push(tag);
44281 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44282 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44286 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44287 if (b.indexOf(tag) > -1) {
44290 this.cwhite.push(tag);
44294 Roo.each(w, function(tag) {
44295 if (b.indexOf(tag) > -1) {
44298 if (this.cwhite.indexOf(tag) > -1) {
44301 this.cwhite.push(tag);
44306 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44307 if (w.indexOf(tag) > -1) {
44310 this.cblack.push(tag);
44314 Roo.each(b, function(tag) {
44315 if (w.indexOf(tag) > -1) {
44318 if (this.cblack.indexOf(tag) > -1) {
44321 this.cblack.push(tag);
44326 setStylesheets : function(stylesheets)
44328 if(typeof(stylesheets) == 'string'){
44329 Roo.get(this.iframe.contentDocument.head).createChild({
44331 rel : 'stylesheet',
44340 Roo.each(stylesheets, function(s) {
44345 Roo.get(_this.iframe.contentDocument.head).createChild({
44347 rel : 'stylesheet',
44356 removeStylesheets : function()
44360 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44365 setStyle : function(style)
44367 Roo.get(this.iframe.contentDocument.head).createChild({
44376 // hide stuff that is not compatible
44390 * @event specialkey
44394 * @cfg {String} fieldClass @hide
44397 * @cfg {String} focusClass @hide
44400 * @cfg {String} autoCreate @hide
44403 * @cfg {String} inputType @hide
44406 * @cfg {String} invalidClass @hide
44409 * @cfg {String} invalidText @hide
44412 * @cfg {String} msgFx @hide
44415 * @cfg {String} validateOnBlur @hide
44419 Roo.HtmlEditorCore.white = [
44420 'area', 'br', 'img', 'input', 'hr', 'wbr',
44422 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44423 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44424 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44425 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44426 'table', 'ul', 'xmp',
44428 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44431 'dir', 'menu', 'ol', 'ul', 'dl',
44437 Roo.HtmlEditorCore.black = [
44438 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44440 'base', 'basefont', 'bgsound', 'blink', 'body',
44441 'frame', 'frameset', 'head', 'html', 'ilayer',
44442 'iframe', 'layer', 'link', 'meta', 'object',
44443 'script', 'style' ,'title', 'xml' // clean later..
44445 Roo.HtmlEditorCore.clean = [
44446 'script', 'style', 'title', 'xml'
44448 Roo.HtmlEditorCore.remove = [
44453 Roo.HtmlEditorCore.ablack = [
44457 Roo.HtmlEditorCore.aclean = [
44458 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44462 Roo.HtmlEditorCore.pwhite= [
44463 'http', 'https', 'mailto'
44466 // white listed style attributes.
44467 Roo.HtmlEditorCore.cwhite= [
44468 // 'text-align', /// default is to allow most things..
44474 // black listed style attributes.
44475 Roo.HtmlEditorCore.cblack= [
44476 // 'font-size' -- this can be set by the project
44480 Roo.HtmlEditorCore.swapCodes =[
44491 //<script type="text/javascript">
44494 * Ext JS Library 1.1.1
44495 * Copyright(c) 2006-2007, Ext JS, LLC.
44501 Roo.form.HtmlEditor = function(config){
44505 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44507 if (!this.toolbars) {
44508 this.toolbars = [];
44510 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44516 * @class Roo.form.HtmlEditor
44517 * @extends Roo.form.Field
44518 * Provides a lightweight HTML Editor component.
44520 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44522 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44523 * supported by this editor.</b><br/><br/>
44524 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44525 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44527 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44529 * @cfg {Boolean} clearUp
44533 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44538 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44543 * @cfg {Number} height (in pixels)
44547 * @cfg {Number} width (in pixels)
44552 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44555 stylesheets: false,
44559 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44564 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44570 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44575 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44583 // private properties
44584 validationEvent : false,
44586 initialized : false,
44589 onFocus : Roo.emptyFn,
44591 hideMode:'offsets',
44593 actionMode : 'container', // defaults to hiding it...
44595 defaultAutoCreate : { // modified by initCompnoent..
44597 style:"width:500px;height:300px;",
44598 autocomplete: "new-password"
44602 initComponent : function(){
44605 * @event initialize
44606 * Fires when the editor is fully initialized (including the iframe)
44607 * @param {HtmlEditor} this
44612 * Fires when the editor is first receives the focus. Any insertion must wait
44613 * until after this event.
44614 * @param {HtmlEditor} this
44618 * @event beforesync
44619 * Fires before the textarea is updated with content from the editor iframe. Return false
44620 * to cancel the sync.
44621 * @param {HtmlEditor} this
44622 * @param {String} html
44626 * @event beforepush
44627 * Fires before the iframe editor is updated with content from the textarea. Return false
44628 * to cancel the push.
44629 * @param {HtmlEditor} this
44630 * @param {String} html
44635 * Fires when the textarea is updated with content from the editor iframe.
44636 * @param {HtmlEditor} this
44637 * @param {String} html
44642 * Fires when the iframe editor is updated with content from the textarea.
44643 * @param {HtmlEditor} this
44644 * @param {String} html
44648 * @event editmodechange
44649 * Fires when the editor switches edit modes
44650 * @param {HtmlEditor} this
44651 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44653 editmodechange: true,
44655 * @event editorevent
44656 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44657 * @param {HtmlEditor} this
44661 * @event firstfocus
44662 * Fires when on first focus - needed by toolbars..
44663 * @param {HtmlEditor} this
44668 * Auto save the htmlEditor value as a file into Events
44669 * @param {HtmlEditor} this
44673 * @event savedpreview
44674 * preview the saved version of htmlEditor
44675 * @param {HtmlEditor} this
44677 savedpreview: true,
44680 * @event stylesheetsclick
44681 * Fires when press the Sytlesheets button
44682 * @param {Roo.HtmlEditorCore} this
44684 stylesheetsclick: true
44686 this.defaultAutoCreate = {
44688 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44689 autocomplete: "new-password"
44694 * Protected method that will not generally be called directly. It
44695 * is called when the editor creates its toolbar. Override this method if you need to
44696 * add custom toolbar buttons.
44697 * @param {HtmlEditor} editor
44699 createToolbar : function(editor){
44700 Roo.log("create toolbars");
44701 if (!editor.toolbars || !editor.toolbars.length) {
44702 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44705 for (var i =0 ; i < editor.toolbars.length;i++) {
44706 editor.toolbars[i] = Roo.factory(
44707 typeof(editor.toolbars[i]) == 'string' ?
44708 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44709 Roo.form.HtmlEditor);
44710 editor.toolbars[i].init(editor);
44718 onRender : function(ct, position)
44721 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44723 this.wrap = this.el.wrap({
44724 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44727 this.editorcore.onRender(ct, position);
44729 if (this.resizable) {
44730 this.resizeEl = new Roo.Resizable(this.wrap, {
44734 minHeight : this.height,
44735 height: this.height,
44736 handles : this.resizable,
44739 resize : function(r, w, h) {
44740 _t.onResize(w,h); // -something
44746 this.createToolbar(this);
44750 this.setSize(this.wrap.getSize());
44752 if (this.resizeEl) {
44753 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44754 // should trigger onReize..
44757 this.keyNav = new Roo.KeyNav(this.el, {
44759 "tab" : function(e){
44760 e.preventDefault();
44762 var value = this.getValue();
44764 var start = this.el.dom.selectionStart;
44765 var end = this.el.dom.selectionEnd;
44769 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44770 this.el.dom.setSelectionRange(end + 1, end + 1);
44774 var f = value.substring(0, start).split("\t");
44776 if(f.pop().length != 0){
44780 this.setValue(f.join("\t") + value.substring(end));
44781 this.el.dom.setSelectionRange(start - 1, start - 1);
44785 "home" : function(e){
44786 e.preventDefault();
44788 var curr = this.el.dom.selectionStart;
44789 var lines = this.getValue().split("\n");
44796 this.el.dom.setSelectionRange(0, 0);
44802 for (var i = 0; i < lines.length;i++) {
44803 pos += lines[i].length;
44813 pos -= lines[i].length;
44819 this.el.dom.setSelectionRange(pos, pos);
44823 this.el.dom.selectionStart = pos;
44824 this.el.dom.selectionEnd = curr;
44827 "end" : function(e){
44828 e.preventDefault();
44830 var curr = this.el.dom.selectionStart;
44831 var lines = this.getValue().split("\n");
44838 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44844 for (var i = 0; i < lines.length;i++) {
44846 pos += lines[i].length;
44860 this.el.dom.setSelectionRange(pos, pos);
44864 this.el.dom.selectionStart = curr;
44865 this.el.dom.selectionEnd = pos;
44870 doRelay : function(foo, bar, hname){
44871 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44877 // if(this.autosave && this.w){
44878 // this.autoSaveFn = setInterval(this.autosave, 1000);
44883 onResize : function(w, h)
44885 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44890 if(typeof w == 'number'){
44891 var aw = w - this.wrap.getFrameWidth('lr');
44892 this.el.setWidth(this.adjustWidth('textarea', aw));
44895 if(typeof h == 'number'){
44897 for (var i =0; i < this.toolbars.length;i++) {
44898 // fixme - ask toolbars for heights?
44899 tbh += this.toolbars[i].tb.el.getHeight();
44900 if (this.toolbars[i].footer) {
44901 tbh += this.toolbars[i].footer.el.getHeight();
44908 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44909 ah -= 5; // knock a few pixes off for look..
44911 this.el.setHeight(this.adjustWidth('textarea', ah));
44915 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44916 this.editorcore.onResize(ew,eh);
44921 * Toggles the editor between standard and source edit mode.
44922 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44924 toggleSourceEdit : function(sourceEditMode)
44926 this.editorcore.toggleSourceEdit(sourceEditMode);
44928 if(this.editorcore.sourceEditMode){
44929 Roo.log('editor - showing textarea');
44932 // Roo.log(this.syncValue());
44933 this.editorcore.syncValue();
44934 this.el.removeClass('x-hidden');
44935 this.el.dom.removeAttribute('tabIndex');
44938 for (var i = 0; i < this.toolbars.length; i++) {
44939 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44940 this.toolbars[i].tb.hide();
44941 this.toolbars[i].footer.hide();
44946 Roo.log('editor - hiding textarea');
44948 // Roo.log(this.pushValue());
44949 this.editorcore.pushValue();
44951 this.el.addClass('x-hidden');
44952 this.el.dom.setAttribute('tabIndex', -1);
44954 for (var i = 0; i < this.toolbars.length; i++) {
44955 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44956 this.toolbars[i].tb.show();
44957 this.toolbars[i].footer.show();
44961 //this.deferFocus();
44964 this.setSize(this.wrap.getSize());
44965 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44967 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44970 // private (for BoxComponent)
44971 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44973 // private (for BoxComponent)
44974 getResizeEl : function(){
44978 // private (for BoxComponent)
44979 getPositionEl : function(){
44984 initEvents : function(){
44985 this.originalValue = this.getValue();
44989 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44992 markInvalid : Roo.emptyFn,
44994 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44997 clearInvalid : Roo.emptyFn,
44999 setValue : function(v){
45000 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45001 this.editorcore.pushValue();
45006 deferFocus : function(){
45007 this.focus.defer(10, this);
45011 focus : function(){
45012 this.editorcore.focus();
45018 onDestroy : function(){
45024 for (var i =0; i < this.toolbars.length;i++) {
45025 // fixme - ask toolbars for heights?
45026 this.toolbars[i].onDestroy();
45029 this.wrap.dom.innerHTML = '';
45030 this.wrap.remove();
45035 onFirstFocus : function(){
45036 //Roo.log("onFirstFocus");
45037 this.editorcore.onFirstFocus();
45038 for (var i =0; i < this.toolbars.length;i++) {
45039 this.toolbars[i].onFirstFocus();
45045 syncValue : function()
45047 this.editorcore.syncValue();
45050 pushValue : function()
45052 this.editorcore.pushValue();
45055 setStylesheets : function(stylesheets)
45057 this.editorcore.setStylesheets(stylesheets);
45060 removeStylesheets : function()
45062 this.editorcore.removeStylesheets();
45066 // hide stuff that is not compatible
45080 * @event specialkey
45084 * @cfg {String} fieldClass @hide
45087 * @cfg {String} focusClass @hide
45090 * @cfg {String} autoCreate @hide
45093 * @cfg {String} inputType @hide
45096 * @cfg {String} invalidClass @hide
45099 * @cfg {String} invalidText @hide
45102 * @cfg {String} msgFx @hide
45105 * @cfg {String} validateOnBlur @hide
45109 // <script type="text/javascript">
45112 * Ext JS Library 1.1.1
45113 * Copyright(c) 2006-2007, Ext JS, LLC.
45119 * @class Roo.form.HtmlEditorToolbar1
45124 new Roo.form.HtmlEditor({
45127 new Roo.form.HtmlEditorToolbar1({
45128 disable : { fonts: 1 , format: 1, ..., ... , ...],
45134 * @cfg {Object} disable List of elements to disable..
45135 * @cfg {Array} btns List of additional buttons.
45139 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45142 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45145 Roo.apply(this, config);
45147 // default disabled, based on 'good practice'..
45148 this.disable = this.disable || {};
45149 Roo.applyIf(this.disable, {
45152 specialElements : true
45156 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45157 // dont call parent... till later.
45160 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45167 editorcore : false,
45169 * @cfg {Object} disable List of toolbar elements to disable
45176 * @cfg {String} createLinkText The default text for the create link prompt
45178 createLinkText : 'Please enter the URL for the link:',
45180 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45182 defaultLinkValue : 'http:/'+'/',
45186 * @cfg {Array} fontFamilies An array of available font families
45204 // "á" , ?? a acute?
45209 "°" // , // degrees
45211 // "é" , // e ecute
45212 // "ú" , // u ecute?
45215 specialElements : [
45217 text: "Insert Table",
45220 ihtml : '<table><tr><td>Cell</td></tr></table>'
45224 text: "Insert Image",
45227 ihtml : '<img src="about:blank"/>'
45236 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45237 "input:submit", "input:button", "select", "textarea", "label" ],
45240 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45242 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45250 * @cfg {String} defaultFont default font to use.
45252 defaultFont: 'tahoma',
45254 fontSelect : false,
45257 formatCombo : false,
45259 init : function(editor)
45261 this.editor = editor;
45262 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45263 var editorcore = this.editorcore;
45267 var fid = editorcore.frameId;
45269 function btn(id, toggle, handler){
45270 var xid = fid + '-'+ id ;
45274 cls : 'x-btn-icon x-edit-'+id,
45275 enableToggle:toggle !== false,
45276 scope: _t, // was editor...
45277 handler:handler||_t.relayBtnCmd,
45278 clickEvent:'mousedown',
45279 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45286 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45288 // stop form submits
45289 tb.el.on('click', function(e){
45290 e.preventDefault(); // what does this do?
45293 if(!this.disable.font) { // && !Roo.isSafari){
45294 /* why no safari for fonts
45295 editor.fontSelect = tb.el.createChild({
45298 cls:'x-font-select',
45299 html: this.createFontOptions()
45302 editor.fontSelect.on('change', function(){
45303 var font = editor.fontSelect.dom.value;
45304 editor.relayCmd('fontname', font);
45305 editor.deferFocus();
45309 editor.fontSelect.dom,
45315 if(!this.disable.formats){
45316 this.formatCombo = new Roo.form.ComboBox({
45317 store: new Roo.data.SimpleStore({
45320 data : this.formats // from states.js
45324 //autoCreate : {tag: "div", size: "20"},
45325 displayField:'tag',
45329 triggerAction: 'all',
45330 emptyText:'Add tag',
45331 selectOnFocus:true,
45334 'select': function(c, r, i) {
45335 editorcore.insertTag(r.get('tag'));
45341 tb.addField(this.formatCombo);
45345 if(!this.disable.format){
45350 btn('strikethrough')
45353 if(!this.disable.fontSize){
45358 btn('increasefontsize', false, editorcore.adjustFont),
45359 btn('decreasefontsize', false, editorcore.adjustFont)
45364 if(!this.disable.colors){
45367 id:editorcore.frameId +'-forecolor',
45368 cls:'x-btn-icon x-edit-forecolor',
45369 clickEvent:'mousedown',
45370 tooltip: this.buttonTips['forecolor'] || undefined,
45372 menu : new Roo.menu.ColorMenu({
45373 allowReselect: true,
45374 focus: Roo.emptyFn,
45377 selectHandler: function(cp, color){
45378 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45379 editor.deferFocus();
45382 clickEvent:'mousedown'
45385 id:editorcore.frameId +'backcolor',
45386 cls:'x-btn-icon x-edit-backcolor',
45387 clickEvent:'mousedown',
45388 tooltip: this.buttonTips['backcolor'] || undefined,
45390 menu : new Roo.menu.ColorMenu({
45391 focus: Roo.emptyFn,
45394 allowReselect: true,
45395 selectHandler: function(cp, color){
45397 editorcore.execCmd('useCSS', false);
45398 editorcore.execCmd('hilitecolor', color);
45399 editorcore.execCmd('useCSS', true);
45400 editor.deferFocus();
45402 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45403 Roo.isSafari || Roo.isIE ? '#'+color : color);
45404 editor.deferFocus();
45408 clickEvent:'mousedown'
45413 // now add all the items...
45416 if(!this.disable.alignments){
45419 btn('justifyleft'),
45420 btn('justifycenter'),
45421 btn('justifyright')
45425 //if(!Roo.isSafari){
45426 if(!this.disable.links){
45429 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45433 if(!this.disable.lists){
45436 btn('insertorderedlist'),
45437 btn('insertunorderedlist')
45440 if(!this.disable.sourceEdit){
45443 btn('sourceedit', true, function(btn){
45444 this.toggleSourceEdit(btn.pressed);
45451 // special menu.. - needs to be tidied up..
45452 if (!this.disable.special) {
45455 cls: 'x-edit-none',
45461 for (var i =0; i < this.specialChars.length; i++) {
45462 smenu.menu.items.push({
45464 html: this.specialChars[i],
45465 handler: function(a,b) {
45466 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45467 //editor.insertAtCursor(a.html);
45481 if (!this.disable.cleanStyles) {
45483 cls: 'x-btn-icon x-btn-clear',
45489 for (var i =0; i < this.cleanStyles.length; i++) {
45490 cmenu.menu.items.push({
45491 actiontype : this.cleanStyles[i],
45492 html: 'Remove ' + this.cleanStyles[i],
45493 handler: function(a,b) {
45496 var c = Roo.get(editorcore.doc.body);
45497 c.select('[style]').each(function(s) {
45498 s.dom.style.removeProperty(a.actiontype);
45500 editorcore.syncValue();
45505 cmenu.menu.items.push({
45506 actiontype : 'tablewidths',
45507 html: 'Remove Table Widths',
45508 handler: function(a,b) {
45509 editorcore.cleanTableWidths();
45510 editorcore.syncValue();
45514 cmenu.menu.items.push({
45515 actiontype : 'word',
45516 html: 'Remove MS Word Formating',
45517 handler: function(a,b) {
45518 editorcore.cleanWord();
45519 editorcore.syncValue();
45524 cmenu.menu.items.push({
45525 actiontype : 'all',
45526 html: 'Remove All Styles',
45527 handler: function(a,b) {
45529 var c = Roo.get(editorcore.doc.body);
45530 c.select('[style]').each(function(s) {
45531 s.dom.removeAttribute('style');
45533 editorcore.syncValue();
45538 cmenu.menu.items.push({
45539 actiontype : 'all',
45540 html: 'Remove All CSS Classes',
45541 handler: function(a,b) {
45543 var c = Roo.get(editorcore.doc.body);
45544 c.select('[class]').each(function(s) {
45545 s.dom.className = '';
45547 editorcore.syncValue();
45552 cmenu.menu.items.push({
45553 actiontype : 'tidy',
45554 html: 'Tidy HTML Source',
45555 handler: function(a,b) {
45556 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45557 editorcore.syncValue();
45566 if (!this.disable.specialElements) {
45569 cls: 'x-edit-none',
45574 for (var i =0; i < this.specialElements.length; i++) {
45575 semenu.menu.items.push(
45577 handler: function(a,b) {
45578 editor.insertAtCursor(this.ihtml);
45580 }, this.specialElements[i])
45592 for(var i =0; i< this.btns.length;i++) {
45593 var b = Roo.factory(this.btns[i],Roo.form);
45594 b.cls = 'x-edit-none';
45596 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45597 b.cls += ' x-init-enable';
45600 b.scope = editorcore;
45608 // disable everything...
45610 this.tb.items.each(function(item){
45613 item.id != editorcore.frameId+ '-sourceedit' &&
45614 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45620 this.rendered = true;
45622 // the all the btns;
45623 editor.on('editorevent', this.updateToolbar, this);
45624 // other toolbars need to implement this..
45625 //editor.on('editmodechange', this.updateToolbar, this);
45629 relayBtnCmd : function(btn) {
45630 this.editorcore.relayCmd(btn.cmd);
45632 // private used internally
45633 createLink : function(){
45634 Roo.log("create link?");
45635 var url = prompt(this.createLinkText, this.defaultLinkValue);
45636 if(url && url != 'http:/'+'/'){
45637 this.editorcore.relayCmd('createlink', url);
45643 * Protected method that will not generally be called directly. It triggers
45644 * a toolbar update by reading the markup state of the current selection in the editor.
45646 updateToolbar: function(){
45648 if(!this.editorcore.activated){
45649 this.editor.onFirstFocus();
45653 var btns = this.tb.items.map,
45654 doc = this.editorcore.doc,
45655 frameId = this.editorcore.frameId;
45657 if(!this.disable.font && !Roo.isSafari){
45659 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45660 if(name != this.fontSelect.dom.value){
45661 this.fontSelect.dom.value = name;
45665 if(!this.disable.format){
45666 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45667 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45668 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45669 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45671 if(!this.disable.alignments){
45672 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45673 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45674 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45676 if(!Roo.isSafari && !this.disable.lists){
45677 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45678 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45681 var ans = this.editorcore.getAllAncestors();
45682 if (this.formatCombo) {
45685 var store = this.formatCombo.store;
45686 this.formatCombo.setValue("");
45687 for (var i =0; i < ans.length;i++) {
45688 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45690 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45698 // hides menus... - so this cant be on a menu...
45699 Roo.menu.MenuMgr.hideAll();
45701 //this.editorsyncValue();
45705 createFontOptions : function(){
45706 var buf = [], fs = this.fontFamilies, ff, lc;
45710 for(var i = 0, len = fs.length; i< len; i++){
45712 lc = ff.toLowerCase();
45714 '<option value="',lc,'" style="font-family:',ff,';"',
45715 (this.defaultFont == lc ? ' selected="true">' : '>'),
45720 return buf.join('');
45723 toggleSourceEdit : function(sourceEditMode){
45725 Roo.log("toolbar toogle");
45726 if(sourceEditMode === undefined){
45727 sourceEditMode = !this.sourceEditMode;
45729 this.sourceEditMode = sourceEditMode === true;
45730 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45731 // just toggle the button?
45732 if(btn.pressed !== this.sourceEditMode){
45733 btn.toggle(this.sourceEditMode);
45737 if(sourceEditMode){
45738 Roo.log("disabling buttons");
45739 this.tb.items.each(function(item){
45740 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45746 Roo.log("enabling buttons");
45747 if(this.editorcore.initialized){
45748 this.tb.items.each(function(item){
45754 Roo.log("calling toggole on editor");
45755 // tell the editor that it's been pressed..
45756 this.editor.toggleSourceEdit(sourceEditMode);
45760 * Object collection of toolbar tooltips for the buttons in the editor. The key
45761 * is the command id associated with that button and the value is a valid QuickTips object.
45766 title: 'Bold (Ctrl+B)',
45767 text: 'Make the selected text bold.',
45768 cls: 'x-html-editor-tip'
45771 title: 'Italic (Ctrl+I)',
45772 text: 'Make the selected text italic.',
45773 cls: 'x-html-editor-tip'
45781 title: 'Bold (Ctrl+B)',
45782 text: 'Make the selected text bold.',
45783 cls: 'x-html-editor-tip'
45786 title: 'Italic (Ctrl+I)',
45787 text: 'Make the selected text italic.',
45788 cls: 'x-html-editor-tip'
45791 title: 'Underline (Ctrl+U)',
45792 text: 'Underline the selected text.',
45793 cls: 'x-html-editor-tip'
45796 title: 'Strikethrough',
45797 text: 'Strikethrough the selected text.',
45798 cls: 'x-html-editor-tip'
45800 increasefontsize : {
45801 title: 'Grow Text',
45802 text: 'Increase the font size.',
45803 cls: 'x-html-editor-tip'
45805 decreasefontsize : {
45806 title: 'Shrink Text',
45807 text: 'Decrease the font size.',
45808 cls: 'x-html-editor-tip'
45811 title: 'Text Highlight Color',
45812 text: 'Change the background color of the selected text.',
45813 cls: 'x-html-editor-tip'
45816 title: 'Font Color',
45817 text: 'Change the color of the selected text.',
45818 cls: 'x-html-editor-tip'
45821 title: 'Align Text Left',
45822 text: 'Align text to the left.',
45823 cls: 'x-html-editor-tip'
45826 title: 'Center Text',
45827 text: 'Center text in the editor.',
45828 cls: 'x-html-editor-tip'
45831 title: 'Align Text Right',
45832 text: 'Align text to the right.',
45833 cls: 'x-html-editor-tip'
45835 insertunorderedlist : {
45836 title: 'Bullet List',
45837 text: 'Start a bulleted list.',
45838 cls: 'x-html-editor-tip'
45840 insertorderedlist : {
45841 title: 'Numbered List',
45842 text: 'Start a numbered list.',
45843 cls: 'x-html-editor-tip'
45846 title: 'Hyperlink',
45847 text: 'Make the selected text a hyperlink.',
45848 cls: 'x-html-editor-tip'
45851 title: 'Source Edit',
45852 text: 'Switch to source editing mode.',
45853 cls: 'x-html-editor-tip'
45857 onDestroy : function(){
45860 this.tb.items.each(function(item){
45862 item.menu.removeAll();
45864 item.menu.el.destroy();
45872 onFirstFocus: function() {
45873 this.tb.items.each(function(item){
45882 // <script type="text/javascript">
45885 * Ext JS Library 1.1.1
45886 * Copyright(c) 2006-2007, Ext JS, LLC.
45893 * @class Roo.form.HtmlEditor.ToolbarContext
45898 new Roo.form.HtmlEditor({
45901 { xtype: 'ToolbarStandard', styles : {} }
45902 { xtype: 'ToolbarContext', disable : {} }
45908 * @config : {Object} disable List of elements to disable.. (not done yet.)
45909 * @config : {Object} styles Map of styles available.
45913 Roo.form.HtmlEditor.ToolbarContext = function(config)
45916 Roo.apply(this, config);
45917 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45918 // dont call parent... till later.
45919 this.styles = this.styles || {};
45924 Roo.form.HtmlEditor.ToolbarContext.types = {
45936 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46002 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46007 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46017 style : 'fontFamily',
46018 displayField: 'display',
46019 optname : 'font-family',
46068 // should we really allow this??
46069 // should this just be
46080 style : 'fontFamily',
46081 displayField: 'display',
46082 optname : 'font-family',
46089 style : 'fontFamily',
46090 displayField: 'display',
46091 optname : 'font-family',
46098 style : 'fontFamily',
46099 displayField: 'display',
46100 optname : 'font-family',
46111 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46112 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46114 Roo.form.HtmlEditor.ToolbarContext.options = {
46116 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46117 [ 'Courier New', 'Courier New'],
46118 [ 'Tahoma', 'Tahoma'],
46119 [ 'Times New Roman,serif', 'Times'],
46120 [ 'Verdana','Verdana' ]
46124 // fixme - these need to be configurable..
46127 //Roo.form.HtmlEditor.ToolbarContext.types
46130 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46137 editorcore : false,
46139 * @cfg {Object} disable List of toolbar elements to disable
46144 * @cfg {Object} styles List of styles
46145 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46147 * These must be defined in the page, so they get rendered correctly..
46158 init : function(editor)
46160 this.editor = editor;
46161 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46162 var editorcore = this.editorcore;
46164 var fid = editorcore.frameId;
46166 function btn(id, toggle, handler){
46167 var xid = fid + '-'+ id ;
46171 cls : 'x-btn-icon x-edit-'+id,
46172 enableToggle:toggle !== false,
46173 scope: editorcore, // was editor...
46174 handler:handler||editorcore.relayBtnCmd,
46175 clickEvent:'mousedown',
46176 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46180 // create a new element.
46181 var wdiv = editor.wrap.createChild({
46183 }, editor.wrap.dom.firstChild.nextSibling, true);
46185 // can we do this more than once??
46187 // stop form submits
46190 // disable everything...
46191 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46192 this.toolbars = {};
46194 for (var i in ty) {
46196 this.toolbars[i] = this.buildToolbar(ty[i],i);
46198 this.tb = this.toolbars.BODY;
46200 this.buildFooter();
46201 this.footer.show();
46202 editor.on('hide', function( ) { this.footer.hide() }, this);
46203 editor.on('show', function( ) { this.footer.show() }, this);
46206 this.rendered = true;
46208 // the all the btns;
46209 editor.on('editorevent', this.updateToolbar, this);
46210 // other toolbars need to implement this..
46211 //editor.on('editmodechange', this.updateToolbar, this);
46217 * Protected method that will not generally be called directly. It triggers
46218 * a toolbar update by reading the markup state of the current selection in the editor.
46220 * Note you can force an update by calling on('editorevent', scope, false)
46222 updateToolbar: function(editor,ev,sel){
46225 // capture mouse up - this is handy for selecting images..
46226 // perhaps should go somewhere else...
46227 if(!this.editorcore.activated){
46228 this.editor.onFirstFocus();
46234 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46235 // selectNode - might want to handle IE?
46237 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46238 ev.target && ev.target.tagName == 'IMG') {
46239 // they have click on an image...
46240 // let's see if we can change the selection...
46243 var nodeRange = sel.ownerDocument.createRange();
46245 nodeRange.selectNode(sel);
46247 nodeRange.selectNodeContents(sel);
46249 //nodeRange.collapse(true);
46250 var s = this.editorcore.win.getSelection();
46251 s.removeAllRanges();
46252 s.addRange(nodeRange);
46256 var updateFooter = sel ? false : true;
46259 var ans = this.editorcore.getAllAncestors();
46262 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46265 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46266 sel = sel ? sel : this.editorcore.doc.body;
46267 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46270 // pick a menu that exists..
46271 var tn = sel.tagName.toUpperCase();
46272 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46274 tn = sel.tagName.toUpperCase();
46276 var lastSel = this.tb.selectedNode;
46278 this.tb.selectedNode = sel;
46280 // if current menu does not match..
46282 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46285 ///console.log("show: " + tn);
46286 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46289 this.tb.items.first().el.innerHTML = tn + ': ';
46292 // update attributes
46293 if (this.tb.fields) {
46294 this.tb.fields.each(function(e) {
46296 e.setValue(sel.style[e.stylename]);
46299 e.setValue(sel.getAttribute(e.attrname));
46303 var hasStyles = false;
46304 for(var i in this.styles) {
46311 var st = this.tb.fields.item(0);
46313 st.store.removeAll();
46316 var cn = sel.className.split(/\s+/);
46319 if (this.styles['*']) {
46321 Roo.each(this.styles['*'], function(v) {
46322 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46325 if (this.styles[tn]) {
46326 Roo.each(this.styles[tn], function(v) {
46327 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46331 st.store.loadData(avs);
46335 // flag our selected Node.
46336 this.tb.selectedNode = sel;
46339 Roo.menu.MenuMgr.hideAll();
46343 if (!updateFooter) {
46344 //this.footDisp.dom.innerHTML = '';
46347 // update the footer
46351 this.footerEls = ans.reverse();
46352 Roo.each(this.footerEls, function(a,i) {
46353 if (!a) { return; }
46354 html += html.length ? ' > ' : '';
46356 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46361 var sz = this.footDisp.up('td').getSize();
46362 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46363 this.footDisp.dom.style.marginLeft = '5px';
46365 this.footDisp.dom.style.overflow = 'hidden';
46367 this.footDisp.dom.innerHTML = html;
46369 //this.editorsyncValue();
46376 onDestroy : function(){
46379 this.tb.items.each(function(item){
46381 item.menu.removeAll();
46383 item.menu.el.destroy();
46391 onFirstFocus: function() {
46392 // need to do this for all the toolbars..
46393 this.tb.items.each(function(item){
46397 buildToolbar: function(tlist, nm)
46399 var editor = this.editor;
46400 var editorcore = this.editorcore;
46401 // create a new element.
46402 var wdiv = editor.wrap.createChild({
46404 }, editor.wrap.dom.firstChild.nextSibling, true);
46407 var tb = new Roo.Toolbar(wdiv);
46410 tb.add(nm+ ": ");
46413 for(var i in this.styles) {
46418 if (styles && styles.length) {
46420 // this needs a multi-select checkbox...
46421 tb.addField( new Roo.form.ComboBox({
46422 store: new Roo.data.SimpleStore({
46424 fields: ['val', 'selected'],
46427 name : '-roo-edit-className',
46428 attrname : 'className',
46429 displayField: 'val',
46433 triggerAction: 'all',
46434 emptyText:'Select Style',
46435 selectOnFocus:true,
46438 'select': function(c, r, i) {
46439 // initial support only for on class per el..
46440 tb.selectedNode.className = r ? r.get('val') : '';
46441 editorcore.syncValue();
46448 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46449 var tbops = tbc.options;
46451 for (var i in tlist) {
46453 var item = tlist[i];
46454 tb.add(item.title + ": ");
46457 //optname == used so you can configure the options available..
46458 var opts = item.opts ? item.opts : false;
46459 if (item.optname) {
46460 opts = tbops[item.optname];
46465 // opts == pulldown..
46466 tb.addField( new Roo.form.ComboBox({
46467 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46469 fields: ['val', 'display'],
46472 name : '-roo-edit-' + i,
46474 stylename : item.style ? item.style : false,
46475 displayField: item.displayField ? item.displayField : 'val',
46476 valueField : 'val',
46478 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46480 triggerAction: 'all',
46481 emptyText:'Select',
46482 selectOnFocus:true,
46483 width: item.width ? item.width : 130,
46485 'select': function(c, r, i) {
46487 tb.selectedNode.style[c.stylename] = r.get('val');
46490 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46499 tb.addField( new Roo.form.TextField({
46502 //allowBlank:false,
46507 tb.addField( new Roo.form.TextField({
46508 name: '-roo-edit-' + i,
46515 'change' : function(f, nv, ov) {
46516 tb.selectedNode.setAttribute(f.attrname, nv);
46517 editorcore.syncValue();
46530 text: 'Stylesheets',
46533 click : function ()
46535 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46543 text: 'Remove Tag',
46546 click : function ()
46549 // undo does not work.
46551 var sn = tb.selectedNode;
46553 var pn = sn.parentNode;
46555 var stn = sn.childNodes[0];
46556 var en = sn.childNodes[sn.childNodes.length - 1 ];
46557 while (sn.childNodes.length) {
46558 var node = sn.childNodes[0];
46559 sn.removeChild(node);
46561 pn.insertBefore(node, sn);
46564 pn.removeChild(sn);
46565 var range = editorcore.createRange();
46567 range.setStart(stn,0);
46568 range.setEnd(en,0); //????
46569 //range.selectNode(sel);
46572 var selection = editorcore.getSelection();
46573 selection.removeAllRanges();
46574 selection.addRange(range);
46578 //_this.updateToolbar(null, null, pn);
46579 _this.updateToolbar(null, null, null);
46580 _this.footDisp.dom.innerHTML = '';
46590 tb.el.on('click', function(e){
46591 e.preventDefault(); // what does this do?
46593 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46596 // dont need to disable them... as they will get hidden
46601 buildFooter : function()
46604 var fel = this.editor.wrap.createChild();
46605 this.footer = new Roo.Toolbar(fel);
46606 // toolbar has scrolly on left / right?
46607 var footDisp= new Roo.Toolbar.Fill();
46613 handler : function() {
46614 _t.footDisp.scrollTo('left',0,true)
46618 this.footer.add( footDisp );
46623 handler : function() {
46625 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46629 var fel = Roo.get(footDisp.el);
46630 fel.addClass('x-editor-context');
46631 this.footDispWrap = fel;
46632 this.footDispWrap.overflow = 'hidden';
46634 this.footDisp = fel.createChild();
46635 this.footDispWrap.on('click', this.onContextClick, this)
46639 onContextClick : function (ev,dom)
46641 ev.preventDefault();
46642 var cn = dom.className;
46644 if (!cn.match(/x-ed-loc-/)) {
46647 var n = cn.split('-').pop();
46648 var ans = this.footerEls;
46652 var range = this.editorcore.createRange();
46654 range.selectNodeContents(sel);
46655 //range.selectNode(sel);
46658 var selection = this.editorcore.getSelection();
46659 selection.removeAllRanges();
46660 selection.addRange(range);
46664 this.updateToolbar(null, null, sel);
46681 * Ext JS Library 1.1.1
46682 * Copyright(c) 2006-2007, Ext JS, LLC.
46684 * Originally Released Under LGPL - original licence link has changed is not relivant.
46687 * <script type="text/javascript">
46691 * @class Roo.form.BasicForm
46692 * @extends Roo.util.Observable
46693 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46695 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46696 * @param {Object} config Configuration options
46698 Roo.form.BasicForm = function(el, config){
46699 this.allItems = [];
46700 this.childForms = [];
46701 Roo.apply(this, config);
46703 * The Roo.form.Field items in this form.
46704 * @type MixedCollection
46708 this.items = new Roo.util.MixedCollection(false, function(o){
46709 return o.id || (o.id = Roo.id());
46713 * @event beforeaction
46714 * Fires before any action is performed. Return false to cancel the action.
46715 * @param {Form} this
46716 * @param {Action} action The action to be performed
46718 beforeaction: true,
46720 * @event actionfailed
46721 * Fires when an action fails.
46722 * @param {Form} this
46723 * @param {Action} action The action that failed
46725 actionfailed : true,
46727 * @event actioncomplete
46728 * Fires when an action is completed.
46729 * @param {Form} this
46730 * @param {Action} action The action that completed
46732 actioncomplete : true
46737 Roo.form.BasicForm.superclass.constructor.call(this);
46740 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46742 * @cfg {String} method
46743 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46746 * @cfg {DataReader} reader
46747 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46748 * This is optional as there is built-in support for processing JSON.
46751 * @cfg {DataReader} errorReader
46752 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46753 * This is completely optional as there is built-in support for processing JSON.
46756 * @cfg {String} url
46757 * The URL to use for form actions if one isn't supplied in the action options.
46760 * @cfg {Boolean} fileUpload
46761 * Set to true if this form is a file upload.
46765 * @cfg {Object} baseParams
46766 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46771 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46776 activeAction : null,
46779 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46780 * or setValues() data instead of when the form was first created.
46782 trackResetOnLoad : false,
46786 * childForms - used for multi-tab forms
46789 childForms : false,
46792 * allItems - full list of fields.
46798 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46799 * element by passing it or its id or mask the form itself by passing in true.
46802 waitMsgTarget : false,
46805 initEl : function(el){
46806 this.el = Roo.get(el);
46807 this.id = this.el.id || Roo.id();
46808 this.el.on('submit', this.onSubmit, this);
46809 this.el.addClass('x-form');
46813 onSubmit : function(e){
46818 * Returns true if client-side validation on the form is successful.
46821 isValid : function(){
46823 this.items.each(function(f){
46832 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46835 isDirty : function(){
46837 this.items.each(function(f){
46847 * Returns true if any fields in this form have changed since their original load. (New version)
46851 hasChanged : function()
46854 this.items.each(function(f){
46855 if(f.hasChanged()){
46864 * Resets all hasChanged to 'false' -
46865 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46866 * So hasChanged storage is only to be used for this purpose
46869 resetHasChanged : function()
46871 this.items.each(function(f){
46872 f.resetHasChanged();
46879 * Performs a predefined action (submit or load) or custom actions you define on this form.
46880 * @param {String} actionName The name of the action type
46881 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46882 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46883 * accept other config options):
46885 Property Type Description
46886 ---------------- --------------- ----------------------------------------------------------------------------------
46887 url String The url for the action (defaults to the form's url)
46888 method String The form method to use (defaults to the form's method, or POST if not defined)
46889 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46890 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46891 validate the form on the client (defaults to false)
46893 * @return {BasicForm} this
46895 doAction : function(action, options){
46896 if(typeof action == 'string'){
46897 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46899 if(this.fireEvent('beforeaction', this, action) !== false){
46900 this.beforeAction(action);
46901 action.run.defer(100, action);
46907 * Shortcut to do a submit action.
46908 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46909 * @return {BasicForm} this
46911 submit : function(options){
46912 this.doAction('submit', options);
46917 * Shortcut to do a load action.
46918 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46919 * @return {BasicForm} this
46921 load : function(options){
46922 this.doAction('load', options);
46927 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46928 * @param {Record} record The record to edit
46929 * @return {BasicForm} this
46931 updateRecord : function(record){
46932 record.beginEdit();
46933 var fs = record.fields;
46934 fs.each(function(f){
46935 var field = this.findField(f.name);
46937 record.set(f.name, field.getValue());
46945 * Loads an Roo.data.Record into this form.
46946 * @param {Record} record The record to load
46947 * @return {BasicForm} this
46949 loadRecord : function(record){
46950 this.setValues(record.data);
46955 beforeAction : function(action){
46956 var o = action.options;
46959 if(this.waitMsgTarget === true){
46960 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46961 }else if(this.waitMsgTarget){
46962 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46963 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46965 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46971 afterAction : function(action, success){
46972 this.activeAction = null;
46973 var o = action.options;
46975 if(this.waitMsgTarget === true){
46977 }else if(this.waitMsgTarget){
46978 this.waitMsgTarget.unmask();
46980 Roo.MessageBox.updateProgress(1);
46981 Roo.MessageBox.hide();
46988 Roo.callback(o.success, o.scope, [this, action]);
46989 this.fireEvent('actioncomplete', this, action);
46993 // failure condition..
46994 // we have a scenario where updates need confirming.
46995 // eg. if a locking scenario exists..
46996 // we look for { errors : { needs_confirm : true }} in the response.
46998 (typeof(action.result) != 'undefined') &&
46999 (typeof(action.result.errors) != 'undefined') &&
47000 (typeof(action.result.errors.needs_confirm) != 'undefined')
47003 Roo.MessageBox.confirm(
47004 "Change requires confirmation",
47005 action.result.errorMsg,
47010 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47020 Roo.callback(o.failure, o.scope, [this, action]);
47021 // show an error message if no failed handler is set..
47022 if (!this.hasListener('actionfailed')) {
47023 Roo.MessageBox.alert("Error",
47024 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47025 action.result.errorMsg :
47026 "Saving Failed, please check your entries or try again"
47030 this.fireEvent('actionfailed', this, action);
47036 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47037 * @param {String} id The value to search for
47040 findField : function(id){
47041 var field = this.items.get(id);
47043 this.items.each(function(f){
47044 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47050 return field || null;
47054 * Add a secondary form to this one,
47055 * Used to provide tabbed forms. One form is primary, with hidden values
47056 * which mirror the elements from the other forms.
47058 * @param {Roo.form.Form} form to add.
47061 addForm : function(form)
47064 if (this.childForms.indexOf(form) > -1) {
47068 this.childForms.push(form);
47070 Roo.each(form.allItems, function (fe) {
47072 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47073 if (this.findField(n)) { // already added..
47076 var add = new Roo.form.Hidden({
47079 add.render(this.el);
47086 * Mark fields in this form invalid in bulk.
47087 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47088 * @return {BasicForm} this
47090 markInvalid : function(errors){
47091 if(errors instanceof Array){
47092 for(var i = 0, len = errors.length; i < len; i++){
47093 var fieldError = errors[i];
47094 var f = this.findField(fieldError.id);
47096 f.markInvalid(fieldError.msg);
47102 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47103 field.markInvalid(errors[id]);
47107 Roo.each(this.childForms || [], function (f) {
47108 f.markInvalid(errors);
47115 * Set values for fields in this form in bulk.
47116 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47117 * @return {BasicForm} this
47119 setValues : function(values){
47120 if(values instanceof Array){ // array of objects
47121 for(var i = 0, len = values.length; i < len; i++){
47123 var f = this.findField(v.id);
47125 f.setValue(v.value);
47126 if(this.trackResetOnLoad){
47127 f.originalValue = f.getValue();
47131 }else{ // object hash
47134 if(typeof values[id] != 'function' && (field = this.findField(id))){
47136 if (field.setFromData &&
47137 field.valueField &&
47138 field.displayField &&
47139 // combos' with local stores can
47140 // be queried via setValue()
47141 // to set their value..
47142 (field.store && !field.store.isLocal)
47146 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47147 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47148 field.setFromData(sd);
47151 field.setValue(values[id]);
47155 if(this.trackResetOnLoad){
47156 field.originalValue = field.getValue();
47161 this.resetHasChanged();
47164 Roo.each(this.childForms || [], function (f) {
47165 f.setValues(values);
47166 f.resetHasChanged();
47173 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47174 * they are returned as an array.
47175 * @param {Boolean} asString
47178 getValues : function(asString){
47179 if (this.childForms) {
47180 // copy values from the child forms
47181 Roo.each(this.childForms, function (f) {
47182 this.setValues(f.getValues());
47188 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47189 if(asString === true){
47192 return Roo.urlDecode(fs);
47196 * Returns the fields in this form as an object with key/value pairs.
47197 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47200 getFieldValues : function(with_hidden)
47202 if (this.childForms) {
47203 // copy values from the child forms
47204 // should this call getFieldValues - probably not as we do not currently copy
47205 // hidden fields when we generate..
47206 Roo.each(this.childForms, function (f) {
47207 this.setValues(f.getValues());
47212 this.items.each(function(f){
47213 if (!f.getName()) {
47216 var v = f.getValue();
47217 if (f.inputType =='radio') {
47218 if (typeof(ret[f.getName()]) == 'undefined') {
47219 ret[f.getName()] = ''; // empty..
47222 if (!f.el.dom.checked) {
47226 v = f.el.dom.value;
47230 // not sure if this supported any more..
47231 if ((typeof(v) == 'object') && f.getRawValue) {
47232 v = f.getRawValue() ; // dates..
47234 // combo boxes where name != hiddenName...
47235 if (f.name != f.getName()) {
47236 ret[f.name] = f.getRawValue();
47238 ret[f.getName()] = v;
47245 * Clears all invalid messages in this form.
47246 * @return {BasicForm} this
47248 clearInvalid : function(){
47249 this.items.each(function(f){
47253 Roo.each(this.childForms || [], function (f) {
47262 * Resets this form.
47263 * @return {BasicForm} this
47265 reset : function(){
47266 this.items.each(function(f){
47270 Roo.each(this.childForms || [], function (f) {
47273 this.resetHasChanged();
47279 * Add Roo.form components to this form.
47280 * @param {Field} field1
47281 * @param {Field} field2 (optional)
47282 * @param {Field} etc (optional)
47283 * @return {BasicForm} this
47286 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47292 * Removes a field from the items collection (does NOT remove its markup).
47293 * @param {Field} field
47294 * @return {BasicForm} this
47296 remove : function(field){
47297 this.items.remove(field);
47302 * Looks at the fields in this form, checks them for an id attribute,
47303 * and calls applyTo on the existing dom element with that id.
47304 * @return {BasicForm} this
47306 render : function(){
47307 this.items.each(function(f){
47308 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47316 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47317 * @param {Object} values
47318 * @return {BasicForm} this
47320 applyToFields : function(o){
47321 this.items.each(function(f){
47328 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47329 * @param {Object} values
47330 * @return {BasicForm} this
47332 applyIfToFields : function(o){
47333 this.items.each(function(f){
47341 Roo.BasicForm = Roo.form.BasicForm;/*
47343 * Ext JS Library 1.1.1
47344 * Copyright(c) 2006-2007, Ext JS, LLC.
47346 * Originally Released Under LGPL - original licence link has changed is not relivant.
47349 * <script type="text/javascript">
47353 * @class Roo.form.Form
47354 * @extends Roo.form.BasicForm
47355 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47357 * @param {Object} config Configuration options
47359 Roo.form.Form = function(config){
47361 if (config.items) {
47362 xitems = config.items;
47363 delete config.items;
47367 Roo.form.Form.superclass.constructor.call(this, null, config);
47368 this.url = this.url || this.action;
47370 this.root = new Roo.form.Layout(Roo.applyIf({
47374 this.active = this.root;
47376 * Array of all the buttons that have been added to this form via {@link addButton}
47380 this.allItems = [];
47383 * @event clientvalidation
47384 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47385 * @param {Form} this
47386 * @param {Boolean} valid true if the form has passed client-side validation
47388 clientvalidation: true,
47391 * Fires when the form is rendered
47392 * @param {Roo.form.Form} form
47397 if (this.progressUrl) {
47398 // push a hidden field onto the list of fields..
47402 name : 'UPLOAD_IDENTIFIER'
47407 Roo.each(xitems, this.addxtype, this);
47413 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47415 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47418 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47421 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47423 buttonAlign:'center',
47426 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47431 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47432 * This property cascades to child containers if not set.
47437 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47438 * fires a looping event with that state. This is required to bind buttons to the valid
47439 * state using the config value formBind:true on the button.
47441 monitorValid : false,
47444 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47449 * @cfg {String} progressUrl - Url to return progress data
47452 progressUrl : false,
47454 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
47455 * sending a formdata with extra parameters - eg uploaded elements.
47461 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47462 * fields are added and the column is closed. If no fields are passed the column remains open
47463 * until end() is called.
47464 * @param {Object} config The config to pass to the column
47465 * @param {Field} field1 (optional)
47466 * @param {Field} field2 (optional)
47467 * @param {Field} etc (optional)
47468 * @return Column The column container object
47470 column : function(c){
47471 var col = new Roo.form.Column(c);
47473 if(arguments.length > 1){ // duplicate code required because of Opera
47474 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47481 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47482 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47483 * until end() is called.
47484 * @param {Object} config The config to pass to the fieldset
47485 * @param {Field} field1 (optional)
47486 * @param {Field} field2 (optional)
47487 * @param {Field} etc (optional)
47488 * @return FieldSet The fieldset container object
47490 fieldset : function(c){
47491 var fs = new Roo.form.FieldSet(c);
47493 if(arguments.length > 1){ // duplicate code required because of Opera
47494 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47501 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47502 * fields are added and the container is closed. If no fields are passed the container remains open
47503 * until end() is called.
47504 * @param {Object} config The config to pass to the Layout
47505 * @param {Field} field1 (optional)
47506 * @param {Field} field2 (optional)
47507 * @param {Field} etc (optional)
47508 * @return Layout The container object
47510 container : function(c){
47511 var l = new Roo.form.Layout(c);
47513 if(arguments.length > 1){ // duplicate code required because of Opera
47514 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47521 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47522 * @param {Object} container A Roo.form.Layout or subclass of Layout
47523 * @return {Form} this
47525 start : function(c){
47526 // cascade label info
47527 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47528 this.active.stack.push(c);
47529 c.ownerCt = this.active;
47535 * Closes the current open container
47536 * @return {Form} this
47539 if(this.active == this.root){
47542 this.active = this.active.ownerCt;
47547 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47548 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47549 * as the label of the field.
47550 * @param {Field} field1
47551 * @param {Field} field2 (optional)
47552 * @param {Field} etc. (optional)
47553 * @return {Form} this
47556 this.active.stack.push.apply(this.active.stack, arguments);
47557 this.allItems.push.apply(this.allItems,arguments);
47559 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47560 if(a[i].isFormField){
47565 Roo.form.Form.superclass.add.apply(this, r);
47575 * Find any element that has been added to a form, using it's ID or name
47576 * This can include framesets, columns etc. along with regular fields..
47577 * @param {String} id - id or name to find.
47579 * @return {Element} e - or false if nothing found.
47581 findbyId : function(id)
47587 Roo.each(this.allItems, function(f){
47588 if (f.id == id || f.name == id ){
47599 * Render this form into the passed container. This should only be called once!
47600 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47601 * @return {Form} this
47603 render : function(ct)
47609 var o = this.autoCreate || {
47611 method : this.method || 'POST',
47612 id : this.id || Roo.id()
47614 this.initEl(ct.createChild(o));
47616 this.root.render(this.el);
47620 this.items.each(function(f){
47621 f.render('x-form-el-'+f.id);
47624 if(this.buttons.length > 0){
47625 // tables are required to maintain order and for correct IE layout
47626 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47627 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47628 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47630 var tr = tb.getElementsByTagName('tr')[0];
47631 for(var i = 0, len = this.buttons.length; i < len; i++) {
47632 var b = this.buttons[i];
47633 var td = document.createElement('td');
47634 td.className = 'x-form-btn-td';
47635 b.render(tr.appendChild(td));
47638 if(this.monitorValid){ // initialize after render
47639 this.startMonitoring();
47641 this.fireEvent('rendered', this);
47646 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47647 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47648 * object or a valid Roo.DomHelper element config
47649 * @param {Function} handler The function called when the button is clicked
47650 * @param {Object} scope (optional) The scope of the handler function
47651 * @return {Roo.Button}
47653 addButton : function(config, handler, scope){
47657 minWidth: this.minButtonWidth,
47660 if(typeof config == "string"){
47663 Roo.apply(bc, config);
47665 var btn = new Roo.Button(null, bc);
47666 this.buttons.push(btn);
47671 * Adds a series of form elements (using the xtype property as the factory method.
47672 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47673 * @param {Object} config
47676 addxtype : function()
47678 var ar = Array.prototype.slice.call(arguments, 0);
47680 for(var i = 0; i < ar.length; i++) {
47682 continue; // skip -- if this happends something invalid got sent, we
47683 // should ignore it, as basically that interface element will not show up
47684 // and that should be pretty obvious!!
47687 if (Roo.form[ar[i].xtype]) {
47689 var fe = Roo.factory(ar[i], Roo.form);
47695 fe.store.form = this;
47700 this.allItems.push(fe);
47701 if (fe.items && fe.addxtype) {
47702 fe.addxtype.apply(fe, fe.items);
47712 // console.log('adding ' + ar[i].xtype);
47714 if (ar[i].xtype == 'Button') {
47715 //console.log('adding button');
47716 //console.log(ar[i]);
47717 this.addButton(ar[i]);
47718 this.allItems.push(fe);
47722 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47723 alert('end is not supported on xtype any more, use items');
47725 // //console.log('adding end');
47733 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47734 * option "monitorValid"
47736 startMonitoring : function(){
47739 Roo.TaskMgr.start({
47740 run : this.bindHandler,
47741 interval : this.monitorPoll || 200,
47748 * Stops monitoring of the valid state of this form
47750 stopMonitoring : function(){
47751 this.bound = false;
47755 bindHandler : function(){
47757 return false; // stops binding
47760 this.items.each(function(f){
47761 if(!f.isValid(true)){
47766 for(var i = 0, len = this.buttons.length; i < len; i++){
47767 var btn = this.buttons[i];
47768 if(btn.formBind === true && btn.disabled === valid){
47769 btn.setDisabled(!valid);
47772 this.fireEvent('clientvalidation', this, valid);
47786 Roo.Form = Roo.form.Form;
47789 * Ext JS Library 1.1.1
47790 * Copyright(c) 2006-2007, Ext JS, LLC.
47792 * Originally Released Under LGPL - original licence link has changed is not relivant.
47795 * <script type="text/javascript">
47798 // as we use this in bootstrap.
47799 Roo.namespace('Roo.form');
47801 * @class Roo.form.Action
47802 * Internal Class used to handle form actions
47804 * @param {Roo.form.BasicForm} el The form element or its id
47805 * @param {Object} config Configuration options
47810 // define the action interface
47811 Roo.form.Action = function(form, options){
47813 this.options = options || {};
47816 * Client Validation Failed
47819 Roo.form.Action.CLIENT_INVALID = 'client';
47821 * Server Validation Failed
47824 Roo.form.Action.SERVER_INVALID = 'server';
47826 * Connect to Server Failed
47829 Roo.form.Action.CONNECT_FAILURE = 'connect';
47831 * Reading Data from Server Failed
47834 Roo.form.Action.LOAD_FAILURE = 'load';
47836 Roo.form.Action.prototype = {
47838 failureType : undefined,
47839 response : undefined,
47840 result : undefined,
47842 // interface method
47843 run : function(options){
47847 // interface method
47848 success : function(response){
47852 // interface method
47853 handleResponse : function(response){
47857 // default connection failure
47858 failure : function(response){
47860 this.response = response;
47861 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47862 this.form.afterAction(this, false);
47865 processResponse : function(response){
47866 this.response = response;
47867 if(!response.responseText){
47870 this.result = this.handleResponse(response);
47871 return this.result;
47874 // utility functions used internally
47875 getUrl : function(appendParams){
47876 var url = this.options.url || this.form.url || this.form.el.dom.action;
47878 var p = this.getParams();
47880 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47886 getMethod : function(){
47887 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47890 getParams : function(){
47891 var bp = this.form.baseParams;
47892 var p = this.options.params;
47894 if(typeof p == "object"){
47895 p = Roo.urlEncode(Roo.applyIf(p, bp));
47896 }else if(typeof p == 'string' && bp){
47897 p += '&' + Roo.urlEncode(bp);
47900 p = Roo.urlEncode(bp);
47905 createCallback : function(){
47907 success: this.success,
47908 failure: this.failure,
47910 timeout: (this.form.timeout*1000),
47911 upload: this.form.fileUpload ? this.success : undefined
47916 Roo.form.Action.Submit = function(form, options){
47917 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47920 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47923 haveProgress : false,
47924 uploadComplete : false,
47926 // uploadProgress indicator.
47927 uploadProgress : function()
47929 if (!this.form.progressUrl) {
47933 if (!this.haveProgress) {
47934 Roo.MessageBox.progress("Uploading", "Uploading");
47936 if (this.uploadComplete) {
47937 Roo.MessageBox.hide();
47941 this.haveProgress = true;
47943 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47945 var c = new Roo.data.Connection();
47947 url : this.form.progressUrl,
47952 success : function(req){
47953 //console.log(data);
47957 rdata = Roo.decode(req.responseText)
47959 Roo.log("Invalid data from server..");
47963 if (!rdata || !rdata.success) {
47965 Roo.MessageBox.alert(Roo.encode(rdata));
47968 var data = rdata.data;
47970 if (this.uploadComplete) {
47971 Roo.MessageBox.hide();
47976 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47977 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47980 this.uploadProgress.defer(2000,this);
47983 failure: function(data) {
47984 Roo.log('progress url failed ');
47995 // run get Values on the form, so it syncs any secondary forms.
47996 this.form.getValues();
47998 var o = this.options;
47999 var method = this.getMethod();
48000 var isPost = method == 'POST';
48001 if(o.clientValidation === false || this.form.isValid()){
48003 if (this.form.progressUrl) {
48004 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48005 (new Date() * 1) + '' + Math.random());
48010 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48011 form:this.form.el.dom,
48012 url:this.getUrl(!isPost),
48014 params:isPost ? this.getParams() : null,
48015 isUpload: this.form.fileUpload,
48016 formData : this.form.formData
48019 this.uploadProgress();
48021 }else if (o.clientValidation !== false){ // client validation failed
48022 this.failureType = Roo.form.Action.CLIENT_INVALID;
48023 this.form.afterAction(this, false);
48027 success : function(response)
48029 this.uploadComplete= true;
48030 if (this.haveProgress) {
48031 Roo.MessageBox.hide();
48035 var result = this.processResponse(response);
48036 if(result === true || result.success){
48037 this.form.afterAction(this, true);
48041 this.form.markInvalid(result.errors);
48042 this.failureType = Roo.form.Action.SERVER_INVALID;
48044 this.form.afterAction(this, false);
48046 failure : function(response)
48048 this.uploadComplete= true;
48049 if (this.haveProgress) {
48050 Roo.MessageBox.hide();
48053 this.response = response;
48054 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48055 this.form.afterAction(this, false);
48058 handleResponse : function(response){
48059 if(this.form.errorReader){
48060 var rs = this.form.errorReader.read(response);
48063 for(var i = 0, len = rs.records.length; i < len; i++) {
48064 var r = rs.records[i];
48065 errors[i] = r.data;
48068 if(errors.length < 1){
48072 success : rs.success,
48078 ret = Roo.decode(response.responseText);
48082 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
48092 Roo.form.Action.Load = function(form, options){
48093 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
48094 this.reader = this.form.reader;
48097 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
48102 Roo.Ajax.request(Roo.apply(
48103 this.createCallback(), {
48104 method:this.getMethod(),
48105 url:this.getUrl(false),
48106 params:this.getParams()
48110 success : function(response){
48112 var result = this.processResponse(response);
48113 if(result === true || !result.success || !result.data){
48114 this.failureType = Roo.form.Action.LOAD_FAILURE;
48115 this.form.afterAction(this, false);
48118 this.form.clearInvalid();
48119 this.form.setValues(result.data);
48120 this.form.afterAction(this, true);
48123 handleResponse : function(response){
48124 if(this.form.reader){
48125 var rs = this.form.reader.read(response);
48126 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
48128 success : rs.success,
48132 return Roo.decode(response.responseText);
48136 Roo.form.Action.ACTION_TYPES = {
48137 'load' : Roo.form.Action.Load,
48138 'submit' : Roo.form.Action.Submit
48141 * Ext JS Library 1.1.1
48142 * Copyright(c) 2006-2007, Ext JS, LLC.
48144 * Originally Released Under LGPL - original licence link has changed is not relivant.
48147 * <script type="text/javascript">
48151 * @class Roo.form.Layout
48152 * @extends Roo.Component
48153 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48155 * @param {Object} config Configuration options
48157 Roo.form.Layout = function(config){
48159 if (config.items) {
48160 xitems = config.items;
48161 delete config.items;
48163 Roo.form.Layout.superclass.constructor.call(this, config);
48165 Roo.each(xitems, this.addxtype, this);
48169 Roo.extend(Roo.form.Layout, Roo.Component, {
48171 * @cfg {String/Object} autoCreate
48172 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48175 * @cfg {String/Object/Function} style
48176 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48177 * a function which returns such a specification.
48180 * @cfg {String} labelAlign
48181 * Valid values are "left," "top" and "right" (defaults to "left")
48184 * @cfg {Number} labelWidth
48185 * Fixed width in pixels of all field labels (defaults to undefined)
48188 * @cfg {Boolean} clear
48189 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48193 * @cfg {String} labelSeparator
48194 * The separator to use after field labels (defaults to ':')
48196 labelSeparator : ':',
48198 * @cfg {Boolean} hideLabels
48199 * True to suppress the display of field labels in this layout (defaults to false)
48201 hideLabels : false,
48204 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48209 onRender : function(ct, position){
48210 if(this.el){ // from markup
48211 this.el = Roo.get(this.el);
48212 }else { // generate
48213 var cfg = this.getAutoCreate();
48214 this.el = ct.createChild(cfg, position);
48217 this.el.applyStyles(this.style);
48219 if(this.labelAlign){
48220 this.el.addClass('x-form-label-'+this.labelAlign);
48222 if(this.hideLabels){
48223 this.labelStyle = "display:none";
48224 this.elementStyle = "padding-left:0;";
48226 if(typeof this.labelWidth == 'number'){
48227 this.labelStyle = "width:"+this.labelWidth+"px;";
48228 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48230 if(this.labelAlign == 'top'){
48231 this.labelStyle = "width:auto;";
48232 this.elementStyle = "padding-left:0;";
48235 var stack = this.stack;
48236 var slen = stack.length;
48238 if(!this.fieldTpl){
48239 var t = new Roo.Template(
48240 '<div class="x-form-item {5}">',
48241 '<label for="{0}" style="{2}">{1}{4}</label>',
48242 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48244 '</div><div class="x-form-clear-left"></div>'
48246 t.disableFormats = true;
48248 Roo.form.Layout.prototype.fieldTpl = t;
48250 for(var i = 0; i < slen; i++) {
48251 if(stack[i].isFormField){
48252 this.renderField(stack[i]);
48254 this.renderComponent(stack[i]);
48259 this.el.createChild({cls:'x-form-clear'});
48264 renderField : function(f){
48265 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48268 f.labelStyle||this.labelStyle||'', //2
48269 this.elementStyle||'', //3
48270 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48271 f.itemCls||this.itemCls||'' //5
48272 ], true).getPrevSibling());
48276 renderComponent : function(c){
48277 c.render(c.isLayout ? this.el : this.el.createChild());
48280 * Adds a object form elements (using the xtype property as the factory method.)
48281 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48282 * @param {Object} config
48284 addxtype : function(o)
48286 // create the lement.
48287 o.form = this.form;
48288 var fe = Roo.factory(o, Roo.form);
48289 this.form.allItems.push(fe);
48290 this.stack.push(fe);
48292 if (fe.isFormField) {
48293 this.form.items.add(fe);
48301 * @class Roo.form.Column
48302 * @extends Roo.form.Layout
48303 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48305 * @param {Object} config Configuration options
48307 Roo.form.Column = function(config){
48308 Roo.form.Column.superclass.constructor.call(this, config);
48311 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48313 * @cfg {Number/String} width
48314 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48317 * @cfg {String/Object} autoCreate
48318 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48322 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48325 onRender : function(ct, position){
48326 Roo.form.Column.superclass.onRender.call(this, ct, position);
48328 this.el.setWidth(this.width);
48335 * @class Roo.form.Row
48336 * @extends Roo.form.Layout
48337 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48339 * @param {Object} config Configuration options
48343 Roo.form.Row = function(config){
48344 Roo.form.Row.superclass.constructor.call(this, config);
48347 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48349 * @cfg {Number/String} width
48350 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48353 * @cfg {Number/String} height
48354 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48356 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48360 onRender : function(ct, position){
48361 //console.log('row render');
48363 var t = new Roo.Template(
48364 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48365 '<label for="{0}" style="{2}">{1}{4}</label>',
48366 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48370 t.disableFormats = true;
48372 Roo.form.Layout.prototype.rowTpl = t;
48374 this.fieldTpl = this.rowTpl;
48376 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48377 var labelWidth = 100;
48379 if ((this.labelAlign != 'top')) {
48380 if (typeof this.labelWidth == 'number') {
48381 labelWidth = this.labelWidth
48383 this.padWidth = 20 + labelWidth;
48387 Roo.form.Column.superclass.onRender.call(this, ct, position);
48389 this.el.setWidth(this.width);
48392 this.el.setHeight(this.height);
48397 renderField : function(f){
48398 f.fieldEl = this.fieldTpl.append(this.el, [
48399 f.id, f.fieldLabel,
48400 f.labelStyle||this.labelStyle||'',
48401 this.elementStyle||'',
48402 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48403 f.itemCls||this.itemCls||'',
48404 f.width ? f.width + this.padWidth : 160 + this.padWidth
48411 * @class Roo.form.FieldSet
48412 * @extends Roo.form.Layout
48413 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48415 * @param {Object} config Configuration options
48417 Roo.form.FieldSet = function(config){
48418 Roo.form.FieldSet.superclass.constructor.call(this, config);
48421 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48423 * @cfg {String} legend
48424 * The text to display as the legend for the FieldSet (defaults to '')
48427 * @cfg {String/Object} autoCreate
48428 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48432 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48435 onRender : function(ct, position){
48436 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48438 this.setLegend(this.legend);
48443 setLegend : function(text){
48445 this.el.child('legend').update(text);
48450 * Ext JS Library 1.1.1
48451 * Copyright(c) 2006-2007, Ext JS, LLC.
48453 * Originally Released Under LGPL - original licence link has changed is not relivant.
48456 * <script type="text/javascript">
48459 * @class Roo.form.VTypes
48460 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48463 Roo.form.VTypes = function(){
48464 // closure these in so they are only created once.
48465 var alpha = /^[a-zA-Z_]+$/;
48466 var alphanum = /^[a-zA-Z0-9_]+$/;
48467 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48468 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48470 // All these messages and functions are configurable
48473 * The function used to validate email addresses
48474 * @param {String} value The email address
48476 'email' : function(v){
48477 return email.test(v);
48480 * The error text to display when the email validation function returns false
48483 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48485 * The keystroke filter mask to be applied on email input
48488 'emailMask' : /[a-z0-9_\.\-@]/i,
48491 * The function used to validate URLs
48492 * @param {String} value The URL
48494 'url' : function(v){
48495 return url.test(v);
48498 * The error text to display when the url validation function returns false
48501 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48504 * The function used to validate alpha values
48505 * @param {String} value The value
48507 'alpha' : function(v){
48508 return alpha.test(v);
48511 * The error text to display when the alpha validation function returns false
48514 'alphaText' : 'This field should only contain letters and _',
48516 * The keystroke filter mask to be applied on alpha input
48519 'alphaMask' : /[a-z_]/i,
48522 * The function used to validate alphanumeric values
48523 * @param {String} value The value
48525 'alphanum' : function(v){
48526 return alphanum.test(v);
48529 * The error text to display when the alphanumeric validation function returns false
48532 'alphanumText' : 'This field should only contain letters, numbers and _',
48534 * The keystroke filter mask to be applied on alphanumeric input
48537 'alphanumMask' : /[a-z0-9_]/i
48539 }();//<script type="text/javascript">
48542 * @class Roo.form.FCKeditor
48543 * @extends Roo.form.TextArea
48544 * Wrapper around the FCKEditor http://www.fckeditor.net
48546 * Creates a new FCKeditor
48547 * @param {Object} config Configuration options
48549 Roo.form.FCKeditor = function(config){
48550 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48553 * @event editorinit
48554 * Fired when the editor is initialized - you can add extra handlers here..
48555 * @param {FCKeditor} this
48556 * @param {Object} the FCK object.
48563 Roo.form.FCKeditor.editors = { };
48564 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48566 //defaultAutoCreate : {
48567 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48571 * @cfg {Object} fck options - see fck manual for details.
48576 * @cfg {Object} fck toolbar set (Basic or Default)
48578 toolbarSet : 'Basic',
48580 * @cfg {Object} fck BasePath
48582 basePath : '/fckeditor/',
48590 onRender : function(ct, position)
48593 this.defaultAutoCreate = {
48595 style:"width:300px;height:60px;",
48596 autocomplete: "new-password"
48599 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48602 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48603 if(this.preventScrollbars){
48604 this.el.setStyle("overflow", "hidden");
48606 this.el.setHeight(this.growMin);
48609 //console.log('onrender' + this.getId() );
48610 Roo.form.FCKeditor.editors[this.getId()] = this;
48613 this.replaceTextarea() ;
48617 getEditor : function() {
48618 return this.fckEditor;
48621 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48622 * @param {Mixed} value The value to set
48626 setValue : function(value)
48628 //console.log('setValue: ' + value);
48630 if(typeof(value) == 'undefined') { // not sure why this is happending...
48633 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48635 //if(!this.el || !this.getEditor()) {
48636 // this.value = value;
48637 //this.setValue.defer(100,this,[value]);
48641 if(!this.getEditor()) {
48645 this.getEditor().SetData(value);
48652 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48653 * @return {Mixed} value The field value
48655 getValue : function()
48658 if (this.frame && this.frame.dom.style.display == 'none') {
48659 return Roo.form.FCKeditor.superclass.getValue.call(this);
48662 if(!this.el || !this.getEditor()) {
48664 // this.getValue.defer(100,this);
48669 var value=this.getEditor().GetData();
48670 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48671 return Roo.form.FCKeditor.superclass.getValue.call(this);
48677 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48678 * @return {Mixed} value The field value
48680 getRawValue : function()
48682 if (this.frame && this.frame.dom.style.display == 'none') {
48683 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48686 if(!this.el || !this.getEditor()) {
48687 //this.getRawValue.defer(100,this);
48694 var value=this.getEditor().GetData();
48695 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48696 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48700 setSize : function(w,h) {
48704 //if (this.frame && this.frame.dom.style.display == 'none') {
48705 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48708 //if(!this.el || !this.getEditor()) {
48709 // this.setSize.defer(100,this, [w,h]);
48715 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48717 this.frame.dom.setAttribute('width', w);
48718 this.frame.dom.setAttribute('height', h);
48719 this.frame.setSize(w,h);
48723 toggleSourceEdit : function(value) {
48727 this.el.dom.style.display = value ? '' : 'none';
48728 this.frame.dom.style.display = value ? 'none' : '';
48733 focus: function(tag)
48735 if (this.frame.dom.style.display == 'none') {
48736 return Roo.form.FCKeditor.superclass.focus.call(this);
48738 if(!this.el || !this.getEditor()) {
48739 this.focus.defer(100,this, [tag]);
48746 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48747 this.getEditor().Focus();
48749 if (!this.getEditor().Selection.GetSelection()) {
48750 this.focus.defer(100,this, [tag]);
48755 var r = this.getEditor().EditorDocument.createRange();
48756 r.setStart(tgs[0],0);
48757 r.setEnd(tgs[0],0);
48758 this.getEditor().Selection.GetSelection().removeAllRanges();
48759 this.getEditor().Selection.GetSelection().addRange(r);
48760 this.getEditor().Focus();
48767 replaceTextarea : function()
48769 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48772 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48774 // We must check the elements firstly using the Id and then the name.
48775 var oTextarea = document.getElementById( this.getId() );
48777 var colElementsByName = document.getElementsByName( this.getId() ) ;
48779 oTextarea.style.display = 'none' ;
48781 if ( oTextarea.tabIndex ) {
48782 this.TabIndex = oTextarea.tabIndex ;
48785 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48786 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48787 this.frame = Roo.get(this.getId() + '___Frame')
48790 _getConfigHtml : function()
48794 for ( var o in this.fckconfig ) {
48795 sConfig += sConfig.length > 0 ? '&' : '';
48796 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48799 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48803 _getIFrameHtml : function()
48805 var sFile = 'fckeditor.html' ;
48806 /* no idea what this is about..
48809 if ( (/fcksource=true/i).test( window.top.location.search ) )
48810 sFile = 'fckeditor.original.html' ;
48815 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48816 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48819 var html = '<iframe id="' + this.getId() +
48820 '___Frame" src="' + sLink +
48821 '" width="' + this.width +
48822 '" height="' + this.height + '"' +
48823 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48824 ' frameborder="0" scrolling="no"></iframe>' ;
48829 _insertHtmlBefore : function( html, element )
48831 if ( element.insertAdjacentHTML ) {
48833 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48835 var oRange = document.createRange() ;
48836 oRange.setStartBefore( element ) ;
48837 var oFragment = oRange.createContextualFragment( html );
48838 element.parentNode.insertBefore( oFragment, element ) ;
48851 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48853 function FCKeditor_OnComplete(editorInstance){
48854 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48855 f.fckEditor = editorInstance;
48856 //console.log("loaded");
48857 f.fireEvent('editorinit', f, editorInstance);
48877 //<script type="text/javascript">
48879 * @class Roo.form.GridField
48880 * @extends Roo.form.Field
48881 * Embed a grid (or editable grid into a form)
48884 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48886 * xgrid.store = Roo.data.Store
48887 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48888 * xgrid.store.reader = Roo.data.JsonReader
48892 * Creates a new GridField
48893 * @param {Object} config Configuration options
48895 Roo.form.GridField = function(config){
48896 Roo.form.GridField.superclass.constructor.call(this, config);
48900 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48902 * @cfg {Number} width - used to restrict width of grid..
48906 * @cfg {Number} height - used to restrict height of grid..
48910 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48916 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48917 * {tag: "input", type: "checkbox", autocomplete: "off"})
48919 // defaultAutoCreate : { tag: 'div' },
48920 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48922 * @cfg {String} addTitle Text to include for adding a title.
48926 onResize : function(){
48927 Roo.form.Field.superclass.onResize.apply(this, arguments);
48930 initEvents : function(){
48931 // Roo.form.Checkbox.superclass.initEvents.call(this);
48932 // has no events...
48937 getResizeEl : function(){
48941 getPositionEl : function(){
48946 onRender : function(ct, position){
48948 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48949 var style = this.style;
48952 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48953 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48954 this.viewEl = this.wrap.createChild({ tag: 'div' });
48956 this.viewEl.applyStyles(style);
48959 this.viewEl.setWidth(this.width);
48962 this.viewEl.setHeight(this.height);
48964 //if(this.inputValue !== undefined){
48965 //this.setValue(this.value);
48968 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48971 this.grid.render();
48972 this.grid.getDataSource().on('remove', this.refreshValue, this);
48973 this.grid.getDataSource().on('update', this.refreshValue, this);
48974 this.grid.on('afteredit', this.refreshValue, this);
48980 * Sets the value of the item.
48981 * @param {String} either an object or a string..
48983 setValue : function(v){
48985 v = v || []; // empty set..
48986 // this does not seem smart - it really only affects memoryproxy grids..
48987 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48988 var ds = this.grid.getDataSource();
48989 // assumes a json reader..
48991 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48992 ds.loadData( data);
48994 // clear selection so it does not get stale.
48995 if (this.grid.sm) {
48996 this.grid.sm.clearSelections();
48999 Roo.form.GridField.superclass.setValue.call(this, v);
49000 this.refreshValue();
49001 // should load data in the grid really....
49005 refreshValue: function() {
49007 this.grid.getDataSource().each(function(r) {
49010 this.el.dom.value = Roo.encode(val);
49018 * Ext JS Library 1.1.1
49019 * Copyright(c) 2006-2007, Ext JS, LLC.
49021 * Originally Released Under LGPL - original licence link has changed is not relivant.
49024 * <script type="text/javascript">
49027 * @class Roo.form.DisplayField
49028 * @extends Roo.form.Field
49029 * A generic Field to display non-editable data.
49030 * @cfg {Boolean} closable (true|false) default false
49032 * Creates a new Display Field item.
49033 * @param {Object} config Configuration options
49035 Roo.form.DisplayField = function(config){
49036 Roo.form.DisplayField.superclass.constructor.call(this, config);
49041 * Fires after the click the close btn
49042 * @param {Roo.form.DisplayField} this
49048 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
49049 inputType: 'hidden',
49055 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49057 focusClass : undefined,
49059 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49061 fieldClass: 'x-form-field',
49064 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
49066 valueRenderer: undefined,
49070 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49071 * {tag: "input", type: "checkbox", autocomplete: "off"})
49074 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
49078 onResize : function(){
49079 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
49083 initEvents : function(){
49084 // Roo.form.Checkbox.superclass.initEvents.call(this);
49085 // has no events...
49088 this.closeEl.on('click', this.onClose, this);
49094 getResizeEl : function(){
49098 getPositionEl : function(){
49103 onRender : function(ct, position){
49105 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
49106 //if(this.inputValue !== undefined){
49107 this.wrap = this.el.wrap();
49109 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
49112 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
49115 if (this.bodyStyle) {
49116 this.viewEl.applyStyles(this.bodyStyle);
49118 //this.viewEl.setStyle('padding', '2px');
49120 this.setValue(this.value);
49125 initValue : Roo.emptyFn,
49130 onClick : function(){
49135 * Sets the checked state of the checkbox.
49136 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49138 setValue : function(v){
49140 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49141 // this might be called before we have a dom element..
49142 if (!this.viewEl) {
49145 this.viewEl.dom.innerHTML = html;
49146 Roo.form.DisplayField.superclass.setValue.call(this, v);
49150 onClose : function(e)
49152 e.preventDefault();
49154 this.fireEvent('close', this);
49163 * @class Roo.form.DayPicker
49164 * @extends Roo.form.Field
49165 * A Day picker show [M] [T] [W] ....
49167 * Creates a new Day Picker
49168 * @param {Object} config Configuration options
49170 Roo.form.DayPicker= function(config){
49171 Roo.form.DayPicker.superclass.constructor.call(this, config);
49175 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49177 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49179 focusClass : undefined,
49181 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49183 fieldClass: "x-form-field",
49186 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49187 * {tag: "input", type: "checkbox", autocomplete: "off"})
49189 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49192 actionMode : 'viewEl',
49196 inputType : 'hidden',
49199 inputElement: false, // real input element?
49200 basedOn: false, // ????
49202 isFormField: true, // not sure where this is needed!!!!
49204 onResize : function(){
49205 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49206 if(!this.boxLabel){
49207 this.el.alignTo(this.wrap, 'c-c');
49211 initEvents : function(){
49212 Roo.form.Checkbox.superclass.initEvents.call(this);
49213 this.el.on("click", this.onClick, this);
49214 this.el.on("change", this.onClick, this);
49218 getResizeEl : function(){
49222 getPositionEl : function(){
49228 onRender : function(ct, position){
49229 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49231 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49233 var r1 = '<table><tr>';
49234 var r2 = '<tr class="x-form-daypick-icons">';
49235 for (var i=0; i < 7; i++) {
49236 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49237 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49240 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49241 viewEl.select('img').on('click', this.onClick, this);
49242 this.viewEl = viewEl;
49245 // this will not work on Chrome!!!
49246 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49247 this.el.on('propertychange', this.setFromHidden, this); //ie
49255 initValue : Roo.emptyFn,
49258 * Returns the checked state of the checkbox.
49259 * @return {Boolean} True if checked, else false
49261 getValue : function(){
49262 return this.el.dom.value;
49267 onClick : function(e){
49268 //this.setChecked(!this.checked);
49269 Roo.get(e.target).toggleClass('x-menu-item-checked');
49270 this.refreshValue();
49271 //if(this.el.dom.checked != this.checked){
49272 // this.setValue(this.el.dom.checked);
49277 refreshValue : function()
49280 this.viewEl.select('img',true).each(function(e,i,n) {
49281 val += e.is(".x-menu-item-checked") ? String(n) : '';
49283 this.setValue(val, true);
49287 * Sets the checked state of the checkbox.
49288 * On is always based on a string comparison between inputValue and the param.
49289 * @param {Boolean/String} value - the value to set
49290 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49292 setValue : function(v,suppressEvent){
49293 if (!this.el.dom) {
49296 var old = this.el.dom.value ;
49297 this.el.dom.value = v;
49298 if (suppressEvent) {
49302 // update display..
49303 this.viewEl.select('img',true).each(function(e,i,n) {
49305 var on = e.is(".x-menu-item-checked");
49306 var newv = v.indexOf(String(n)) > -1;
49308 e.toggleClass('x-menu-item-checked');
49314 this.fireEvent('change', this, v, old);
49319 // handle setting of hidden value by some other method!!?!?
49320 setFromHidden: function()
49325 //console.log("SET FROM HIDDEN");
49326 //alert('setFrom hidden');
49327 this.setValue(this.el.dom.value);
49330 onDestroy : function()
49333 Roo.get(this.viewEl).remove();
49336 Roo.form.DayPicker.superclass.onDestroy.call(this);
49340 * RooJS Library 1.1.1
49341 * Copyright(c) 2008-2011 Alan Knowles
49348 * @class Roo.form.ComboCheck
49349 * @extends Roo.form.ComboBox
49350 * A combobox for multiple select items.
49352 * FIXME - could do with a reset button..
49355 * Create a new ComboCheck
49356 * @param {Object} config Configuration options
49358 Roo.form.ComboCheck = function(config){
49359 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49360 // should verify some data...
49362 // hiddenName = required..
49363 // displayField = required
49364 // valudField == required
49365 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49367 Roo.each(req, function(e) {
49368 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49369 throw "Roo.form.ComboCheck : missing value for: " + e;
49376 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49381 selectedClass: 'x-menu-item-checked',
49384 onRender : function(ct, position){
49390 var cls = 'x-combo-list';
49393 this.tpl = new Roo.Template({
49394 html : '<div class="'+cls+'-item x-menu-check-item">' +
49395 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49396 '<span>{' + this.displayField + '}</span>' +
49403 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49404 this.view.singleSelect = false;
49405 this.view.multiSelect = true;
49406 this.view.toggleSelect = true;
49407 this.pageTb.add(new Roo.Toolbar.Fill(), {
49410 handler: function()
49417 onViewOver : function(e, t){
49423 onViewClick : function(doFocus,index){
49427 select: function () {
49428 //Roo.log("SELECT CALLED");
49431 selectByValue : function(xv, scrollIntoView){
49432 var ar = this.getValueArray();
49435 Roo.each(ar, function(v) {
49436 if(v === undefined || v === null){
49439 var r = this.findRecord(this.valueField, v);
49441 sels.push(this.store.indexOf(r))
49445 this.view.select(sels);
49451 onSelect : function(record, index){
49452 // Roo.log("onselect Called");
49453 // this is only called by the clear button now..
49454 this.view.clearSelections();
49455 this.setValue('[]');
49456 if (this.value != this.valueBefore) {
49457 this.fireEvent('change', this, this.value, this.valueBefore);
49458 this.valueBefore = this.value;
49461 getValueArray : function()
49466 //Roo.log(this.value);
49467 if (typeof(this.value) == 'undefined') {
49470 var ar = Roo.decode(this.value);
49471 return ar instanceof Array ? ar : []; //?? valid?
49474 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49479 expand : function ()
49482 Roo.form.ComboCheck.superclass.expand.call(this);
49483 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49484 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49489 collapse : function(){
49490 Roo.form.ComboCheck.superclass.collapse.call(this);
49491 var sl = this.view.getSelectedIndexes();
49492 var st = this.store;
49496 Roo.each(sl, function(i) {
49498 nv.push(r.get(this.valueField));
49500 this.setValue(Roo.encode(nv));
49501 if (this.value != this.valueBefore) {
49503 this.fireEvent('change', this, this.value, this.valueBefore);
49504 this.valueBefore = this.value;
49509 setValue : function(v){
49513 var vals = this.getValueArray();
49515 Roo.each(vals, function(k) {
49516 var r = this.findRecord(this.valueField, k);
49518 tv.push(r.data[this.displayField]);
49519 }else if(this.valueNotFoundText !== undefined){
49520 tv.push( this.valueNotFoundText );
49525 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49526 this.hiddenField.value = v;
49532 * Ext JS Library 1.1.1
49533 * Copyright(c) 2006-2007, Ext JS, LLC.
49535 * Originally Released Under LGPL - original licence link has changed is not relivant.
49538 * <script type="text/javascript">
49542 * @class Roo.form.Signature
49543 * @extends Roo.form.Field
49547 * @param {Object} config Configuration options
49550 Roo.form.Signature = function(config){
49551 Roo.form.Signature.superclass.constructor.call(this, config);
49553 this.addEvents({// not in used??
49556 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49557 * @param {Roo.form.Signature} combo This combo box
49562 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49563 * @param {Roo.form.ComboBox} combo This combo box
49564 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49570 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49572 * @cfg {Object} labels Label to use when rendering a form.
49576 * confirm : "Confirm"
49581 confirm : "Confirm"
49584 * @cfg {Number} width The signature panel width (defaults to 300)
49588 * @cfg {Number} height The signature panel height (defaults to 100)
49592 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49594 allowBlank : false,
49597 // {Object} signPanel The signature SVG panel element (defaults to {})
49599 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49600 isMouseDown : false,
49601 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49602 isConfirmed : false,
49603 // {String} signatureTmp SVG mapping string (defaults to empty string)
49607 defaultAutoCreate : { // modified by initCompnoent..
49613 onRender : function(ct, position){
49615 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49617 this.wrap = this.el.wrap({
49618 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49621 this.createToolbar(this);
49622 this.signPanel = this.wrap.createChild({
49624 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49628 this.svgID = Roo.id();
49629 this.svgEl = this.signPanel.createChild({
49630 xmlns : 'http://www.w3.org/2000/svg',
49632 id : this.svgID + "-svg",
49634 height: this.height,
49635 viewBox: '0 0 '+this.width+' '+this.height,
49639 id: this.svgID + "-svg-r",
49641 height: this.height,
49646 id: this.svgID + "-svg-l",
49648 y1: (this.height*0.8), // start set the line in 80% of height
49649 x2: this.width, // end
49650 y2: (this.height*0.8), // end set the line in 80% of height
49652 'stroke-width': "1",
49653 'stroke-dasharray': "3",
49654 'shape-rendering': "crispEdges",
49655 'pointer-events': "none"
49659 id: this.svgID + "-svg-p",
49661 'stroke-width': "3",
49663 'pointer-events': 'none'
49668 this.svgBox = this.svgEl.dom.getScreenCTM();
49670 createSVG : function(){
49671 var svg = this.signPanel;
49672 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49675 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49676 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49677 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49678 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49679 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49680 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49681 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49684 isTouchEvent : function(e){
49685 return e.type.match(/^touch/);
49687 getCoords : function (e) {
49688 var pt = this.svgEl.dom.createSVGPoint();
49691 if (this.isTouchEvent(e)) {
49692 pt.x = e.targetTouches[0].clientX;
49693 pt.y = e.targetTouches[0].clientY;
49695 var a = this.svgEl.dom.getScreenCTM();
49696 var b = a.inverse();
49697 var mx = pt.matrixTransform(b);
49698 return mx.x + ',' + mx.y;
49700 //mouse event headler
49701 down : function (e) {
49702 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49703 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49705 this.isMouseDown = true;
49707 e.preventDefault();
49709 move : function (e) {
49710 if (this.isMouseDown) {
49711 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49712 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49715 e.preventDefault();
49717 up : function (e) {
49718 this.isMouseDown = false;
49719 var sp = this.signatureTmp.split(' ');
49722 if(!sp[sp.length-2].match(/^L/)){
49726 this.signatureTmp = sp.join(" ");
49729 if(this.getValue() != this.signatureTmp){
49730 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49731 this.isConfirmed = false;
49733 e.preventDefault();
49737 * Protected method that will not generally be called directly. It
49738 * is called when the editor creates its toolbar. Override this method if you need to
49739 * add custom toolbar buttons.
49740 * @param {HtmlEditor} editor
49742 createToolbar : function(editor){
49743 function btn(id, toggle, handler){
49744 var xid = fid + '-'+ id ;
49748 cls : 'x-btn-icon x-edit-'+id,
49749 enableToggle:toggle !== false,
49750 scope: editor, // was editor...
49751 handler:handler||editor.relayBtnCmd,
49752 clickEvent:'mousedown',
49753 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49759 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49763 cls : ' x-signature-btn x-signature-'+id,
49764 scope: editor, // was editor...
49765 handler: this.reset,
49766 clickEvent:'mousedown',
49767 text: this.labels.clear
49774 cls : ' x-signature-btn x-signature-'+id,
49775 scope: editor, // was editor...
49776 handler: this.confirmHandler,
49777 clickEvent:'mousedown',
49778 text: this.labels.confirm
49785 * when user is clicked confirm then show this image.....
49787 * @return {String} Image Data URI
49789 getImageDataURI : function(){
49790 var svg = this.svgEl.dom.parentNode.innerHTML;
49791 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49796 * @return {Boolean} this.isConfirmed
49798 getConfirmed : function(){
49799 return this.isConfirmed;
49803 * @return {Number} this.width
49805 getWidth : function(){
49810 * @return {Number} this.height
49812 getHeight : function(){
49813 return this.height;
49816 getSignature : function(){
49817 return this.signatureTmp;
49820 reset : function(){
49821 this.signatureTmp = '';
49822 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49823 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49824 this.isConfirmed = false;
49825 Roo.form.Signature.superclass.reset.call(this);
49827 setSignature : function(s){
49828 this.signatureTmp = s;
49829 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49830 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49832 this.isConfirmed = false;
49833 Roo.form.Signature.superclass.reset.call(this);
49836 // Roo.log(this.signPanel.dom.contentWindow.up())
49839 setConfirmed : function(){
49843 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49846 confirmHandler : function(){
49847 if(!this.getSignature()){
49851 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49852 this.setValue(this.getSignature());
49853 this.isConfirmed = true;
49855 this.fireEvent('confirm', this);
49858 // Subclasses should provide the validation implementation by overriding this
49859 validateValue : function(value){
49860 if(this.allowBlank){
49864 if(this.isConfirmed){
49871 * Ext JS Library 1.1.1
49872 * Copyright(c) 2006-2007, Ext JS, LLC.
49874 * Originally Released Under LGPL - original licence link has changed is not relivant.
49877 * <script type="text/javascript">
49882 * @class Roo.form.ComboBox
49883 * @extends Roo.form.TriggerField
49884 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49886 * Create a new ComboBox.
49887 * @param {Object} config Configuration options
49889 Roo.form.Select = function(config){
49890 Roo.form.Select.superclass.constructor.call(this, config);
49894 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49896 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49899 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49900 * rendering into an Roo.Editor, defaults to false)
49903 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49904 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49907 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49910 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49911 * the dropdown list (defaults to undefined, with no header element)
49915 * @cfg {String/Roo.Template} tpl The template to use to render the output
49919 defaultAutoCreate : {tag: "select" },
49921 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49923 listWidth: undefined,
49925 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49926 * mode = 'remote' or 'text' if mode = 'local')
49928 displayField: undefined,
49930 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49931 * mode = 'remote' or 'value' if mode = 'local').
49932 * Note: use of a valueField requires the user make a selection
49933 * in order for a value to be mapped.
49935 valueField: undefined,
49939 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49940 * field's data value (defaults to the underlying DOM element's name)
49942 hiddenName: undefined,
49944 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49948 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49950 selectedClass: 'x-combo-selected',
49952 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49953 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49954 * which displays a downward arrow icon).
49956 triggerClass : 'x-form-arrow-trigger',
49958 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49962 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49963 * anchor positions (defaults to 'tl-bl')
49965 listAlign: 'tl-bl?',
49967 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49971 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49972 * query specified by the allQuery config option (defaults to 'query')
49974 triggerAction: 'query',
49976 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49977 * (defaults to 4, does not apply if editable = false)
49981 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49982 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49986 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49987 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49991 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49992 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49996 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49997 * when editable = true (defaults to false)
49999 selectOnFocus:false,
50001 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50003 queryParam: 'query',
50005 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50006 * when mode = 'remote' (defaults to 'Loading...')
50008 loadingText: 'Loading...',
50010 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50014 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
50018 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
50019 * traditional select (defaults to true)
50023 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
50027 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
50031 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
50032 * listWidth has a higher value)
50036 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
50037 * allow the user to set arbitrary text into the field (defaults to false)
50039 forceSelection:false,
50041 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
50042 * if typeAhead = true (defaults to 250)
50044 typeAheadDelay : 250,
50046 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
50047 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
50049 valueNotFoundText : undefined,
50052 * @cfg {String} defaultValue The value displayed after loading the store.
50057 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
50059 blockFocus : false,
50062 * @cfg {Boolean} disableClear Disable showing of clear button.
50064 disableClear : false,
50066 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
50068 alwaysQuery : false,
50074 // element that contains real text value.. (when hidden is used..)
50077 onRender : function(ct, position){
50078 Roo.form.Field.prototype.onRender.call(this, ct, position);
50081 this.store.on('beforeload', this.onBeforeLoad, this);
50082 this.store.on('load', this.onLoad, this);
50083 this.store.on('loadexception', this.onLoadException, this);
50084 this.store.load({});
50092 initEvents : function(){
50093 //Roo.form.ComboBox.superclass.initEvents.call(this);
50097 onDestroy : function(){
50100 this.store.un('beforeload', this.onBeforeLoad, this);
50101 this.store.un('load', this.onLoad, this);
50102 this.store.un('loadexception', this.onLoadException, this);
50104 //Roo.form.ComboBox.superclass.onDestroy.call(this);
50108 fireKey : function(e){
50109 if(e.isNavKeyPress() && !this.list.isVisible()){
50110 this.fireEvent("specialkey", this, e);
50115 onResize: function(w, h){
50123 * Allow or prevent the user from directly editing the field text. If false is passed,
50124 * the user will only be able to select from the items defined in the dropdown list. This method
50125 * is the runtime equivalent of setting the 'editable' config option at config time.
50126 * @param {Boolean} value True to allow the user to directly edit the field text
50128 setEditable : function(value){
50133 onBeforeLoad : function(){
50135 Roo.log("Select before load");
50138 this.innerList.update(this.loadingText ?
50139 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50140 //this.restrictHeight();
50141 this.selectedIndex = -1;
50145 onLoad : function(){
50148 var dom = this.el.dom;
50149 dom.innerHTML = '';
50150 var od = dom.ownerDocument;
50152 if (this.emptyText) {
50153 var op = od.createElement('option');
50154 op.setAttribute('value', '');
50155 op.innerHTML = String.format('{0}', this.emptyText);
50156 dom.appendChild(op);
50158 if(this.store.getCount() > 0){
50160 var vf = this.valueField;
50161 var df = this.displayField;
50162 this.store.data.each(function(r) {
50163 // which colmsn to use... testing - cdoe / title..
50164 var op = od.createElement('option');
50165 op.setAttribute('value', r.data[vf]);
50166 op.innerHTML = String.format('{0}', r.data[df]);
50167 dom.appendChild(op);
50169 if (typeof(this.defaultValue != 'undefined')) {
50170 this.setValue(this.defaultValue);
50175 //this.onEmptyResults();
50180 onLoadException : function()
50182 dom.innerHTML = '';
50184 Roo.log("Select on load exception");
50188 Roo.log(this.store.reader.jsonData);
50189 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50190 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50196 onTypeAhead : function(){
50201 onSelect : function(record, index){
50202 Roo.log('on select?');
50204 if(this.fireEvent('beforeselect', this, record, index) !== false){
50205 this.setFromData(index > -1 ? record.data : false);
50207 this.fireEvent('select', this, record, index);
50212 * Returns the currently selected field value or empty string if no value is set.
50213 * @return {String} value The selected value
50215 getValue : function(){
50216 var dom = this.el.dom;
50217 this.value = dom.options[dom.selectedIndex].value;
50223 * Clears any text/value currently set in the field
50225 clearValue : function(){
50227 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50232 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50233 * will be displayed in the field. If the value does not match the data value of an existing item,
50234 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50235 * Otherwise the field will be blank (although the value will still be set).
50236 * @param {String} value The value to match
50238 setValue : function(v){
50239 var d = this.el.dom;
50240 for (var i =0; i < d.options.length;i++) {
50241 if (v == d.options[i].value) {
50242 d.selectedIndex = i;
50250 * @property {Object} the last set data for the element
50255 * Sets the value of the field based on a object which is related to the record format for the store.
50256 * @param {Object} value the value to set as. or false on reset?
50258 setFromData : function(o){
50259 Roo.log('setfrom data?');
50265 reset : function(){
50269 findRecord : function(prop, value){
50274 if(this.store.getCount() > 0){
50275 this.store.each(function(r){
50276 if(r.data[prop] == value){
50286 getName: function()
50288 // returns hidden if it's set..
50289 if (!this.rendered) {return ''};
50290 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50298 onEmptyResults : function(){
50299 Roo.log('empty results');
50304 * Returns true if the dropdown list is expanded, else false.
50306 isExpanded : function(){
50311 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50312 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50313 * @param {String} value The data value of the item to select
50314 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50315 * selected item if it is not currently in view (defaults to true)
50316 * @return {Boolean} True if the value matched an item in the list, else false
50318 selectByValue : function(v, scrollIntoView){
50319 Roo.log('select By Value');
50322 if(v !== undefined && v !== null){
50323 var r = this.findRecord(this.valueField || this.displayField, v);
50325 this.select(this.store.indexOf(r), scrollIntoView);
50333 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50334 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50335 * @param {Number} index The zero-based index of the list item to select
50336 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50337 * selected item if it is not currently in view (defaults to true)
50339 select : function(index, scrollIntoView){
50340 Roo.log('select ');
50343 this.selectedIndex = index;
50344 this.view.select(index);
50345 if(scrollIntoView !== false){
50346 var el = this.view.getNode(index);
50348 this.innerList.scrollChildIntoView(el, false);
50356 validateBlur : function(){
50363 initQuery : function(){
50364 this.doQuery(this.getRawValue());
50368 doForce : function(){
50369 if(this.el.dom.value.length > 0){
50370 this.el.dom.value =
50371 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50377 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50378 * query allowing the query action to be canceled if needed.
50379 * @param {String} query The SQL query to execute
50380 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50381 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50382 * saved in the current store (defaults to false)
50384 doQuery : function(q, forceAll){
50386 Roo.log('doQuery?');
50387 if(q === undefined || q === null){
50392 forceAll: forceAll,
50396 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50400 forceAll = qe.forceAll;
50401 if(forceAll === true || (q.length >= this.minChars)){
50402 if(this.lastQuery != q || this.alwaysQuery){
50403 this.lastQuery = q;
50404 if(this.mode == 'local'){
50405 this.selectedIndex = -1;
50407 this.store.clearFilter();
50409 this.store.filter(this.displayField, q);
50413 this.store.baseParams[this.queryParam] = q;
50415 params: this.getParams(q)
50420 this.selectedIndex = -1;
50427 getParams : function(q){
50429 //p[this.queryParam] = q;
50432 p.limit = this.pageSize;
50438 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50440 collapse : function(){
50445 collapseIf : function(e){
50450 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50452 expand : function(){
50460 * @cfg {Boolean} grow
50464 * @cfg {Number} growMin
50468 * @cfg {Number} growMax
50476 setWidth : function()
50480 getResizeEl : function(){
50483 });//<script type="text/javasscript">
50487 * @class Roo.DDView
50488 * A DnD enabled version of Roo.View.
50489 * @param {Element/String} container The Element in which to create the View.
50490 * @param {String} tpl The template string used to create the markup for each element of the View
50491 * @param {Object} config The configuration properties. These include all the config options of
50492 * {@link Roo.View} plus some specific to this class.<br>
50494 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50495 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50497 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50498 .x-view-drag-insert-above {
50499 border-top:1px dotted #3366cc;
50501 .x-view-drag-insert-below {
50502 border-bottom:1px dotted #3366cc;
50508 Roo.DDView = function(container, tpl, config) {
50509 Roo.DDView.superclass.constructor.apply(this, arguments);
50510 this.getEl().setStyle("outline", "0px none");
50511 this.getEl().unselectable();
50512 if (this.dragGroup) {
50513 this.setDraggable(this.dragGroup.split(","));
50515 if (this.dropGroup) {
50516 this.setDroppable(this.dropGroup.split(","));
50518 if (this.deletable) {
50519 this.setDeletable();
50521 this.isDirtyFlag = false;
50527 Roo.extend(Roo.DDView, Roo.View, {
50528 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50529 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50530 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50531 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50535 reset: Roo.emptyFn,
50537 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50539 validate: function() {
50543 destroy: function() {
50544 this.purgeListeners();
50545 this.getEl.removeAllListeners();
50546 this.getEl().remove();
50547 if (this.dragZone) {
50548 if (this.dragZone.destroy) {
50549 this.dragZone.destroy();
50552 if (this.dropZone) {
50553 if (this.dropZone.destroy) {
50554 this.dropZone.destroy();
50559 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50560 getName: function() {
50564 /** Loads the View from a JSON string representing the Records to put into the Store. */
50565 setValue: function(v) {
50567 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50570 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50571 this.store.proxy = new Roo.data.MemoryProxy(data);
50575 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50576 getValue: function() {
50578 this.store.each(function(rec) {
50579 result += rec.id + ',';
50581 return result.substr(0, result.length - 1) + ')';
50584 getIds: function() {
50585 var i = 0, result = new Array(this.store.getCount());
50586 this.store.each(function(rec) {
50587 result[i++] = rec.id;
50592 isDirty: function() {
50593 return this.isDirtyFlag;
50597 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50598 * whole Element becomes the target, and this causes the drop gesture to append.
50600 getTargetFromEvent : function(e) {
50601 var target = e.getTarget();
50602 while ((target !== null) && (target.parentNode != this.el.dom)) {
50603 target = target.parentNode;
50606 target = this.el.dom.lastChild || this.el.dom;
50612 * Create the drag data which consists of an object which has the property "ddel" as
50613 * the drag proxy element.
50615 getDragData : function(e) {
50616 var target = this.findItemFromChild(e.getTarget());
50618 this.handleSelection(e);
50619 var selNodes = this.getSelectedNodes();
50622 copy: this.copy || (this.allowCopy && e.ctrlKey),
50626 var selectedIndices = this.getSelectedIndexes();
50627 for (var i = 0; i < selectedIndices.length; i++) {
50628 dragData.records.push(this.store.getAt(selectedIndices[i]));
50630 if (selNodes.length == 1) {
50631 dragData.ddel = target.cloneNode(true); // the div element
50633 var div = document.createElement('div'); // create the multi element drag "ghost"
50634 div.className = 'multi-proxy';
50635 for (var i = 0, len = selNodes.length; i < len; i++) {
50636 div.appendChild(selNodes[i].cloneNode(true));
50638 dragData.ddel = div;
50640 //console.log(dragData)
50641 //console.log(dragData.ddel.innerHTML)
50644 //console.log('nodragData')
50648 /** Specify to which ddGroup items in this DDView may be dragged. */
50649 setDraggable: function(ddGroup) {
50650 if (ddGroup instanceof Array) {
50651 Roo.each(ddGroup, this.setDraggable, this);
50654 if (this.dragZone) {
50655 this.dragZone.addToGroup(ddGroup);
50657 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50658 containerScroll: true,
50662 // Draggability implies selection. DragZone's mousedown selects the element.
50663 if (!this.multiSelect) { this.singleSelect = true; }
50665 // Wire the DragZone's handlers up to methods in *this*
50666 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50670 /** Specify from which ddGroup this DDView accepts drops. */
50671 setDroppable: function(ddGroup) {
50672 if (ddGroup instanceof Array) {
50673 Roo.each(ddGroup, this.setDroppable, this);
50676 if (this.dropZone) {
50677 this.dropZone.addToGroup(ddGroup);
50679 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50680 containerScroll: true,
50684 // Wire the DropZone's handlers up to methods in *this*
50685 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50686 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50687 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50688 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50689 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50693 /** Decide whether to drop above or below a View node. */
50694 getDropPoint : function(e, n, dd){
50695 if (n == this.el.dom) { return "above"; }
50696 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50697 var c = t + (b - t) / 2;
50698 var y = Roo.lib.Event.getPageY(e);
50706 onNodeEnter : function(n, dd, e, data){
50710 onNodeOver : function(n, dd, e, data){
50711 var pt = this.getDropPoint(e, n, dd);
50712 // set the insert point style on the target node
50713 var dragElClass = this.dropNotAllowed;
50716 if (pt == "above"){
50717 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50718 targetElClass = "x-view-drag-insert-above";
50720 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50721 targetElClass = "x-view-drag-insert-below";
50723 if (this.lastInsertClass != targetElClass){
50724 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50725 this.lastInsertClass = targetElClass;
50728 return dragElClass;
50731 onNodeOut : function(n, dd, e, data){
50732 this.removeDropIndicators(n);
50735 onNodeDrop : function(n, dd, e, data){
50736 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50739 var pt = this.getDropPoint(e, n, dd);
50740 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50741 if (pt == "below") { insertAt++; }
50742 for (var i = 0; i < data.records.length; i++) {
50743 var r = data.records[i];
50744 var dup = this.store.getById(r.id);
50745 if (dup && (dd != this.dragZone)) {
50746 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50749 this.store.insert(insertAt++, r.copy());
50751 data.source.isDirtyFlag = true;
50753 this.store.insert(insertAt++, r);
50755 this.isDirtyFlag = true;
50758 this.dragZone.cachedTarget = null;
50762 removeDropIndicators : function(n){
50764 Roo.fly(n).removeClass([
50765 "x-view-drag-insert-above",
50766 "x-view-drag-insert-below"]);
50767 this.lastInsertClass = "_noclass";
50772 * Utility method. Add a delete option to the DDView's context menu.
50773 * @param {String} imageUrl The URL of the "delete" icon image.
50775 setDeletable: function(imageUrl) {
50776 if (!this.singleSelect && !this.multiSelect) {
50777 this.singleSelect = true;
50779 var c = this.getContextMenu();
50780 this.contextMenu.on("itemclick", function(item) {
50783 this.remove(this.getSelectedIndexes());
50787 this.contextMenu.add({
50794 /** Return the context menu for this DDView. */
50795 getContextMenu: function() {
50796 if (!this.contextMenu) {
50797 // Create the View's context menu
50798 this.contextMenu = new Roo.menu.Menu({
50799 id: this.id + "-contextmenu"
50801 this.el.on("contextmenu", this.showContextMenu, this);
50803 return this.contextMenu;
50806 disableContextMenu: function() {
50807 if (this.contextMenu) {
50808 this.el.un("contextmenu", this.showContextMenu, this);
50812 showContextMenu: function(e, item) {
50813 item = this.findItemFromChild(e.getTarget());
50816 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50817 this.contextMenu.showAt(e.getXY());
50822 * Remove {@link Roo.data.Record}s at the specified indices.
50823 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50825 remove: function(selectedIndices) {
50826 selectedIndices = [].concat(selectedIndices);
50827 for (var i = 0; i < selectedIndices.length; i++) {
50828 var rec = this.store.getAt(selectedIndices[i]);
50829 this.store.remove(rec);
50834 * Double click fires the event, but also, if this is draggable, and there is only one other
50835 * related DropZone, it transfers the selected node.
50837 onDblClick : function(e){
50838 var item = this.findItemFromChild(e.getTarget());
50840 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50843 if (this.dragGroup) {
50844 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50845 while (targets.indexOf(this.dropZone) > -1) {
50846 targets.remove(this.dropZone);
50848 if (targets.length == 1) {
50849 this.dragZone.cachedTarget = null;
50850 var el = Roo.get(targets[0].getEl());
50851 var box = el.getBox(true);
50852 targets[0].onNodeDrop(el.dom, {
50854 xy: [box.x, box.y + box.height - 1]
50855 }, null, this.getDragData(e));
50861 handleSelection: function(e) {
50862 this.dragZone.cachedTarget = null;
50863 var item = this.findItemFromChild(e.getTarget());
50865 this.clearSelections(true);
50868 if (item && (this.multiSelect || this.singleSelect)){
50869 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50870 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50871 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50872 this.unselect(item);
50874 this.select(item, this.multiSelect && e.ctrlKey);
50875 this.lastSelection = item;
50880 onItemClick : function(item, index, e){
50881 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50887 unselect : function(nodeInfo, suppressEvent){
50888 var node = this.getNode(nodeInfo);
50889 if(node && this.isSelected(node)){
50890 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50891 Roo.fly(node).removeClass(this.selectedClass);
50892 this.selections.remove(node);
50893 if(!suppressEvent){
50894 this.fireEvent("selectionchange", this, this.selections);
50902 * Ext JS Library 1.1.1
50903 * Copyright(c) 2006-2007, Ext JS, LLC.
50905 * Originally Released Under LGPL - original licence link has changed is not relivant.
50908 * <script type="text/javascript">
50912 * @class Roo.LayoutManager
50913 * @extends Roo.util.Observable
50914 * Base class for layout managers.
50916 Roo.LayoutManager = function(container, config){
50917 Roo.LayoutManager.superclass.constructor.call(this);
50918 this.el = Roo.get(container);
50919 // ie scrollbar fix
50920 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50921 document.body.scroll = "no";
50922 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50923 this.el.position('relative');
50925 this.id = this.el.id;
50926 this.el.addClass("x-layout-container");
50927 /** false to disable window resize monitoring @type Boolean */
50928 this.monitorWindowResize = true;
50933 * Fires when a layout is performed.
50934 * @param {Roo.LayoutManager} this
50938 * @event regionresized
50939 * Fires when the user resizes a region.
50940 * @param {Roo.LayoutRegion} region The resized region
50941 * @param {Number} newSize The new size (width for east/west, height for north/south)
50943 "regionresized" : true,
50945 * @event regioncollapsed
50946 * Fires when a region is collapsed.
50947 * @param {Roo.LayoutRegion} region The collapsed region
50949 "regioncollapsed" : true,
50951 * @event regionexpanded
50952 * Fires when a region is expanded.
50953 * @param {Roo.LayoutRegion} region The expanded region
50955 "regionexpanded" : true
50957 this.updating = false;
50958 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50961 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50963 * Returns true if this layout is currently being updated
50964 * @return {Boolean}
50966 isUpdating : function(){
50967 return this.updating;
50971 * Suspend the LayoutManager from doing auto-layouts while
50972 * making multiple add or remove calls
50974 beginUpdate : function(){
50975 this.updating = true;
50979 * Restore auto-layouts and optionally disable the manager from performing a layout
50980 * @param {Boolean} noLayout true to disable a layout update
50982 endUpdate : function(noLayout){
50983 this.updating = false;
50989 layout: function(){
50993 onRegionResized : function(region, newSize){
50994 this.fireEvent("regionresized", region, newSize);
50998 onRegionCollapsed : function(region){
50999 this.fireEvent("regioncollapsed", region);
51002 onRegionExpanded : function(region){
51003 this.fireEvent("regionexpanded", region);
51007 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51008 * performs box-model adjustments.
51009 * @return {Object} The size as an object {width: (the width), height: (the height)}
51011 getViewSize : function(){
51013 if(this.el.dom != document.body){
51014 size = this.el.getSize();
51016 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
51018 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
51019 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
51024 * Returns the Element this layout is bound to.
51025 * @return {Roo.Element}
51027 getEl : function(){
51032 * Returns the specified region.
51033 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
51034 * @return {Roo.LayoutRegion}
51036 getRegion : function(target){
51037 return this.regions[target.toLowerCase()];
51040 onWindowResize : function(){
51041 if(this.monitorWindowResize){
51047 * Ext JS Library 1.1.1
51048 * Copyright(c) 2006-2007, Ext JS, LLC.
51050 * Originally Released Under LGPL - original licence link has changed is not relivant.
51053 * <script type="text/javascript">
51056 * @class Roo.BorderLayout
51057 * @extends Roo.LayoutManager
51058 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
51059 * please see: <br><br>
51060 * <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>
51061 * <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>
51064 var layout = new Roo.BorderLayout(document.body, {
51098 preferredTabWidth: 150
51103 var CP = Roo.ContentPanel;
51105 layout.beginUpdate();
51106 layout.add("north", new CP("north", "North"));
51107 layout.add("south", new CP("south", {title: "South", closable: true}));
51108 layout.add("west", new CP("west", {title: "West"}));
51109 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
51110 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
51111 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
51112 layout.getRegion("center").showPanel("center1");
51113 layout.endUpdate();
51116 <b>The container the layout is rendered into can be either the body element or any other element.
51117 If it is not the body element, the container needs to either be an absolute positioned element,
51118 or you will need to add "position:relative" to the css of the container. You will also need to specify
51119 the container size if it is not the body element.</b>
51122 * Create a new BorderLayout
51123 * @param {String/HTMLElement/Element} container The container this layout is bound to
51124 * @param {Object} config Configuration options
51126 Roo.BorderLayout = function(container, config){
51127 config = config || {};
51128 Roo.BorderLayout.superclass.constructor.call(this, container, config);
51129 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
51130 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
51131 var target = this.factory.validRegions[i];
51132 if(config[target]){
51133 this.addRegion(target, config[target]);
51138 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51140 * Creates and adds a new region if it doesn't already exist.
51141 * @param {String} target The target region key (north, south, east, west or center).
51142 * @param {Object} config The regions config object
51143 * @return {BorderLayoutRegion} The new region
51145 addRegion : function(target, config){
51146 if(!this.regions[target]){
51147 var r = this.factory.create(target, this, config);
51148 this.bindRegion(target, r);
51150 return this.regions[target];
51154 bindRegion : function(name, r){
51155 this.regions[name] = r;
51156 r.on("visibilitychange", this.layout, this);
51157 r.on("paneladded", this.layout, this);
51158 r.on("panelremoved", this.layout, this);
51159 r.on("invalidated", this.layout, this);
51160 r.on("resized", this.onRegionResized, this);
51161 r.on("collapsed", this.onRegionCollapsed, this);
51162 r.on("expanded", this.onRegionExpanded, this);
51166 * Performs a layout update.
51168 layout : function(){
51169 if(this.updating) {
51172 var size = this.getViewSize();
51173 var w = size.width;
51174 var h = size.height;
51179 //var x = 0, y = 0;
51181 var rs = this.regions;
51182 var north = rs["north"];
51183 var south = rs["south"];
51184 var west = rs["west"];
51185 var east = rs["east"];
51186 var center = rs["center"];
51187 //if(this.hideOnLayout){ // not supported anymore
51188 //c.el.setStyle("display", "none");
51190 if(north && north.isVisible()){
51191 var b = north.getBox();
51192 var m = north.getMargins();
51193 b.width = w - (m.left+m.right);
51196 centerY = b.height + b.y + m.bottom;
51197 centerH -= centerY;
51198 north.updateBox(this.safeBox(b));
51200 if(south && south.isVisible()){
51201 var b = south.getBox();
51202 var m = south.getMargins();
51203 b.width = w - (m.left+m.right);
51205 var totalHeight = (b.height + m.top + m.bottom);
51206 b.y = h - totalHeight + m.top;
51207 centerH -= totalHeight;
51208 south.updateBox(this.safeBox(b));
51210 if(west && west.isVisible()){
51211 var b = west.getBox();
51212 var m = west.getMargins();
51213 b.height = centerH - (m.top+m.bottom);
51215 b.y = centerY + m.top;
51216 var totalWidth = (b.width + m.left + m.right);
51217 centerX += totalWidth;
51218 centerW -= totalWidth;
51219 west.updateBox(this.safeBox(b));
51221 if(east && east.isVisible()){
51222 var b = east.getBox();
51223 var m = east.getMargins();
51224 b.height = centerH - (m.top+m.bottom);
51225 var totalWidth = (b.width + m.left + m.right);
51226 b.x = w - totalWidth + m.left;
51227 b.y = centerY + m.top;
51228 centerW -= totalWidth;
51229 east.updateBox(this.safeBox(b));
51232 var m = center.getMargins();
51234 x: centerX + m.left,
51235 y: centerY + m.top,
51236 width: centerW - (m.left+m.right),
51237 height: centerH - (m.top+m.bottom)
51239 //if(this.hideOnLayout){
51240 //center.el.setStyle("display", "block");
51242 center.updateBox(this.safeBox(centerBox));
51245 this.fireEvent("layout", this);
51249 safeBox : function(box){
51250 box.width = Math.max(0, box.width);
51251 box.height = Math.max(0, box.height);
51256 * Adds a ContentPanel (or subclass) to this layout.
51257 * @param {String} target The target region key (north, south, east, west or center).
51258 * @param {Roo.ContentPanel} panel The panel to add
51259 * @return {Roo.ContentPanel} The added panel
51261 add : function(target, panel){
51263 target = target.toLowerCase();
51264 return this.regions[target].add(panel);
51268 * Remove a ContentPanel (or subclass) to this layout.
51269 * @param {String} target The target region key (north, south, east, west or center).
51270 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51271 * @return {Roo.ContentPanel} The removed panel
51273 remove : function(target, panel){
51274 target = target.toLowerCase();
51275 return this.regions[target].remove(panel);
51279 * Searches all regions for a panel with the specified id
51280 * @param {String} panelId
51281 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51283 findPanel : function(panelId){
51284 var rs = this.regions;
51285 for(var target in rs){
51286 if(typeof rs[target] != "function"){
51287 var p = rs[target].getPanel(panelId);
51297 * Searches all regions for a panel with the specified id and activates (shows) it.
51298 * @param {String/ContentPanel} panelId The panels id or the panel itself
51299 * @return {Roo.ContentPanel} The shown panel or null
51301 showPanel : function(panelId) {
51302 var rs = this.regions;
51303 for(var target in rs){
51304 var r = rs[target];
51305 if(typeof r != "function"){
51306 if(r.hasPanel(panelId)){
51307 return r.showPanel(panelId);
51315 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51316 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51318 restoreState : function(provider){
51320 provider = Roo.state.Manager;
51322 var sm = new Roo.LayoutStateManager();
51323 sm.init(this, provider);
51327 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51328 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51329 * a valid ContentPanel config object. Example:
51331 // Create the main layout
51332 var layout = new Roo.BorderLayout('main-ct', {
51343 // Create and add multiple ContentPanels at once via configs
51346 id: 'source-files',
51348 title:'Ext Source Files',
51361 * @param {Object} regions An object containing ContentPanel configs by region name
51363 batchAdd : function(regions){
51364 this.beginUpdate();
51365 for(var rname in regions){
51366 var lr = this.regions[rname];
51368 this.addTypedPanels(lr, regions[rname]);
51375 addTypedPanels : function(lr, ps){
51376 if(typeof ps == 'string'){
51377 lr.add(new Roo.ContentPanel(ps));
51379 else if(ps instanceof Array){
51380 for(var i =0, len = ps.length; i < len; i++){
51381 this.addTypedPanels(lr, ps[i]);
51384 else if(!ps.events){ // raw config?
51386 delete ps.el; // prevent conflict
51387 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51389 else { // panel object assumed!
51394 * Adds a xtype elements to the layout.
51398 xtype : 'ContentPanel',
51405 xtype : 'NestedLayoutPanel',
51411 items : [ ... list of content panels or nested layout panels.. ]
51415 * @param {Object} cfg Xtype definition of item to add.
51417 addxtype : function(cfg)
51419 // basically accepts a pannel...
51420 // can accept a layout region..!?!?
51421 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51423 if (!cfg.xtype.match(/Panel$/)) {
51428 if (typeof(cfg.region) == 'undefined') {
51429 Roo.log("Failed to add Panel, region was not set");
51433 var region = cfg.region;
51439 xitems = cfg.items;
51446 case 'ContentPanel': // ContentPanel (el, cfg)
51447 case 'ScrollPanel': // ContentPanel (el, cfg)
51449 if(cfg.autoCreate) {
51450 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51452 var el = this.el.createChild();
51453 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51456 this.add(region, ret);
51460 case 'TreePanel': // our new panel!
51461 cfg.el = this.el.createChild();
51462 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51463 this.add(region, ret);
51466 case 'NestedLayoutPanel':
51467 // create a new Layout (which is a Border Layout...
51468 var el = this.el.createChild();
51469 var clayout = cfg.layout;
51471 clayout.items = clayout.items || [];
51472 // replace this exitems with the clayout ones..
51473 xitems = clayout.items;
51476 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51477 cfg.background = false;
51479 var layout = new Roo.BorderLayout(el, clayout);
51481 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51482 //console.log('adding nested layout panel ' + cfg.toSource());
51483 this.add(region, ret);
51484 nb = {}; /// find first...
51489 // needs grid and region
51491 //var el = this.getRegion(region).el.createChild();
51492 var el = this.el.createChild();
51493 // create the grid first...
51495 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51497 if (region == 'center' && this.active ) {
51498 cfg.background = false;
51500 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51502 this.add(region, ret);
51503 if (cfg.background) {
51504 ret.on('activate', function(gp) {
51505 if (!gp.grid.rendered) {
51520 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51522 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51523 this.add(region, ret);
51526 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51530 // GridPanel (grid, cfg)
51533 this.beginUpdate();
51537 Roo.each(xitems, function(i) {
51538 region = nb && i.region ? i.region : false;
51540 var add = ret.addxtype(i);
51543 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51544 if (!i.background) {
51545 abn[region] = nb[region] ;
51552 // make the last non-background panel active..
51553 //if (nb) { Roo.log(abn); }
51556 for(var r in abn) {
51557 region = this.getRegion(r);
51559 // tried using nb[r], but it does not work..
51561 region.showPanel(abn[r]);
51572 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51573 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51574 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51575 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51578 var CP = Roo.ContentPanel;
51580 var layout = Roo.BorderLayout.create({
51584 panels: [new CP("north", "North")]
51593 panels: [new CP("west", {title: "West"})]
51602 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51611 panels: [new CP("south", {title: "South", closable: true})]
51618 preferredTabWidth: 150,
51620 new CP("center1", {title: "Close Me", closable: true}),
51621 new CP("center2", {title: "Center Panel", closable: false})
51626 layout.getRegion("center").showPanel("center1");
51631 Roo.BorderLayout.create = function(config, targetEl){
51632 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51633 layout.beginUpdate();
51634 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51635 for(var j = 0, jlen = regions.length; j < jlen; j++){
51636 var lr = regions[j];
51637 if(layout.regions[lr] && config[lr].panels){
51638 var r = layout.regions[lr];
51639 var ps = config[lr].panels;
51640 layout.addTypedPanels(r, ps);
51643 layout.endUpdate();
51648 Roo.BorderLayout.RegionFactory = {
51650 validRegions : ["north","south","east","west","center"],
51653 create : function(target, mgr, config){
51654 target = target.toLowerCase();
51655 if(config.lightweight || config.basic){
51656 return new Roo.BasicLayoutRegion(mgr, config, target);
51660 return new Roo.NorthLayoutRegion(mgr, config);
51662 return new Roo.SouthLayoutRegion(mgr, config);
51664 return new Roo.EastLayoutRegion(mgr, config);
51666 return new Roo.WestLayoutRegion(mgr, config);
51668 return new Roo.CenterLayoutRegion(mgr, config);
51670 throw 'Layout region "'+target+'" not supported.';
51674 * Ext JS Library 1.1.1
51675 * Copyright(c) 2006-2007, Ext JS, LLC.
51677 * Originally Released Under LGPL - original licence link has changed is not relivant.
51680 * <script type="text/javascript">
51684 * @class Roo.BasicLayoutRegion
51685 * @extends Roo.util.Observable
51686 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51687 * and does not have a titlebar, tabs or any other features. All it does is size and position
51688 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51690 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51692 this.position = pos;
51695 * @scope Roo.BasicLayoutRegion
51699 * @event beforeremove
51700 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51701 * @param {Roo.LayoutRegion} this
51702 * @param {Roo.ContentPanel} panel The panel
51703 * @param {Object} e The cancel event object
51705 "beforeremove" : true,
51707 * @event invalidated
51708 * Fires when the layout for this region is changed.
51709 * @param {Roo.LayoutRegion} this
51711 "invalidated" : true,
51713 * @event visibilitychange
51714 * Fires when this region is shown or hidden
51715 * @param {Roo.LayoutRegion} this
51716 * @param {Boolean} visibility true or false
51718 "visibilitychange" : true,
51720 * @event paneladded
51721 * Fires when a panel is added.
51722 * @param {Roo.LayoutRegion} this
51723 * @param {Roo.ContentPanel} panel The panel
51725 "paneladded" : true,
51727 * @event panelremoved
51728 * Fires when a panel is removed.
51729 * @param {Roo.LayoutRegion} this
51730 * @param {Roo.ContentPanel} panel The panel
51732 "panelremoved" : true,
51734 * @event beforecollapse
51735 * Fires when this region before collapse.
51736 * @param {Roo.LayoutRegion} this
51738 "beforecollapse" : true,
51741 * Fires when this region is collapsed.
51742 * @param {Roo.LayoutRegion} this
51744 "collapsed" : true,
51747 * Fires when this region is expanded.
51748 * @param {Roo.LayoutRegion} this
51753 * Fires when this region is slid into view.
51754 * @param {Roo.LayoutRegion} this
51756 "slideshow" : true,
51759 * Fires when this region slides out of view.
51760 * @param {Roo.LayoutRegion} this
51762 "slidehide" : true,
51764 * @event panelactivated
51765 * Fires when a panel is activated.
51766 * @param {Roo.LayoutRegion} this
51767 * @param {Roo.ContentPanel} panel The activated panel
51769 "panelactivated" : true,
51772 * Fires when the user resizes this region.
51773 * @param {Roo.LayoutRegion} this
51774 * @param {Number} newSize The new size (width for east/west, height for north/south)
51778 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51779 this.panels = new Roo.util.MixedCollection();
51780 this.panels.getKey = this.getPanelId.createDelegate(this);
51782 this.activePanel = null;
51783 // ensure listeners are added...
51785 if (config.listeners || config.events) {
51786 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51787 listeners : config.listeners || {},
51788 events : config.events || {}
51792 if(skipConfig !== true){
51793 this.applyConfig(config);
51797 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51798 getPanelId : function(p){
51802 applyConfig : function(config){
51803 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51804 this.config = config;
51809 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51810 * the width, for horizontal (north, south) the height.
51811 * @param {Number} newSize The new width or height
51813 resizeTo : function(newSize){
51814 var el = this.el ? this.el :
51815 (this.activePanel ? this.activePanel.getEl() : null);
51817 switch(this.position){
51820 el.setWidth(newSize);
51821 this.fireEvent("resized", this, newSize);
51825 el.setHeight(newSize);
51826 this.fireEvent("resized", this, newSize);
51832 getBox : function(){
51833 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51836 getMargins : function(){
51837 return this.margins;
51840 updateBox : function(box){
51842 var el = this.activePanel.getEl();
51843 el.dom.style.left = box.x + "px";
51844 el.dom.style.top = box.y + "px";
51845 this.activePanel.setSize(box.width, box.height);
51849 * Returns the container element for this region.
51850 * @return {Roo.Element}
51852 getEl : function(){
51853 return this.activePanel;
51857 * Returns true if this region is currently visible.
51858 * @return {Boolean}
51860 isVisible : function(){
51861 return this.activePanel ? true : false;
51864 setActivePanel : function(panel){
51865 panel = this.getPanel(panel);
51866 if(this.activePanel && this.activePanel != panel){
51867 this.activePanel.setActiveState(false);
51868 this.activePanel.getEl().setLeftTop(-10000,-10000);
51870 this.activePanel = panel;
51871 panel.setActiveState(true);
51873 panel.setSize(this.box.width, this.box.height);
51875 this.fireEvent("panelactivated", this, panel);
51876 this.fireEvent("invalidated");
51880 * Show the specified panel.
51881 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51882 * @return {Roo.ContentPanel} The shown panel or null
51884 showPanel : function(panel){
51885 if(panel = this.getPanel(panel)){
51886 this.setActivePanel(panel);
51892 * Get the active panel for this region.
51893 * @return {Roo.ContentPanel} The active panel or null
51895 getActivePanel : function(){
51896 return this.activePanel;
51900 * Add the passed ContentPanel(s)
51901 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51902 * @return {Roo.ContentPanel} The panel added (if only one was added)
51904 add : function(panel){
51905 if(arguments.length > 1){
51906 for(var i = 0, len = arguments.length; i < len; i++) {
51907 this.add(arguments[i]);
51911 if(this.hasPanel(panel)){
51912 this.showPanel(panel);
51915 var el = panel.getEl();
51916 if(el.dom.parentNode != this.mgr.el.dom){
51917 this.mgr.el.dom.appendChild(el.dom);
51919 if(panel.setRegion){
51920 panel.setRegion(this);
51922 this.panels.add(panel);
51923 el.setStyle("position", "absolute");
51924 if(!panel.background){
51925 this.setActivePanel(panel);
51926 if(this.config.initialSize && this.panels.getCount()==1){
51927 this.resizeTo(this.config.initialSize);
51930 this.fireEvent("paneladded", this, panel);
51935 * Returns true if the panel is in this region.
51936 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51937 * @return {Boolean}
51939 hasPanel : function(panel){
51940 if(typeof panel == "object"){ // must be panel obj
51941 panel = panel.getId();
51943 return this.getPanel(panel) ? true : false;
51947 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51948 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51949 * @param {Boolean} preservePanel Overrides the config preservePanel option
51950 * @return {Roo.ContentPanel} The panel that was removed
51952 remove : function(panel, preservePanel){
51953 panel = this.getPanel(panel);
51958 this.fireEvent("beforeremove", this, panel, e);
51959 if(e.cancel === true){
51962 var panelId = panel.getId();
51963 this.panels.removeKey(panelId);
51968 * Returns the panel specified or null if it's not in this region.
51969 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51970 * @return {Roo.ContentPanel}
51972 getPanel : function(id){
51973 if(typeof id == "object"){ // must be panel obj
51976 return this.panels.get(id);
51980 * Returns this regions position (north/south/east/west/center).
51983 getPosition: function(){
51984 return this.position;
51988 * Ext JS Library 1.1.1
51989 * Copyright(c) 2006-2007, Ext JS, LLC.
51991 * Originally Released Under LGPL - original licence link has changed is not relivant.
51994 * <script type="text/javascript">
51998 * @class Roo.LayoutRegion
51999 * @extends Roo.BasicLayoutRegion
52000 * This class represents a region in a layout manager.
52001 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52002 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52003 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52004 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52005 * @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})
52006 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52007 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52008 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52009 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52010 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52011 * @cfg {String} title The title for the region (overrides panel titles)
52012 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52013 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52014 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52015 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
52016 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
52017 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
52018 * the space available, similar to FireFox 1.5 tabs (defaults to false)
52019 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
52020 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
52021 * @cfg {Boolean} showPin True to show a pin button
52022 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
52023 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
52024 * @cfg {Boolean} disableTabTips True to disable tab tooltips
52025 * @cfg {Number} width For East/West panels
52026 * @cfg {Number} height For North/South panels
52027 * @cfg {Boolean} split To show the splitter
52028 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
52030 Roo.LayoutRegion = function(mgr, config, pos){
52031 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
52032 var dh = Roo.DomHelper;
52033 /** This region's container element
52034 * @type Roo.Element */
52035 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
52036 /** This region's title element
52037 * @type Roo.Element */
52039 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
52040 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
52041 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
52043 this.titleEl.enableDisplayMode();
52044 /** This region's title text element
52045 * @type HTMLElement */
52046 this.titleTextEl = this.titleEl.dom.firstChild;
52047 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
52048 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
52049 this.closeBtn.enableDisplayMode();
52050 this.closeBtn.on("click", this.closeClicked, this);
52051 this.closeBtn.hide();
52053 this.createBody(config);
52054 this.visible = true;
52055 this.collapsed = false;
52057 if(config.hideWhenEmpty){
52059 this.on("paneladded", this.validateVisibility, this);
52060 this.on("panelremoved", this.validateVisibility, this);
52062 this.applyConfig(config);
52065 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
52067 createBody : function(){
52068 /** This region's body element
52069 * @type Roo.Element */
52070 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
52073 applyConfig : function(c){
52074 if(c.collapsible && this.position != "center" && !this.collapsedEl){
52075 var dh = Roo.DomHelper;
52076 if(c.titlebar !== false){
52077 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
52078 this.collapseBtn.on("click", this.collapse, this);
52079 this.collapseBtn.enableDisplayMode();
52081 if(c.showPin === true || this.showPin){
52082 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
52083 this.stickBtn.enableDisplayMode();
52084 this.stickBtn.on("click", this.expand, this);
52085 this.stickBtn.hide();
52088 /** This region's collapsed element
52089 * @type Roo.Element */
52090 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
52091 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
52093 if(c.floatable !== false){
52094 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
52095 this.collapsedEl.on("click", this.collapseClick, this);
52098 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
52099 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
52100 id: "message", unselectable: "on", style:{"float":"left"}});
52101 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
52103 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
52104 this.expandBtn.on("click", this.expand, this);
52106 if(this.collapseBtn){
52107 this.collapseBtn.setVisible(c.collapsible == true);
52109 this.cmargins = c.cmargins || this.cmargins ||
52110 (this.position == "west" || this.position == "east" ?
52111 {top: 0, left: 2, right:2, bottom: 0} :
52112 {top: 2, left: 0, right:0, bottom: 2});
52113 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52114 this.bottomTabs = c.tabPosition != "top";
52115 this.autoScroll = c.autoScroll || false;
52116 if(this.autoScroll){
52117 this.bodyEl.setStyle("overflow", "auto");
52119 this.bodyEl.setStyle("overflow", "hidden");
52121 //if(c.titlebar !== false){
52122 if((!c.titlebar && !c.title) || c.titlebar === false){
52123 this.titleEl.hide();
52125 this.titleEl.show();
52127 this.titleTextEl.innerHTML = c.title;
52131 this.duration = c.duration || .30;
52132 this.slideDuration = c.slideDuration || .45;
52135 this.collapse(true);
52142 * Returns true if this region is currently visible.
52143 * @return {Boolean}
52145 isVisible : function(){
52146 return this.visible;
52150 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52151 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52153 setCollapsedTitle : function(title){
52154 title = title || " ";
52155 if(this.collapsedTitleTextEl){
52156 this.collapsedTitleTextEl.innerHTML = title;
52160 getBox : function(){
52162 if(!this.collapsed){
52163 b = this.el.getBox(false, true);
52165 b = this.collapsedEl.getBox(false, true);
52170 getMargins : function(){
52171 return this.collapsed ? this.cmargins : this.margins;
52174 highlight : function(){
52175 this.el.addClass("x-layout-panel-dragover");
52178 unhighlight : function(){
52179 this.el.removeClass("x-layout-panel-dragover");
52182 updateBox : function(box){
52184 if(!this.collapsed){
52185 this.el.dom.style.left = box.x + "px";
52186 this.el.dom.style.top = box.y + "px";
52187 this.updateBody(box.width, box.height);
52189 this.collapsedEl.dom.style.left = box.x + "px";
52190 this.collapsedEl.dom.style.top = box.y + "px";
52191 this.collapsedEl.setSize(box.width, box.height);
52194 this.tabs.autoSizeTabs();
52198 updateBody : function(w, h){
52200 this.el.setWidth(w);
52201 w -= this.el.getBorderWidth("rl");
52202 if(this.config.adjustments){
52203 w += this.config.adjustments[0];
52207 this.el.setHeight(h);
52208 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52209 h -= this.el.getBorderWidth("tb");
52210 if(this.config.adjustments){
52211 h += this.config.adjustments[1];
52213 this.bodyEl.setHeight(h);
52215 h = this.tabs.syncHeight(h);
52218 if(this.panelSize){
52219 w = w !== null ? w : this.panelSize.width;
52220 h = h !== null ? h : this.panelSize.height;
52222 if(this.activePanel){
52223 var el = this.activePanel.getEl();
52224 w = w !== null ? w : el.getWidth();
52225 h = h !== null ? h : el.getHeight();
52226 this.panelSize = {width: w, height: h};
52227 this.activePanel.setSize(w, h);
52229 if(Roo.isIE && this.tabs){
52230 this.tabs.el.repaint();
52235 * Returns the container element for this region.
52236 * @return {Roo.Element}
52238 getEl : function(){
52243 * Hides this region.
52246 if(!this.collapsed){
52247 this.el.dom.style.left = "-2000px";
52250 this.collapsedEl.dom.style.left = "-2000px";
52251 this.collapsedEl.hide();
52253 this.visible = false;
52254 this.fireEvent("visibilitychange", this, false);
52258 * Shows this region if it was previously hidden.
52261 if(!this.collapsed){
52264 this.collapsedEl.show();
52266 this.visible = true;
52267 this.fireEvent("visibilitychange", this, true);
52270 closeClicked : function(){
52271 if(this.activePanel){
52272 this.remove(this.activePanel);
52276 collapseClick : function(e){
52278 e.stopPropagation();
52281 e.stopPropagation();
52287 * Collapses this region.
52288 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52290 collapse : function(skipAnim, skipCheck = false){
52291 if(this.collapsed) {
52295 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52297 this.collapsed = true;
52299 this.split.el.hide();
52301 if(this.config.animate && skipAnim !== true){
52302 this.fireEvent("invalidated", this);
52303 this.animateCollapse();
52305 this.el.setLocation(-20000,-20000);
52307 this.collapsedEl.show();
52308 this.fireEvent("collapsed", this);
52309 this.fireEvent("invalidated", this);
52315 animateCollapse : function(){
52320 * Expands this region if it was previously collapsed.
52321 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52322 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52324 expand : function(e, skipAnim){
52326 e.stopPropagation();
52328 if(!this.collapsed || this.el.hasActiveFx()) {
52332 this.afterSlideIn();
52335 this.collapsed = false;
52336 if(this.config.animate && skipAnim !== true){
52337 this.animateExpand();
52341 this.split.el.show();
52343 this.collapsedEl.setLocation(-2000,-2000);
52344 this.collapsedEl.hide();
52345 this.fireEvent("invalidated", this);
52346 this.fireEvent("expanded", this);
52350 animateExpand : function(){
52354 initTabs : function()
52356 this.bodyEl.setStyle("overflow", "hidden");
52357 var ts = new Roo.TabPanel(
52360 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52361 disableTooltips: this.config.disableTabTips,
52362 toolbar : this.config.toolbar
52365 if(this.config.hideTabs){
52366 ts.stripWrap.setDisplayed(false);
52369 ts.resizeTabs = this.config.resizeTabs === true;
52370 ts.minTabWidth = this.config.minTabWidth || 40;
52371 ts.maxTabWidth = this.config.maxTabWidth || 250;
52372 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52373 ts.monitorResize = false;
52374 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52375 ts.bodyEl.addClass('x-layout-tabs-body');
52376 this.panels.each(this.initPanelAsTab, this);
52379 initPanelAsTab : function(panel){
52380 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52381 this.config.closeOnTab && panel.isClosable());
52382 if(panel.tabTip !== undefined){
52383 ti.setTooltip(panel.tabTip);
52385 ti.on("activate", function(){
52386 this.setActivePanel(panel);
52388 if(this.config.closeOnTab){
52389 ti.on("beforeclose", function(t, e){
52391 this.remove(panel);
52397 updatePanelTitle : function(panel, title){
52398 if(this.activePanel == panel){
52399 this.updateTitle(title);
52402 var ti = this.tabs.getTab(panel.getEl().id);
52404 if(panel.tabTip !== undefined){
52405 ti.setTooltip(panel.tabTip);
52410 updateTitle : function(title){
52411 if(this.titleTextEl && !this.config.title){
52412 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52416 setActivePanel : function(panel){
52417 panel = this.getPanel(panel);
52418 if(this.activePanel && this.activePanel != panel){
52419 this.activePanel.setActiveState(false);
52421 this.activePanel = panel;
52422 panel.setActiveState(true);
52423 if(this.panelSize){
52424 panel.setSize(this.panelSize.width, this.panelSize.height);
52427 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52429 this.updateTitle(panel.getTitle());
52431 this.fireEvent("invalidated", this);
52433 this.fireEvent("panelactivated", this, panel);
52437 * Shows the specified panel.
52438 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52439 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52441 showPanel : function(panel)
52443 panel = this.getPanel(panel);
52446 var tab = this.tabs.getTab(panel.getEl().id);
52447 if(tab.isHidden()){
52448 this.tabs.unhideTab(tab.id);
52452 this.setActivePanel(panel);
52459 * Get the active panel for this region.
52460 * @return {Roo.ContentPanel} The active panel or null
52462 getActivePanel : function(){
52463 return this.activePanel;
52466 validateVisibility : function(){
52467 if(this.panels.getCount() < 1){
52468 this.updateTitle(" ");
52469 this.closeBtn.hide();
52472 if(!this.isVisible()){
52479 * Adds the passed ContentPanel(s) to this region.
52480 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52481 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52483 add : function(panel){
52484 if(arguments.length > 1){
52485 for(var i = 0, len = arguments.length; i < len; i++) {
52486 this.add(arguments[i]);
52490 if(this.hasPanel(panel)){
52491 this.showPanel(panel);
52494 panel.setRegion(this);
52495 this.panels.add(panel);
52496 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52497 this.bodyEl.dom.appendChild(panel.getEl().dom);
52498 if(panel.background !== true){
52499 this.setActivePanel(panel);
52501 this.fireEvent("paneladded", this, panel);
52507 this.initPanelAsTab(panel);
52509 if(panel.background !== true){
52510 this.tabs.activate(panel.getEl().id);
52512 this.fireEvent("paneladded", this, panel);
52517 * Hides the tab for the specified panel.
52518 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52520 hidePanel : function(panel){
52521 if(this.tabs && (panel = this.getPanel(panel))){
52522 this.tabs.hideTab(panel.getEl().id);
52527 * Unhides the tab for a previously hidden panel.
52528 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52530 unhidePanel : function(panel){
52531 if(this.tabs && (panel = this.getPanel(panel))){
52532 this.tabs.unhideTab(panel.getEl().id);
52536 clearPanels : function(){
52537 while(this.panels.getCount() > 0){
52538 this.remove(this.panels.first());
52543 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52544 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52545 * @param {Boolean} preservePanel Overrides the config preservePanel option
52546 * @return {Roo.ContentPanel} The panel that was removed
52548 remove : function(panel, preservePanel){
52549 panel = this.getPanel(panel);
52554 this.fireEvent("beforeremove", this, panel, e);
52555 if(e.cancel === true){
52558 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52559 var panelId = panel.getId();
52560 this.panels.removeKey(panelId);
52562 document.body.appendChild(panel.getEl().dom);
52565 this.tabs.removeTab(panel.getEl().id);
52566 }else if (!preservePanel){
52567 this.bodyEl.dom.removeChild(panel.getEl().dom);
52569 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52570 var p = this.panels.first();
52571 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52572 tempEl.appendChild(p.getEl().dom);
52573 this.bodyEl.update("");
52574 this.bodyEl.dom.appendChild(p.getEl().dom);
52576 this.updateTitle(p.getTitle());
52578 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52579 this.setActivePanel(p);
52581 panel.setRegion(null);
52582 if(this.activePanel == panel){
52583 this.activePanel = null;
52585 if(this.config.autoDestroy !== false && preservePanel !== true){
52586 try{panel.destroy();}catch(e){}
52588 this.fireEvent("panelremoved", this, panel);
52593 * Returns the TabPanel component used by this region
52594 * @return {Roo.TabPanel}
52596 getTabs : function(){
52600 createTool : function(parentEl, className){
52601 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52602 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52603 btn.addClassOnOver("x-layout-tools-button-over");
52608 * Ext JS Library 1.1.1
52609 * Copyright(c) 2006-2007, Ext JS, LLC.
52611 * Originally Released Under LGPL - original licence link has changed is not relivant.
52614 * <script type="text/javascript">
52620 * @class Roo.SplitLayoutRegion
52621 * @extends Roo.LayoutRegion
52622 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52624 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52625 this.cursor = cursor;
52626 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52629 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52630 splitTip : "Drag to resize.",
52631 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52632 useSplitTips : false,
52634 applyConfig : function(config){
52635 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52638 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52639 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52640 /** The SplitBar for this region
52641 * @type Roo.SplitBar */
52642 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52643 this.split.on("moved", this.onSplitMove, this);
52644 this.split.useShim = config.useShim === true;
52645 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52646 if(this.useSplitTips){
52647 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52649 if(config.collapsible){
52650 this.split.el.on("dblclick", this.collapse, this);
52653 if(typeof config.minSize != "undefined"){
52654 this.split.minSize = config.minSize;
52656 if(typeof config.maxSize != "undefined"){
52657 this.split.maxSize = config.maxSize;
52659 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52660 this.hideSplitter();
52665 getHMaxSize : function(){
52666 var cmax = this.config.maxSize || 10000;
52667 var center = this.mgr.getRegion("center");
52668 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52671 getVMaxSize : function(){
52672 var cmax = this.config.maxSize || 10000;
52673 var center = this.mgr.getRegion("center");
52674 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52677 onSplitMove : function(split, newSize){
52678 this.fireEvent("resized", this, newSize);
52682 * Returns the {@link Roo.SplitBar} for this region.
52683 * @return {Roo.SplitBar}
52685 getSplitBar : function(){
52690 this.hideSplitter();
52691 Roo.SplitLayoutRegion.superclass.hide.call(this);
52694 hideSplitter : function(){
52696 this.split.el.setLocation(-2000,-2000);
52697 this.split.el.hide();
52703 this.split.el.show();
52705 Roo.SplitLayoutRegion.superclass.show.call(this);
52708 beforeSlide: function(){
52709 if(Roo.isGecko){// firefox overflow auto bug workaround
52710 this.bodyEl.clip();
52712 this.tabs.bodyEl.clip();
52714 if(this.activePanel){
52715 this.activePanel.getEl().clip();
52717 if(this.activePanel.beforeSlide){
52718 this.activePanel.beforeSlide();
52724 afterSlide : function(){
52725 if(Roo.isGecko){// firefox overflow auto bug workaround
52726 this.bodyEl.unclip();
52728 this.tabs.bodyEl.unclip();
52730 if(this.activePanel){
52731 this.activePanel.getEl().unclip();
52732 if(this.activePanel.afterSlide){
52733 this.activePanel.afterSlide();
52739 initAutoHide : function(){
52740 if(this.autoHide !== false){
52741 if(!this.autoHideHd){
52742 var st = new Roo.util.DelayedTask(this.slideIn, this);
52743 this.autoHideHd = {
52744 "mouseout": function(e){
52745 if(!e.within(this.el, true)){
52749 "mouseover" : function(e){
52755 this.el.on(this.autoHideHd);
52759 clearAutoHide : function(){
52760 if(this.autoHide !== false){
52761 this.el.un("mouseout", this.autoHideHd.mouseout);
52762 this.el.un("mouseover", this.autoHideHd.mouseover);
52766 clearMonitor : function(){
52767 Roo.get(document).un("click", this.slideInIf, this);
52770 // these names are backwards but not changed for compat
52771 slideOut : function(){
52772 if(this.isSlid || this.el.hasActiveFx()){
52775 this.isSlid = true;
52776 if(this.collapseBtn){
52777 this.collapseBtn.hide();
52779 this.closeBtnState = this.closeBtn.getStyle('display');
52780 this.closeBtn.hide();
52782 this.stickBtn.show();
52785 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52786 this.beforeSlide();
52787 this.el.setStyle("z-index", 10001);
52788 this.el.slideIn(this.getSlideAnchor(), {
52789 callback: function(){
52791 this.initAutoHide();
52792 Roo.get(document).on("click", this.slideInIf, this);
52793 this.fireEvent("slideshow", this);
52800 afterSlideIn : function(){
52801 this.clearAutoHide();
52802 this.isSlid = false;
52803 this.clearMonitor();
52804 this.el.setStyle("z-index", "");
52805 if(this.collapseBtn){
52806 this.collapseBtn.show();
52808 this.closeBtn.setStyle('display', this.closeBtnState);
52810 this.stickBtn.hide();
52812 this.fireEvent("slidehide", this);
52815 slideIn : function(cb){
52816 if(!this.isSlid || this.el.hasActiveFx()){
52820 this.isSlid = false;
52821 this.beforeSlide();
52822 this.el.slideOut(this.getSlideAnchor(), {
52823 callback: function(){
52824 this.el.setLeftTop(-10000, -10000);
52826 this.afterSlideIn();
52834 slideInIf : function(e){
52835 if(!e.within(this.el)){
52840 animateCollapse : function(){
52841 this.beforeSlide();
52842 this.el.setStyle("z-index", 20000);
52843 var anchor = this.getSlideAnchor();
52844 this.el.slideOut(anchor, {
52845 callback : function(){
52846 this.el.setStyle("z-index", "");
52847 this.collapsedEl.slideIn(anchor, {duration:.3});
52849 this.el.setLocation(-10000,-10000);
52851 this.fireEvent("collapsed", this);
52858 animateExpand : function(){
52859 this.beforeSlide();
52860 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52861 this.el.setStyle("z-index", 20000);
52862 this.collapsedEl.hide({
52865 this.el.slideIn(this.getSlideAnchor(), {
52866 callback : function(){
52867 this.el.setStyle("z-index", "");
52870 this.split.el.show();
52872 this.fireEvent("invalidated", this);
52873 this.fireEvent("expanded", this);
52901 getAnchor : function(){
52902 return this.anchors[this.position];
52905 getCollapseAnchor : function(){
52906 return this.canchors[this.position];
52909 getSlideAnchor : function(){
52910 return this.sanchors[this.position];
52913 getAlignAdj : function(){
52914 var cm = this.cmargins;
52915 switch(this.position){
52931 getExpandAdj : function(){
52932 var c = this.collapsedEl, cm = this.cmargins;
52933 switch(this.position){
52935 return [-(cm.right+c.getWidth()+cm.left), 0];
52938 return [cm.right+c.getWidth()+cm.left, 0];
52941 return [0, -(cm.top+cm.bottom+c.getHeight())];
52944 return [0, cm.top+cm.bottom+c.getHeight()];
52950 * Ext JS Library 1.1.1
52951 * Copyright(c) 2006-2007, Ext JS, LLC.
52953 * Originally Released Under LGPL - original licence link has changed is not relivant.
52956 * <script type="text/javascript">
52959 * These classes are private internal classes
52961 Roo.CenterLayoutRegion = function(mgr, config){
52962 Roo.LayoutRegion.call(this, mgr, config, "center");
52963 this.visible = true;
52964 this.minWidth = config.minWidth || 20;
52965 this.minHeight = config.minHeight || 20;
52968 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52970 // center panel can't be hidden
52974 // center panel can't be hidden
52977 getMinWidth: function(){
52978 return this.minWidth;
52981 getMinHeight: function(){
52982 return this.minHeight;
52987 Roo.NorthLayoutRegion = function(mgr, config){
52988 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52990 this.split.placement = Roo.SplitBar.TOP;
52991 this.split.orientation = Roo.SplitBar.VERTICAL;
52992 this.split.el.addClass("x-layout-split-v");
52994 var size = config.initialSize || config.height;
52995 if(typeof size != "undefined"){
52996 this.el.setHeight(size);
52999 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53000 orientation: Roo.SplitBar.VERTICAL,
53001 getBox : function(){
53002 if(this.collapsed){
53003 return this.collapsedEl.getBox();
53005 var box = this.el.getBox();
53007 box.height += this.split.el.getHeight();
53012 updateBox : function(box){
53013 if(this.split && !this.collapsed){
53014 box.height -= this.split.el.getHeight();
53015 this.split.el.setLeft(box.x);
53016 this.split.el.setTop(box.y+box.height);
53017 this.split.el.setWidth(box.width);
53019 if(this.collapsed){
53020 this.updateBody(box.width, null);
53022 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53026 Roo.SouthLayoutRegion = function(mgr, config){
53027 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
53029 this.split.placement = Roo.SplitBar.BOTTOM;
53030 this.split.orientation = Roo.SplitBar.VERTICAL;
53031 this.split.el.addClass("x-layout-split-v");
53033 var size = config.initialSize || config.height;
53034 if(typeof size != "undefined"){
53035 this.el.setHeight(size);
53038 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
53039 orientation: Roo.SplitBar.VERTICAL,
53040 getBox : function(){
53041 if(this.collapsed){
53042 return this.collapsedEl.getBox();
53044 var box = this.el.getBox();
53046 var sh = this.split.el.getHeight();
53053 updateBox : function(box){
53054 if(this.split && !this.collapsed){
53055 var sh = this.split.el.getHeight();
53058 this.split.el.setLeft(box.x);
53059 this.split.el.setTop(box.y-sh);
53060 this.split.el.setWidth(box.width);
53062 if(this.collapsed){
53063 this.updateBody(box.width, null);
53065 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53069 Roo.EastLayoutRegion = function(mgr, config){
53070 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
53072 this.split.placement = Roo.SplitBar.RIGHT;
53073 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53074 this.split.el.addClass("x-layout-split-h");
53076 var size = config.initialSize || config.width;
53077 if(typeof size != "undefined"){
53078 this.el.setWidth(size);
53081 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
53082 orientation: Roo.SplitBar.HORIZONTAL,
53083 getBox : function(){
53084 if(this.collapsed){
53085 return this.collapsedEl.getBox();
53087 var box = this.el.getBox();
53089 var sw = this.split.el.getWidth();
53096 updateBox : function(box){
53097 if(this.split && !this.collapsed){
53098 var sw = this.split.el.getWidth();
53100 this.split.el.setLeft(box.x);
53101 this.split.el.setTop(box.y);
53102 this.split.el.setHeight(box.height);
53105 if(this.collapsed){
53106 this.updateBody(null, box.height);
53108 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53112 Roo.WestLayoutRegion = function(mgr, config){
53113 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
53115 this.split.placement = Roo.SplitBar.LEFT;
53116 this.split.orientation = Roo.SplitBar.HORIZONTAL;
53117 this.split.el.addClass("x-layout-split-h");
53119 var size = config.initialSize || config.width;
53120 if(typeof size != "undefined"){
53121 this.el.setWidth(size);
53124 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
53125 orientation: Roo.SplitBar.HORIZONTAL,
53126 getBox : function(){
53127 if(this.collapsed){
53128 return this.collapsedEl.getBox();
53130 var box = this.el.getBox();
53132 box.width += this.split.el.getWidth();
53137 updateBox : function(box){
53138 if(this.split && !this.collapsed){
53139 var sw = this.split.el.getWidth();
53141 this.split.el.setLeft(box.x+box.width);
53142 this.split.el.setTop(box.y);
53143 this.split.el.setHeight(box.height);
53145 if(this.collapsed){
53146 this.updateBody(null, box.height);
53148 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53153 * Ext JS Library 1.1.1
53154 * Copyright(c) 2006-2007, Ext JS, LLC.
53156 * Originally Released Under LGPL - original licence link has changed is not relivant.
53159 * <script type="text/javascript">
53164 * Private internal class for reading and applying state
53166 Roo.LayoutStateManager = function(layout){
53167 // default empty state
53176 Roo.LayoutStateManager.prototype = {
53177 init : function(layout, provider){
53178 this.provider = provider;
53179 var state = provider.get(layout.id+"-layout-state");
53181 var wasUpdating = layout.isUpdating();
53183 layout.beginUpdate();
53185 for(var key in state){
53186 if(typeof state[key] != "function"){
53187 var rstate = state[key];
53188 var r = layout.getRegion(key);
53191 r.resizeTo(rstate.size);
53193 if(rstate.collapsed == true){
53196 r.expand(null, true);
53202 layout.endUpdate();
53204 this.state = state;
53206 this.layout = layout;
53207 layout.on("regionresized", this.onRegionResized, this);
53208 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53209 layout.on("regionexpanded", this.onRegionExpanded, this);
53212 storeState : function(){
53213 this.provider.set(this.layout.id+"-layout-state", this.state);
53216 onRegionResized : function(region, newSize){
53217 this.state[region.getPosition()].size = newSize;
53221 onRegionCollapsed : function(region){
53222 this.state[region.getPosition()].collapsed = true;
53226 onRegionExpanded : function(region){
53227 this.state[region.getPosition()].collapsed = false;
53232 * Ext JS Library 1.1.1
53233 * Copyright(c) 2006-2007, Ext JS, LLC.
53235 * Originally Released Under LGPL - original licence link has changed is not relivant.
53238 * <script type="text/javascript">
53241 * @class Roo.ContentPanel
53242 * @extends Roo.util.Observable
53243 * A basic ContentPanel element.
53244 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53245 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53246 * @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
53247 * @cfg {Boolean} closable True if the panel can be closed/removed
53248 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53249 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53250 * @cfg {Toolbar} toolbar A toolbar for this panel
53251 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53252 * @cfg {String} title The title for this panel
53253 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53254 * @cfg {String} url Calls {@link #setUrl} with this value
53255 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53256 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53257 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53258 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53261 * Create a new ContentPanel.
53262 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53263 * @param {String/Object} config A string to set only the title or a config object
53264 * @param {String} content (optional) Set the HTML content for this panel
53265 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53267 Roo.ContentPanel = function(el, config, content){
53271 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53275 if (config && config.parentLayout) {
53276 el = config.parentLayout.el.createChild();
53279 if(el.autoCreate){ // xtype is available if this is called from factory
53283 this.el = Roo.get(el);
53284 if(!this.el && config && config.autoCreate){
53285 if(typeof config.autoCreate == "object"){
53286 if(!config.autoCreate.id){
53287 config.autoCreate.id = config.id||el;
53289 this.el = Roo.DomHelper.append(document.body,
53290 config.autoCreate, true);
53292 this.el = Roo.DomHelper.append(document.body,
53293 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53296 this.closable = false;
53297 this.loaded = false;
53298 this.active = false;
53299 if(typeof config == "string"){
53300 this.title = config;
53302 Roo.apply(this, config);
53305 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53306 this.wrapEl = this.el.wrap();
53307 this.toolbar.container = this.el.insertSibling(false, 'before');
53308 this.toolbar = new Roo.Toolbar(this.toolbar);
53311 // xtype created footer. - not sure if will work as we normally have to render first..
53312 if (this.footer && !this.footer.el && this.footer.xtype) {
53313 if (!this.wrapEl) {
53314 this.wrapEl = this.el.wrap();
53317 this.footer.container = this.wrapEl.createChild();
53319 this.footer = Roo.factory(this.footer, Roo);
53324 this.resizeEl = Roo.get(this.resizeEl, true);
53326 this.resizeEl = this.el;
53328 // handle view.xtype
53336 * Fires when this panel is activated.
53337 * @param {Roo.ContentPanel} this
53341 * @event deactivate
53342 * Fires when this panel is activated.
53343 * @param {Roo.ContentPanel} this
53345 "deactivate" : true,
53349 * Fires when this panel is resized if fitToFrame is true.
53350 * @param {Roo.ContentPanel} this
53351 * @param {Number} width The width after any component adjustments
53352 * @param {Number} height The height after any component adjustments
53358 * Fires when this tab is created
53359 * @param {Roo.ContentPanel} this
53370 if(this.autoScroll){
53371 this.resizeEl.setStyle("overflow", "auto");
53373 // fix randome scrolling
53374 this.el.on('scroll', function() {
53375 Roo.log('fix random scolling');
53376 this.scrollTo('top',0);
53379 content = content || this.content;
53381 this.setContent(content);
53383 if(config && config.url){
53384 this.setUrl(this.url, this.params, this.loadOnce);
53389 Roo.ContentPanel.superclass.constructor.call(this);
53391 if (this.view && typeof(this.view.xtype) != 'undefined') {
53392 this.view.el = this.el.appendChild(document.createElement("div"));
53393 this.view = Roo.factory(this.view);
53394 this.view.render && this.view.render(false, '');
53398 this.fireEvent('render', this);
53401 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53403 setRegion : function(region){
53404 this.region = region;
53406 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53408 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53413 * Returns the toolbar for this Panel if one was configured.
53414 * @return {Roo.Toolbar}
53416 getToolbar : function(){
53417 return this.toolbar;
53420 setActiveState : function(active){
53421 this.active = active;
53423 this.fireEvent("deactivate", this);
53425 this.fireEvent("activate", this);
53429 * Updates this panel's element
53430 * @param {String} content The new content
53431 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53433 setContent : function(content, loadScripts){
53434 this.el.update(content, loadScripts);
53437 ignoreResize : function(w, h){
53438 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53441 this.lastSize = {width: w, height: h};
53446 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53447 * @return {Roo.UpdateManager} The UpdateManager
53449 getUpdateManager : function(){
53450 return this.el.getUpdateManager();
53453 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53454 * @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:
53457 url: "your-url.php",
53458 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53459 callback: yourFunction,
53460 scope: yourObject, //(optional scope)
53463 text: "Loading...",
53468 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53469 * 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.
53470 * @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}
53471 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53472 * @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.
53473 * @return {Roo.ContentPanel} this
53476 var um = this.el.getUpdateManager();
53477 um.update.apply(um, arguments);
53483 * 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.
53484 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53485 * @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)
53486 * @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)
53487 * @return {Roo.UpdateManager} The UpdateManager
53489 setUrl : function(url, params, loadOnce){
53490 if(this.refreshDelegate){
53491 this.removeListener("activate", this.refreshDelegate);
53493 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53494 this.on("activate", this.refreshDelegate);
53495 return this.el.getUpdateManager();
53498 _handleRefresh : function(url, params, loadOnce){
53499 if(!loadOnce || !this.loaded){
53500 var updater = this.el.getUpdateManager();
53501 updater.update(url, params, this._setLoaded.createDelegate(this));
53505 _setLoaded : function(){
53506 this.loaded = true;
53510 * Returns this panel's id
53513 getId : function(){
53518 * Returns this panel's element - used by regiosn to add.
53519 * @return {Roo.Element}
53521 getEl : function(){
53522 return this.wrapEl || this.el;
53525 adjustForComponents : function(width, height)
53527 //Roo.log('adjustForComponents ');
53528 if(this.resizeEl != this.el){
53529 width -= this.el.getFrameWidth('lr');
53530 height -= this.el.getFrameWidth('tb');
53533 var te = this.toolbar.getEl();
53534 height -= te.getHeight();
53535 te.setWidth(width);
53538 var te = this.footer.getEl();
53539 Roo.log("footer:" + te.getHeight());
53541 height -= te.getHeight();
53542 te.setWidth(width);
53546 if(this.adjustments){
53547 width += this.adjustments[0];
53548 height += this.adjustments[1];
53550 return {"width": width, "height": height};
53553 setSize : function(width, height){
53554 if(this.fitToFrame && !this.ignoreResize(width, height)){
53555 if(this.fitContainer && this.resizeEl != this.el){
53556 this.el.setSize(width, height);
53558 var size = this.adjustForComponents(width, height);
53559 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53560 this.fireEvent('resize', this, size.width, size.height);
53565 * Returns this panel's title
53568 getTitle : function(){
53573 * Set this panel's title
53574 * @param {String} title
53576 setTitle : function(title){
53577 this.title = title;
53579 this.region.updatePanelTitle(this, title);
53584 * Returns true is this panel was configured to be closable
53585 * @return {Boolean}
53587 isClosable : function(){
53588 return this.closable;
53591 beforeSlide : function(){
53593 this.resizeEl.clip();
53596 afterSlide : function(){
53598 this.resizeEl.unclip();
53602 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53603 * Will fail silently if the {@link #setUrl} method has not been called.
53604 * This does not activate the panel, just updates its content.
53606 refresh : function(){
53607 if(this.refreshDelegate){
53608 this.loaded = false;
53609 this.refreshDelegate();
53614 * Destroys this panel
53616 destroy : function(){
53617 this.el.removeAllListeners();
53618 var tempEl = document.createElement("span");
53619 tempEl.appendChild(this.el.dom);
53620 tempEl.innerHTML = "";
53626 * form - if the content panel contains a form - this is a reference to it.
53627 * @type {Roo.form.Form}
53631 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53632 * This contains a reference to it.
53638 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53648 * @param {Object} cfg Xtype definition of item to add.
53651 addxtype : function(cfg) {
53653 if (cfg.xtype.match(/^Form$/)) {
53656 //if (this.footer) {
53657 // el = this.footer.container.insertSibling(false, 'before');
53659 el = this.el.createChild();
53662 this.form = new Roo.form.Form(cfg);
53665 if ( this.form.allItems.length) {
53666 this.form.render(el.dom);
53670 // should only have one of theses..
53671 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53672 // views.. should not be just added - used named prop 'view''
53674 cfg.el = this.el.appendChild(document.createElement("div"));
53677 var ret = new Roo.factory(cfg);
53679 ret.render && ret.render(false, ''); // render blank..
53688 * @class Roo.GridPanel
53689 * @extends Roo.ContentPanel
53691 * Create a new GridPanel.
53692 * @param {Roo.grid.Grid} grid The grid for this panel
53693 * @param {String/Object} config A string to set only the panel's title, or a config object
53695 Roo.GridPanel = function(grid, config){
53698 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53699 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53701 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53703 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53706 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53708 // xtype created footer. - not sure if will work as we normally have to render first..
53709 if (this.footer && !this.footer.el && this.footer.xtype) {
53711 this.footer.container = this.grid.getView().getFooterPanel(true);
53712 this.footer.dataSource = this.grid.dataSource;
53713 this.footer = Roo.factory(this.footer, Roo);
53717 grid.monitorWindowResize = false; // turn off autosizing
53718 grid.autoHeight = false;
53719 grid.autoWidth = false;
53721 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53724 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53725 getId : function(){
53726 return this.grid.id;
53730 * Returns the grid for this panel
53731 * @return {Roo.grid.Grid}
53733 getGrid : function(){
53737 setSize : function(width, height){
53738 if(!this.ignoreResize(width, height)){
53739 var grid = this.grid;
53740 var size = this.adjustForComponents(width, height);
53741 grid.getGridEl().setSize(size.width, size.height);
53746 beforeSlide : function(){
53747 this.grid.getView().scroller.clip();
53750 afterSlide : function(){
53751 this.grid.getView().scroller.unclip();
53754 destroy : function(){
53755 this.grid.destroy();
53757 Roo.GridPanel.superclass.destroy.call(this);
53763 * @class Roo.NestedLayoutPanel
53764 * @extends Roo.ContentPanel
53766 * Create a new NestedLayoutPanel.
53769 * @param {Roo.BorderLayout} layout The layout for this panel
53770 * @param {String/Object} config A string to set only the title or a config object
53772 Roo.NestedLayoutPanel = function(layout, config)
53774 // construct with only one argument..
53775 /* FIXME - implement nicer consturctors
53776 if (layout.layout) {
53778 layout = config.layout;
53779 delete config.layout;
53781 if (layout.xtype && !layout.getEl) {
53782 // then layout needs constructing..
53783 layout = Roo.factory(layout, Roo);
53788 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53790 layout.monitorWindowResize = false; // turn off autosizing
53791 this.layout = layout;
53792 this.layout.getEl().addClass("x-layout-nested-layout");
53799 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53801 setSize : function(width, height){
53802 if(!this.ignoreResize(width, height)){
53803 var size = this.adjustForComponents(width, height);
53804 var el = this.layout.getEl();
53805 el.setSize(size.width, size.height);
53806 var touch = el.dom.offsetWidth;
53807 this.layout.layout();
53808 // ie requires a double layout on the first pass
53809 if(Roo.isIE && !this.initialized){
53810 this.initialized = true;
53811 this.layout.layout();
53816 // activate all subpanels if not currently active..
53818 setActiveState : function(active){
53819 this.active = active;
53821 this.fireEvent("deactivate", this);
53825 this.fireEvent("activate", this);
53826 // not sure if this should happen before or after..
53827 if (!this.layout) {
53828 return; // should not happen..
53831 for (var r in this.layout.regions) {
53832 reg = this.layout.getRegion(r);
53833 if (reg.getActivePanel()) {
53834 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53835 reg.setActivePanel(reg.getActivePanel());
53838 if (!reg.panels.length) {
53841 reg.showPanel(reg.getPanel(0));
53850 * Returns the nested BorderLayout for this panel
53851 * @return {Roo.BorderLayout}
53853 getLayout : function(){
53854 return this.layout;
53858 * Adds a xtype elements to the layout of the nested panel
53862 xtype : 'ContentPanel',
53869 xtype : 'NestedLayoutPanel',
53875 items : [ ... list of content panels or nested layout panels.. ]
53879 * @param {Object} cfg Xtype definition of item to add.
53881 addxtype : function(cfg) {
53882 return this.layout.addxtype(cfg);
53887 Roo.ScrollPanel = function(el, config, content){
53888 config = config || {};
53889 config.fitToFrame = true;
53890 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53892 this.el.dom.style.overflow = "hidden";
53893 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53894 this.el.removeClass("x-layout-inactive-content");
53895 this.el.on("mousewheel", this.onWheel, this);
53897 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53898 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53899 up.unselectable(); down.unselectable();
53900 up.on("click", this.scrollUp, this);
53901 down.on("click", this.scrollDown, this);
53902 up.addClassOnOver("x-scroller-btn-over");
53903 down.addClassOnOver("x-scroller-btn-over");
53904 up.addClassOnClick("x-scroller-btn-click");
53905 down.addClassOnClick("x-scroller-btn-click");
53906 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53908 this.resizeEl = this.el;
53909 this.el = wrap; this.up = up; this.down = down;
53912 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53914 wheelIncrement : 5,
53915 scrollUp : function(){
53916 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53919 scrollDown : function(){
53920 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53923 afterScroll : function(){
53924 var el = this.resizeEl;
53925 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53926 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53927 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53930 setSize : function(){
53931 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53932 this.afterScroll();
53935 onWheel : function(e){
53936 var d = e.getWheelDelta();
53937 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53938 this.afterScroll();
53942 setContent : function(content, loadScripts){
53943 this.resizeEl.update(content, loadScripts);
53957 * @class Roo.TreePanel
53958 * @extends Roo.ContentPanel
53960 * Create a new TreePanel. - defaults to fit/scoll contents.
53961 * @param {String/Object} config A string to set only the panel's title, or a config object
53962 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53964 Roo.TreePanel = function(config){
53965 var el = config.el;
53966 var tree = config.tree;
53967 delete config.tree;
53968 delete config.el; // hopefull!
53970 // wrapper for IE7 strict & safari scroll issue
53972 var treeEl = el.createChild();
53973 config.resizeEl = treeEl;
53977 Roo.TreePanel.superclass.constructor.call(this, el, config);
53980 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53981 //console.log(tree);
53982 this.on('activate', function()
53984 if (this.tree.rendered) {
53987 //console.log('render tree');
53988 this.tree.render();
53990 // this should not be needed.. - it's actually the 'el' that resizes?
53991 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53993 //this.on('resize', function (cp, w, h) {
53994 // this.tree.innerCt.setWidth(w);
53995 // this.tree.innerCt.setHeight(h);
53996 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54003 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
54020 * Ext JS Library 1.1.1
54021 * Copyright(c) 2006-2007, Ext JS, LLC.
54023 * Originally Released Under LGPL - original licence link has changed is not relivant.
54026 * <script type="text/javascript">
54031 * @class Roo.ReaderLayout
54032 * @extends Roo.BorderLayout
54033 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
54034 * center region containing two nested regions (a top one for a list view and one for item preview below),
54035 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
54036 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
54037 * expedites the setup of the overall layout and regions for this common application style.
54040 var reader = new Roo.ReaderLayout();
54041 var CP = Roo.ContentPanel; // shortcut for adding
54043 reader.beginUpdate();
54044 reader.add("north", new CP("north", "North"));
54045 reader.add("west", new CP("west", {title: "West"}));
54046 reader.add("east", new CP("east", {title: "East"}));
54048 reader.regions.listView.add(new CP("listView", "List"));
54049 reader.regions.preview.add(new CP("preview", "Preview"));
54050 reader.endUpdate();
54053 * Create a new ReaderLayout
54054 * @param {Object} config Configuration options
54055 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
54056 * document.body if omitted)
54058 Roo.ReaderLayout = function(config, renderTo){
54059 var c = config || {size:{}};
54060 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
54061 north: c.north !== false ? Roo.apply({
54065 }, c.north) : false,
54066 west: c.west !== false ? Roo.apply({
54074 margins:{left:5,right:0,bottom:5,top:5},
54075 cmargins:{left:5,right:5,bottom:5,top:5}
54076 }, c.west) : false,
54077 east: c.east !== false ? Roo.apply({
54085 margins:{left:0,right:5,bottom:5,top:5},
54086 cmargins:{left:5,right:5,bottom:5,top:5}
54087 }, c.east) : false,
54088 center: Roo.apply({
54089 tabPosition: 'top',
54093 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
54097 this.el.addClass('x-reader');
54099 this.beginUpdate();
54101 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
54102 south: c.preview !== false ? Roo.apply({
54109 cmargins:{top:5,left:0, right:0, bottom:0}
54110 }, c.preview) : false,
54111 center: Roo.apply({
54117 this.add('center', new Roo.NestedLayoutPanel(inner,
54118 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
54122 this.regions.preview = inner.getRegion('south');
54123 this.regions.listView = inner.getRegion('center');
54126 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
54128 * Ext JS Library 1.1.1
54129 * Copyright(c) 2006-2007, Ext JS, LLC.
54131 * Originally Released Under LGPL - original licence link has changed is not relivant.
54134 * <script type="text/javascript">
54138 * @class Roo.grid.Grid
54139 * @extends Roo.util.Observable
54140 * This class represents the primary interface of a component based grid control.
54141 * <br><br>Usage:<pre><code>
54142 var grid = new Roo.grid.Grid("my-container-id", {
54145 selModel: mySelectionModel,
54146 autoSizeColumns: true,
54147 monitorWindowResize: false,
54148 trackMouseOver: true
54153 * <b>Common Problems:</b><br/>
54154 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54155 * element will correct this<br/>
54156 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54157 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54158 * are unpredictable.<br/>
54159 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54160 * grid to calculate dimensions/offsets.<br/>
54162 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54163 * The container MUST have some type of size defined for the grid to fill. The container will be
54164 * automatically set to position relative if it isn't already.
54165 * @param {Object} config A config object that sets properties on this grid.
54167 Roo.grid.Grid = function(container, config){
54168 // initialize the container
54169 this.container = Roo.get(container);
54170 this.container.update("");
54171 this.container.setStyle("overflow", "hidden");
54172 this.container.addClass('x-grid-container');
54174 this.id = this.container.id;
54176 Roo.apply(this, config);
54177 // check and correct shorthanded configs
54179 this.dataSource = this.ds;
54183 this.colModel = this.cm;
54187 this.selModel = this.sm;
54191 if (this.selModel) {
54192 this.selModel = Roo.factory(this.selModel, Roo.grid);
54193 this.sm = this.selModel;
54194 this.sm.xmodule = this.xmodule || false;
54196 if (typeof(this.colModel.config) == 'undefined') {
54197 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54198 this.cm = this.colModel;
54199 this.cm.xmodule = this.xmodule || false;
54201 if (this.dataSource) {
54202 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54203 this.ds = this.dataSource;
54204 this.ds.xmodule = this.xmodule || false;
54211 this.container.setWidth(this.width);
54215 this.container.setHeight(this.height);
54222 * The raw click event for the entire grid.
54223 * @param {Roo.EventObject} e
54228 * The raw dblclick event for the entire grid.
54229 * @param {Roo.EventObject} e
54233 * @event contextmenu
54234 * The raw contextmenu event for the entire grid.
54235 * @param {Roo.EventObject} e
54237 "contextmenu" : true,
54240 * The raw mousedown event for the entire grid.
54241 * @param {Roo.EventObject} e
54243 "mousedown" : true,
54246 * The raw mouseup event for the entire grid.
54247 * @param {Roo.EventObject} e
54252 * The raw mouseover event for the entire grid.
54253 * @param {Roo.EventObject} e
54255 "mouseover" : true,
54258 * The raw mouseout event for the entire grid.
54259 * @param {Roo.EventObject} e
54264 * The raw keypress event for the entire grid.
54265 * @param {Roo.EventObject} e
54270 * The raw keydown event for the entire grid.
54271 * @param {Roo.EventObject} e
54279 * Fires when a cell is clicked
54280 * @param {Grid} this
54281 * @param {Number} rowIndex
54282 * @param {Number} columnIndex
54283 * @param {Roo.EventObject} e
54285 "cellclick" : true,
54287 * @event celldblclick
54288 * Fires when a cell is double clicked
54289 * @param {Grid} this
54290 * @param {Number} rowIndex
54291 * @param {Number} columnIndex
54292 * @param {Roo.EventObject} e
54294 "celldblclick" : true,
54297 * Fires when a row is clicked
54298 * @param {Grid} this
54299 * @param {Number} rowIndex
54300 * @param {Roo.EventObject} e
54304 * @event rowdblclick
54305 * Fires when a row is double clicked
54306 * @param {Grid} this
54307 * @param {Number} rowIndex
54308 * @param {Roo.EventObject} e
54310 "rowdblclick" : true,
54312 * @event headerclick
54313 * Fires when a header is clicked
54314 * @param {Grid} this
54315 * @param {Number} columnIndex
54316 * @param {Roo.EventObject} e
54318 "headerclick" : true,
54320 * @event headerdblclick
54321 * Fires when a header cell is double clicked
54322 * @param {Grid} this
54323 * @param {Number} columnIndex
54324 * @param {Roo.EventObject} e
54326 "headerdblclick" : true,
54328 * @event rowcontextmenu
54329 * Fires when a row is right clicked
54330 * @param {Grid} this
54331 * @param {Number} rowIndex
54332 * @param {Roo.EventObject} e
54334 "rowcontextmenu" : true,
54336 * @event cellcontextmenu
54337 * Fires when a cell is right clicked
54338 * @param {Grid} this
54339 * @param {Number} rowIndex
54340 * @param {Number} cellIndex
54341 * @param {Roo.EventObject} e
54343 "cellcontextmenu" : true,
54345 * @event headercontextmenu
54346 * Fires when a header is right clicked
54347 * @param {Grid} this
54348 * @param {Number} columnIndex
54349 * @param {Roo.EventObject} e
54351 "headercontextmenu" : true,
54353 * @event bodyscroll
54354 * Fires when the body element is scrolled
54355 * @param {Number} scrollLeft
54356 * @param {Number} scrollTop
54358 "bodyscroll" : true,
54360 * @event columnresize
54361 * Fires when the user resizes a column
54362 * @param {Number} columnIndex
54363 * @param {Number} newSize
54365 "columnresize" : true,
54367 * @event columnmove
54368 * Fires when the user moves a column
54369 * @param {Number} oldIndex
54370 * @param {Number} newIndex
54372 "columnmove" : true,
54375 * Fires when row(s) start being dragged
54376 * @param {Grid} this
54377 * @param {Roo.GridDD} dd The drag drop object
54378 * @param {event} e The raw browser event
54380 "startdrag" : true,
54383 * Fires when a drag operation is complete
54384 * @param {Grid} this
54385 * @param {Roo.GridDD} dd The drag drop object
54386 * @param {event} e The raw browser event
54391 * Fires when dragged row(s) are dropped on a valid DD target
54392 * @param {Grid} this
54393 * @param {Roo.GridDD} dd The drag drop object
54394 * @param {String} targetId The target drag drop object
54395 * @param {event} e The raw browser event
54400 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54401 * @param {Grid} this
54402 * @param {Roo.GridDD} dd The drag drop object
54403 * @param {String} targetId The target drag drop object
54404 * @param {event} e The raw browser event
54409 * Fires when the dragged row(s) first cross another DD target while being dragged
54410 * @param {Grid} this
54411 * @param {Roo.GridDD} dd The drag drop object
54412 * @param {String} targetId The target drag drop object
54413 * @param {event} e The raw browser event
54415 "dragenter" : true,
54418 * Fires when the dragged row(s) leave another DD target while being dragged
54419 * @param {Grid} this
54420 * @param {Roo.GridDD} dd The drag drop object
54421 * @param {String} targetId The target drag drop object
54422 * @param {event} e The raw browser event
54427 * Fires when a row is rendered, so you can change add a style to it.
54428 * @param {GridView} gridview The grid view
54429 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54435 * Fires when the grid is rendered
54436 * @param {Grid} grid
54441 Roo.grid.Grid.superclass.constructor.call(this);
54443 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54446 * @cfg {String} ddGroup - drag drop group.
54450 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54452 minColumnWidth : 25,
54455 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54456 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54457 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54459 autoSizeColumns : false,
54462 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54464 autoSizeHeaders : true,
54467 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54469 monitorWindowResize : true,
54472 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54473 * rows measured to get a columns size. Default is 0 (all rows).
54475 maxRowsToMeasure : 0,
54478 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54480 trackMouseOver : true,
54483 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54487 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54489 enableDragDrop : false,
54492 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54494 enableColumnMove : true,
54497 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54499 enableColumnHide : true,
54502 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54504 enableRowHeightSync : false,
54507 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54512 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54514 autoHeight : false,
54517 * @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.
54519 autoExpandColumn : false,
54522 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54525 autoExpandMin : 50,
54528 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54530 autoExpandMax : 1000,
54533 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54538 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54542 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54552 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54553 * of a fixed width. Default is false.
54556 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54559 * Called once after all setup has been completed and the grid is ready to be rendered.
54560 * @return {Roo.grid.Grid} this
54562 render : function()
54564 var c = this.container;
54565 // try to detect autoHeight/width mode
54566 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54567 this.autoHeight = true;
54569 var view = this.getView();
54572 c.on("click", this.onClick, this);
54573 c.on("dblclick", this.onDblClick, this);
54574 c.on("contextmenu", this.onContextMenu, this);
54575 c.on("keydown", this.onKeyDown, this);
54577 c.on("touchstart", this.onTouchStart, this);
54580 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54582 this.getSelectionModel().init(this);
54587 this.loadMask = new Roo.LoadMask(this.container,
54588 Roo.apply({store:this.dataSource}, this.loadMask));
54592 if (this.toolbar && this.toolbar.xtype) {
54593 this.toolbar.container = this.getView().getHeaderPanel(true);
54594 this.toolbar = new Roo.Toolbar(this.toolbar);
54596 if (this.footer && this.footer.xtype) {
54597 this.footer.dataSource = this.getDataSource();
54598 this.footer.container = this.getView().getFooterPanel(true);
54599 this.footer = Roo.factory(this.footer, Roo);
54601 if (this.dropTarget && this.dropTarget.xtype) {
54602 delete this.dropTarget.xtype;
54603 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54607 this.rendered = true;
54608 this.fireEvent('render', this);
54613 * Reconfigures the grid to use a different Store and Column Model.
54614 * The View will be bound to the new objects and refreshed.
54615 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54616 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54618 reconfigure : function(dataSource, colModel){
54620 this.loadMask.destroy();
54621 this.loadMask = new Roo.LoadMask(this.container,
54622 Roo.apply({store:dataSource}, this.loadMask));
54624 this.view.bind(dataSource, colModel);
54625 this.dataSource = dataSource;
54626 this.colModel = colModel;
54627 this.view.refresh(true);
54631 onKeyDown : function(e){
54632 this.fireEvent("keydown", e);
54636 * Destroy this grid.
54637 * @param {Boolean} removeEl True to remove the element
54639 destroy : function(removeEl, keepListeners){
54641 this.loadMask.destroy();
54643 var c = this.container;
54644 c.removeAllListeners();
54645 this.view.destroy();
54646 this.colModel.purgeListeners();
54647 if(!keepListeners){
54648 this.purgeListeners();
54651 if(removeEl === true){
54657 processEvent : function(name, e){
54658 // does this fire select???
54659 //Roo.log('grid:processEvent ' + name);
54661 if (name != 'touchstart' ) {
54662 this.fireEvent(name, e);
54665 var t = e.getTarget();
54667 var header = v.findHeaderIndex(t);
54668 if(header !== false){
54669 var ename = name == 'touchstart' ? 'click' : name;
54671 this.fireEvent("header" + ename, this, header, e);
54673 var row = v.findRowIndex(t);
54674 var cell = v.findCellIndex(t);
54675 if (name == 'touchstart') {
54676 // first touch is always a click.
54677 // hopefull this happens after selection is updated.?
54680 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54681 var cs = this.selModel.getSelectedCell();
54682 if (row == cs[0] && cell == cs[1]){
54686 if (typeof(this.selModel.getSelections) != 'undefined') {
54687 var cs = this.selModel.getSelections();
54688 var ds = this.dataSource;
54689 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54700 this.fireEvent("row" + name, this, row, e);
54701 if(cell !== false){
54702 this.fireEvent("cell" + name, this, row, cell, e);
54709 onClick : function(e){
54710 this.processEvent("click", e);
54713 onTouchStart : function(e){
54714 this.processEvent("touchstart", e);
54718 onContextMenu : function(e, t){
54719 this.processEvent("contextmenu", e);
54723 onDblClick : function(e){
54724 this.processEvent("dblclick", e);
54728 walkCells : function(row, col, step, fn, scope){
54729 var cm = this.colModel, clen = cm.getColumnCount();
54730 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54742 if(fn.call(scope || this, row, col, cm) === true){
54760 if(fn.call(scope || this, row, col, cm) === true){
54772 getSelections : function(){
54773 return this.selModel.getSelections();
54777 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54778 * but if manual update is required this method will initiate it.
54780 autoSize : function(){
54782 this.view.layout();
54783 if(this.view.adjustForScroll){
54784 this.view.adjustForScroll();
54790 * Returns the grid's underlying element.
54791 * @return {Element} The element
54793 getGridEl : function(){
54794 return this.container;
54797 // private for compatibility, overridden by editor grid
54798 stopEditing : function(){},
54801 * Returns the grid's SelectionModel.
54802 * @return {SelectionModel}
54804 getSelectionModel : function(){
54805 if(!this.selModel){
54806 this.selModel = new Roo.grid.RowSelectionModel();
54808 return this.selModel;
54812 * Returns the grid's DataSource.
54813 * @return {DataSource}
54815 getDataSource : function(){
54816 return this.dataSource;
54820 * Returns the grid's ColumnModel.
54821 * @return {ColumnModel}
54823 getColumnModel : function(){
54824 return this.colModel;
54828 * Returns the grid's GridView object.
54829 * @return {GridView}
54831 getView : function(){
54833 this.view = new Roo.grid.GridView(this.viewConfig);
54838 * Called to get grid's drag proxy text, by default returns this.ddText.
54841 getDragDropText : function(){
54842 var count = this.selModel.getCount();
54843 return String.format(this.ddText, count, count == 1 ? '' : 's');
54847 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54848 * %0 is replaced with the number of selected rows.
54851 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54853 * Ext JS Library 1.1.1
54854 * Copyright(c) 2006-2007, Ext JS, LLC.
54856 * Originally Released Under LGPL - original licence link has changed is not relivant.
54859 * <script type="text/javascript">
54862 Roo.grid.AbstractGridView = function(){
54866 "beforerowremoved" : true,
54867 "beforerowsinserted" : true,
54868 "beforerefresh" : true,
54869 "rowremoved" : true,
54870 "rowsinserted" : true,
54871 "rowupdated" : true,
54874 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54877 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54878 rowClass : "x-grid-row",
54879 cellClass : "x-grid-cell",
54880 tdClass : "x-grid-td",
54881 hdClass : "x-grid-hd",
54882 splitClass : "x-grid-hd-split",
54884 init: function(grid){
54886 var cid = this.grid.getGridEl().id;
54887 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54888 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54889 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54890 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54893 getColumnRenderers : function(){
54894 var renderers = [];
54895 var cm = this.grid.colModel;
54896 var colCount = cm.getColumnCount();
54897 for(var i = 0; i < colCount; i++){
54898 renderers[i] = cm.getRenderer(i);
54903 getColumnIds : function(){
54905 var cm = this.grid.colModel;
54906 var colCount = cm.getColumnCount();
54907 for(var i = 0; i < colCount; i++){
54908 ids[i] = cm.getColumnId(i);
54913 getDataIndexes : function(){
54914 if(!this.indexMap){
54915 this.indexMap = this.buildIndexMap();
54917 return this.indexMap.colToData;
54920 getColumnIndexByDataIndex : function(dataIndex){
54921 if(!this.indexMap){
54922 this.indexMap = this.buildIndexMap();
54924 return this.indexMap.dataToCol[dataIndex];
54928 * Set a css style for a column dynamically.
54929 * @param {Number} colIndex The index of the column
54930 * @param {String} name The css property name
54931 * @param {String} value The css value
54933 setCSSStyle : function(colIndex, name, value){
54934 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54935 Roo.util.CSS.updateRule(selector, name, value);
54938 generateRules : function(cm){
54939 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54940 Roo.util.CSS.removeStyleSheet(rulesId);
54941 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54942 var cid = cm.getColumnId(i);
54943 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54944 this.tdSelector, cid, " {\n}\n",
54945 this.hdSelector, cid, " {\n}\n",
54946 this.splitSelector, cid, " {\n}\n");
54948 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54952 * Ext JS Library 1.1.1
54953 * Copyright(c) 2006-2007, Ext JS, LLC.
54955 * Originally Released Under LGPL - original licence link has changed is not relivant.
54958 * <script type="text/javascript">
54962 // This is a support class used internally by the Grid components
54963 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54965 this.view = grid.getView();
54966 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54967 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54969 this.setHandleElId(Roo.id(hd));
54970 this.setOuterHandleElId(Roo.id(hd2));
54972 this.scroll = false;
54974 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54976 getDragData : function(e){
54977 var t = Roo.lib.Event.getTarget(e);
54978 var h = this.view.findHeaderCell(t);
54980 return {ddel: h.firstChild, header:h};
54985 onInitDrag : function(e){
54986 this.view.headersDisabled = true;
54987 var clone = this.dragData.ddel.cloneNode(true);
54988 clone.id = Roo.id();
54989 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54990 this.proxy.update(clone);
54994 afterValidDrop : function(){
54996 setTimeout(function(){
54997 v.headersDisabled = false;
55001 afterInvalidDrop : function(){
55003 setTimeout(function(){
55004 v.headersDisabled = false;
55010 * Ext JS Library 1.1.1
55011 * Copyright(c) 2006-2007, Ext JS, LLC.
55013 * Originally Released Under LGPL - original licence link has changed is not relivant.
55016 * <script type="text/javascript">
55019 // This is a support class used internally by the Grid components
55020 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
55022 this.view = grid.getView();
55023 // split the proxies so they don't interfere with mouse events
55024 this.proxyTop = Roo.DomHelper.append(document.body, {
55025 cls:"col-move-top", html:" "
55027 this.proxyBottom = Roo.DomHelper.append(document.body, {
55028 cls:"col-move-bottom", html:" "
55030 this.proxyTop.hide = this.proxyBottom.hide = function(){
55031 this.setLeftTop(-100,-100);
55032 this.setStyle("visibility", "hidden");
55034 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55035 // temporarily disabled
55036 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
55037 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
55039 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
55040 proxyOffsets : [-4, -9],
55041 fly: Roo.Element.fly,
55043 getTargetFromEvent : function(e){
55044 var t = Roo.lib.Event.getTarget(e);
55045 var cindex = this.view.findCellIndex(t);
55046 if(cindex !== false){
55047 return this.view.getHeaderCell(cindex);
55052 nextVisible : function(h){
55053 var v = this.view, cm = this.grid.colModel;
55056 if(!cm.isHidden(v.getCellIndex(h))){
55064 prevVisible : function(h){
55065 var v = this.view, cm = this.grid.colModel;
55068 if(!cm.isHidden(v.getCellIndex(h))){
55076 positionIndicator : function(h, n, e){
55077 var x = Roo.lib.Event.getPageX(e);
55078 var r = Roo.lib.Dom.getRegion(n.firstChild);
55079 var px, pt, py = r.top + this.proxyOffsets[1];
55080 if((r.right - x) <= (r.right-r.left)/2){
55081 px = r.right+this.view.borderWidth;
55087 var oldIndex = this.view.getCellIndex(h);
55088 var newIndex = this.view.getCellIndex(n);
55090 if(this.grid.colModel.isFixed(newIndex)){
55094 var locked = this.grid.colModel.isLocked(newIndex);
55099 if(oldIndex < newIndex){
55102 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
55105 px += this.proxyOffsets[0];
55106 this.proxyTop.setLeftTop(px, py);
55107 this.proxyTop.show();
55108 if(!this.bottomOffset){
55109 this.bottomOffset = this.view.mainHd.getHeight();
55111 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
55112 this.proxyBottom.show();
55116 onNodeEnter : function(n, dd, e, data){
55117 if(data.header != n){
55118 this.positionIndicator(data.header, n, e);
55122 onNodeOver : function(n, dd, e, data){
55123 var result = false;
55124 if(data.header != n){
55125 result = this.positionIndicator(data.header, n, e);
55128 this.proxyTop.hide();
55129 this.proxyBottom.hide();
55131 return result ? this.dropAllowed : this.dropNotAllowed;
55134 onNodeOut : function(n, dd, e, data){
55135 this.proxyTop.hide();
55136 this.proxyBottom.hide();
55139 onNodeDrop : function(n, dd, e, data){
55140 var h = data.header;
55142 var cm = this.grid.colModel;
55143 var x = Roo.lib.Event.getPageX(e);
55144 var r = Roo.lib.Dom.getRegion(n.firstChild);
55145 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55146 var oldIndex = this.view.getCellIndex(h);
55147 var newIndex = this.view.getCellIndex(n);
55148 var locked = cm.isLocked(newIndex);
55152 if(oldIndex < newIndex){
55155 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55158 cm.setLocked(oldIndex, locked, true);
55159 cm.moveColumn(oldIndex, newIndex);
55160 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55168 * Ext JS Library 1.1.1
55169 * Copyright(c) 2006-2007, Ext JS, LLC.
55171 * Originally Released Under LGPL - original licence link has changed is not relivant.
55174 * <script type="text/javascript">
55178 * @class Roo.grid.GridView
55179 * @extends Roo.util.Observable
55182 * @param {Object} config
55184 Roo.grid.GridView = function(config){
55185 Roo.grid.GridView.superclass.constructor.call(this);
55188 Roo.apply(this, config);
55191 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55193 unselectable : 'unselectable="on"',
55194 unselectableCls : 'x-unselectable',
55197 rowClass : "x-grid-row",
55199 cellClass : "x-grid-col",
55201 tdClass : "x-grid-td",
55203 hdClass : "x-grid-hd",
55205 splitClass : "x-grid-split",
55207 sortClasses : ["sort-asc", "sort-desc"],
55209 enableMoveAnim : false,
55213 dh : Roo.DomHelper,
55215 fly : Roo.Element.fly,
55217 css : Roo.util.CSS,
55223 scrollIncrement : 22,
55225 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55227 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55229 bind : function(ds, cm){
55231 this.ds.un("load", this.onLoad, this);
55232 this.ds.un("datachanged", this.onDataChange, this);
55233 this.ds.un("add", this.onAdd, this);
55234 this.ds.un("remove", this.onRemove, this);
55235 this.ds.un("update", this.onUpdate, this);
55236 this.ds.un("clear", this.onClear, this);
55239 ds.on("load", this.onLoad, this);
55240 ds.on("datachanged", this.onDataChange, this);
55241 ds.on("add", this.onAdd, this);
55242 ds.on("remove", this.onRemove, this);
55243 ds.on("update", this.onUpdate, this);
55244 ds.on("clear", this.onClear, this);
55249 this.cm.un("widthchange", this.onColWidthChange, this);
55250 this.cm.un("headerchange", this.onHeaderChange, this);
55251 this.cm.un("hiddenchange", this.onHiddenChange, this);
55252 this.cm.un("columnmoved", this.onColumnMove, this);
55253 this.cm.un("columnlockchange", this.onColumnLock, this);
55256 this.generateRules(cm);
55257 cm.on("widthchange", this.onColWidthChange, this);
55258 cm.on("headerchange", this.onHeaderChange, this);
55259 cm.on("hiddenchange", this.onHiddenChange, this);
55260 cm.on("columnmoved", this.onColumnMove, this);
55261 cm.on("columnlockchange", this.onColumnLock, this);
55266 init: function(grid){
55267 Roo.grid.GridView.superclass.init.call(this, grid);
55269 this.bind(grid.dataSource, grid.colModel);
55271 grid.on("headerclick", this.handleHeaderClick, this);
55273 if(grid.trackMouseOver){
55274 grid.on("mouseover", this.onRowOver, this);
55275 grid.on("mouseout", this.onRowOut, this);
55277 grid.cancelTextSelection = function(){};
55278 this.gridId = grid.id;
55280 var tpls = this.templates || {};
55283 tpls.master = new Roo.Template(
55284 '<div class="x-grid" hidefocus="true">',
55285 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55286 '<div class="x-grid-topbar"></div>',
55287 '<div class="x-grid-scroller"><div></div></div>',
55288 '<div class="x-grid-locked">',
55289 '<div class="x-grid-header">{lockedHeader}</div>',
55290 '<div class="x-grid-body">{lockedBody}</div>',
55292 '<div class="x-grid-viewport">',
55293 '<div class="x-grid-header">{header}</div>',
55294 '<div class="x-grid-body">{body}</div>',
55296 '<div class="x-grid-bottombar"></div>',
55298 '<div class="x-grid-resize-proxy"> </div>',
55301 tpls.master.disableformats = true;
55305 tpls.header = new Roo.Template(
55306 '<table border="0" cellspacing="0" cellpadding="0">',
55307 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55310 tpls.header.disableformats = true;
55312 tpls.header.compile();
55315 tpls.hcell = new Roo.Template(
55316 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55317 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55320 tpls.hcell.disableFormats = true;
55322 tpls.hcell.compile();
55325 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55326 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55327 tpls.hsplit.disableFormats = true;
55329 tpls.hsplit.compile();
55332 tpls.body = new Roo.Template(
55333 '<table border="0" cellspacing="0" cellpadding="0">',
55334 "<tbody>{rows}</tbody>",
55337 tpls.body.disableFormats = true;
55339 tpls.body.compile();
55342 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55343 tpls.row.disableFormats = true;
55345 tpls.row.compile();
55348 tpls.cell = new Roo.Template(
55349 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55350 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55351 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55354 tpls.cell.disableFormats = true;
55356 tpls.cell.compile();
55358 this.templates = tpls;
55361 // remap these for backwards compat
55362 onColWidthChange : function(){
55363 this.updateColumns.apply(this, arguments);
55365 onHeaderChange : function(){
55366 this.updateHeaders.apply(this, arguments);
55368 onHiddenChange : function(){
55369 this.handleHiddenChange.apply(this, arguments);
55371 onColumnMove : function(){
55372 this.handleColumnMove.apply(this, arguments);
55374 onColumnLock : function(){
55375 this.handleLockChange.apply(this, arguments);
55378 onDataChange : function(){
55380 this.updateHeaderSortState();
55383 onClear : function(){
55387 onUpdate : function(ds, record){
55388 this.refreshRow(record);
55391 refreshRow : function(record){
55392 var ds = this.ds, index;
55393 if(typeof record == 'number'){
55395 record = ds.getAt(index);
55397 index = ds.indexOf(record);
55399 this.insertRows(ds, index, index, true);
55400 this.onRemove(ds, record, index+1, true);
55401 this.syncRowHeights(index, index);
55403 this.fireEvent("rowupdated", this, index, record);
55406 onAdd : function(ds, records, index){
55407 this.insertRows(ds, index, index + (records.length-1));
55410 onRemove : function(ds, record, index, isUpdate){
55411 if(isUpdate !== true){
55412 this.fireEvent("beforerowremoved", this, index, record);
55414 var bt = this.getBodyTable(), lt = this.getLockedTable();
55415 if(bt.rows[index]){
55416 bt.firstChild.removeChild(bt.rows[index]);
55418 if(lt.rows[index]){
55419 lt.firstChild.removeChild(lt.rows[index]);
55421 if(isUpdate !== true){
55422 this.stripeRows(index);
55423 this.syncRowHeights(index, index);
55425 this.fireEvent("rowremoved", this, index, record);
55429 onLoad : function(){
55430 this.scrollToTop();
55434 * Scrolls the grid to the top
55436 scrollToTop : function(){
55438 this.scroller.dom.scrollTop = 0;
55444 * Gets a panel in the header of the grid that can be used for toolbars etc.
55445 * After modifying the contents of this panel a call to grid.autoSize() may be
55446 * required to register any changes in size.
55447 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55448 * @return Roo.Element
55450 getHeaderPanel : function(doShow){
55452 this.headerPanel.show();
55454 return this.headerPanel;
55458 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55459 * After modifying the contents of this panel a call to grid.autoSize() may be
55460 * required to register any changes in size.
55461 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55462 * @return Roo.Element
55464 getFooterPanel : function(doShow){
55466 this.footerPanel.show();
55468 return this.footerPanel;
55471 initElements : function(){
55472 var E = Roo.Element;
55473 var el = this.grid.getGridEl().dom.firstChild;
55474 var cs = el.childNodes;
55476 this.el = new E(el);
55478 this.focusEl = new E(el.firstChild);
55479 this.focusEl.swallowEvent("click", true);
55481 this.headerPanel = new E(cs[1]);
55482 this.headerPanel.enableDisplayMode("block");
55484 this.scroller = new E(cs[2]);
55485 this.scrollSizer = new E(this.scroller.dom.firstChild);
55487 this.lockedWrap = new E(cs[3]);
55488 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55489 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55491 this.mainWrap = new E(cs[4]);
55492 this.mainHd = new E(this.mainWrap.dom.firstChild);
55493 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55495 this.footerPanel = new E(cs[5]);
55496 this.footerPanel.enableDisplayMode("block");
55498 this.resizeProxy = new E(cs[6]);
55500 this.headerSelector = String.format(
55501 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55502 this.lockedHd.id, this.mainHd.id
55505 this.splitterSelector = String.format(
55506 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55507 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55510 idToCssName : function(s)
55512 return s.replace(/[^a-z0-9]+/ig, '-');
55515 getHeaderCell : function(index){
55516 return Roo.DomQuery.select(this.headerSelector)[index];
55519 getHeaderCellMeasure : function(index){
55520 return this.getHeaderCell(index).firstChild;
55523 getHeaderCellText : function(index){
55524 return this.getHeaderCell(index).firstChild.firstChild;
55527 getLockedTable : function(){
55528 return this.lockedBody.dom.firstChild;
55531 getBodyTable : function(){
55532 return this.mainBody.dom.firstChild;
55535 getLockedRow : function(index){
55536 return this.getLockedTable().rows[index];
55539 getRow : function(index){
55540 return this.getBodyTable().rows[index];
55543 getRowComposite : function(index){
55545 this.rowEl = new Roo.CompositeElementLite();
55547 var els = [], lrow, mrow;
55548 if(lrow = this.getLockedRow(index)){
55551 if(mrow = this.getRow(index)){
55554 this.rowEl.elements = els;
55558 * Gets the 'td' of the cell
55560 * @param {Integer} rowIndex row to select
55561 * @param {Integer} colIndex column to select
55565 getCell : function(rowIndex, colIndex){
55566 var locked = this.cm.getLockedCount();
55568 if(colIndex < locked){
55569 source = this.lockedBody.dom.firstChild;
55571 source = this.mainBody.dom.firstChild;
55572 colIndex -= locked;
55574 return source.rows[rowIndex].childNodes[colIndex];
55577 getCellText : function(rowIndex, colIndex){
55578 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55581 getCellBox : function(cell){
55582 var b = this.fly(cell).getBox();
55583 if(Roo.isOpera){ // opera fails to report the Y
55584 b.y = cell.offsetTop + this.mainBody.getY();
55589 getCellIndex : function(cell){
55590 var id = String(cell.className).match(this.cellRE);
55592 return parseInt(id[1], 10);
55597 findHeaderIndex : function(n){
55598 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55599 return r ? this.getCellIndex(r) : false;
55602 findHeaderCell : function(n){
55603 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55604 return r ? r : false;
55607 findRowIndex : function(n){
55611 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55612 return r ? r.rowIndex : false;
55615 findCellIndex : function(node){
55616 var stop = this.el.dom;
55617 while(node && node != stop){
55618 if(this.findRE.test(node.className)){
55619 return this.getCellIndex(node);
55621 node = node.parentNode;
55626 getColumnId : function(index){
55627 return this.cm.getColumnId(index);
55630 getSplitters : function()
55632 if(this.splitterSelector){
55633 return Roo.DomQuery.select(this.splitterSelector);
55639 getSplitter : function(index){
55640 return this.getSplitters()[index];
55643 onRowOver : function(e, t){
55645 if((row = this.findRowIndex(t)) !== false){
55646 this.getRowComposite(row).addClass("x-grid-row-over");
55650 onRowOut : function(e, t){
55652 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55653 this.getRowComposite(row).removeClass("x-grid-row-over");
55657 renderHeaders : function(){
55659 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55660 var cb = [], lb = [], sb = [], lsb = [], p = {};
55661 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55662 p.cellId = "x-grid-hd-0-" + i;
55663 p.splitId = "x-grid-csplit-0-" + i;
55664 p.id = cm.getColumnId(i);
55665 p.value = cm.getColumnHeader(i) || "";
55666 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55667 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55668 if(!cm.isLocked(i)){
55669 cb[cb.length] = ct.apply(p);
55670 sb[sb.length] = st.apply(p);
55672 lb[lb.length] = ct.apply(p);
55673 lsb[lsb.length] = st.apply(p);
55676 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55677 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55680 updateHeaders : function(){
55681 var html = this.renderHeaders();
55682 this.lockedHd.update(html[0]);
55683 this.mainHd.update(html[1]);
55687 * Focuses the specified row.
55688 * @param {Number} row The row index
55690 focusRow : function(row)
55692 //Roo.log('GridView.focusRow');
55693 var x = this.scroller.dom.scrollLeft;
55694 this.focusCell(row, 0, false);
55695 this.scroller.dom.scrollLeft = x;
55699 * Focuses the specified cell.
55700 * @param {Number} row The row index
55701 * @param {Number} col The column index
55702 * @param {Boolean} hscroll false to disable horizontal scrolling
55704 focusCell : function(row, col, hscroll)
55706 //Roo.log('GridView.focusCell');
55707 var el = this.ensureVisible(row, col, hscroll);
55708 this.focusEl.alignTo(el, "tl-tl");
55710 this.focusEl.focus();
55712 this.focusEl.focus.defer(1, this.focusEl);
55717 * Scrolls the specified cell into view
55718 * @param {Number} row The row index
55719 * @param {Number} col The column index
55720 * @param {Boolean} hscroll false to disable horizontal scrolling
55722 ensureVisible : function(row, col, hscroll)
55724 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55725 //return null; //disable for testing.
55726 if(typeof row != "number"){
55727 row = row.rowIndex;
55729 if(row < 0 && row >= this.ds.getCount()){
55732 col = (col !== undefined ? col : 0);
55733 var cm = this.grid.colModel;
55734 while(cm.isHidden(col)){
55738 var el = this.getCell(row, col);
55742 var c = this.scroller.dom;
55744 var ctop = parseInt(el.offsetTop, 10);
55745 var cleft = parseInt(el.offsetLeft, 10);
55746 var cbot = ctop + el.offsetHeight;
55747 var cright = cleft + el.offsetWidth;
55749 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55750 var stop = parseInt(c.scrollTop, 10);
55751 var sleft = parseInt(c.scrollLeft, 10);
55752 var sbot = stop + ch;
55753 var sright = sleft + c.clientWidth;
55755 Roo.log('GridView.ensureVisible:' +
55757 ' c.clientHeight:' + c.clientHeight +
55758 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55766 c.scrollTop = ctop;
55767 //Roo.log("set scrolltop to ctop DISABLE?");
55768 }else if(cbot > sbot){
55769 //Roo.log("set scrolltop to cbot-ch");
55770 c.scrollTop = cbot-ch;
55773 if(hscroll !== false){
55775 c.scrollLeft = cleft;
55776 }else if(cright > sright){
55777 c.scrollLeft = cright-c.clientWidth;
55784 updateColumns : function(){
55785 this.grid.stopEditing();
55786 var cm = this.grid.colModel, colIds = this.getColumnIds();
55787 //var totalWidth = cm.getTotalWidth();
55789 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55790 //if(cm.isHidden(i)) continue;
55791 var w = cm.getColumnWidth(i);
55792 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55793 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55795 this.updateSplitters();
55798 generateRules : function(cm){
55799 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55800 Roo.util.CSS.removeStyleSheet(rulesId);
55801 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55802 var cid = cm.getColumnId(i);
55804 if(cm.config[i].align){
55805 align = 'text-align:'+cm.config[i].align+';';
55808 if(cm.isHidden(i)){
55809 hidden = 'display:none;';
55811 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55813 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55814 this.hdSelector, cid, " {\n", align, width, "}\n",
55815 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55816 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55818 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55821 updateSplitters : function(){
55822 var cm = this.cm, s = this.getSplitters();
55823 if(s){ // splitters not created yet
55824 var pos = 0, locked = true;
55825 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55826 if(cm.isHidden(i)) {
55829 var w = cm.getColumnWidth(i); // make sure it's a number
55830 if(!cm.isLocked(i) && locked){
55835 s[i].style.left = (pos-this.splitOffset) + "px";
55840 handleHiddenChange : function(colModel, colIndex, hidden){
55842 this.hideColumn(colIndex);
55844 this.unhideColumn(colIndex);
55848 hideColumn : function(colIndex){
55849 var cid = this.getColumnId(colIndex);
55850 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55851 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55853 this.updateHeaders();
55855 this.updateSplitters();
55859 unhideColumn : function(colIndex){
55860 var cid = this.getColumnId(colIndex);
55861 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55862 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55865 this.updateHeaders();
55867 this.updateSplitters();
55871 insertRows : function(dm, firstRow, lastRow, isUpdate){
55872 if(firstRow == 0 && lastRow == dm.getCount()-1){
55876 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55878 var s = this.getScrollState();
55879 var markup = this.renderRows(firstRow, lastRow);
55880 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55881 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55882 this.restoreScroll(s);
55884 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55885 this.syncRowHeights(firstRow, lastRow);
55886 this.stripeRows(firstRow);
55892 bufferRows : function(markup, target, index){
55893 var before = null, trows = target.rows, tbody = target.tBodies[0];
55894 if(index < trows.length){
55895 before = trows[index];
55897 var b = document.createElement("div");
55898 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55899 var rows = b.firstChild.rows;
55900 for(var i = 0, len = rows.length; i < len; i++){
55902 tbody.insertBefore(rows[0], before);
55904 tbody.appendChild(rows[0]);
55911 deleteRows : function(dm, firstRow, lastRow){
55912 if(dm.getRowCount()<1){
55913 this.fireEvent("beforerefresh", this);
55914 this.mainBody.update("");
55915 this.lockedBody.update("");
55916 this.fireEvent("refresh", this);
55918 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55919 var bt = this.getBodyTable();
55920 var tbody = bt.firstChild;
55921 var rows = bt.rows;
55922 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55923 tbody.removeChild(rows[firstRow]);
55925 this.stripeRows(firstRow);
55926 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55930 updateRows : function(dataSource, firstRow, lastRow){
55931 var s = this.getScrollState();
55933 this.restoreScroll(s);
55936 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55940 this.updateHeaderSortState();
55943 getScrollState : function(){
55945 var sb = this.scroller.dom;
55946 return {left: sb.scrollLeft, top: sb.scrollTop};
55949 stripeRows : function(startRow){
55950 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55953 startRow = startRow || 0;
55954 var rows = this.getBodyTable().rows;
55955 var lrows = this.getLockedTable().rows;
55956 var cls = ' x-grid-row-alt ';
55957 for(var i = startRow, len = rows.length; i < len; i++){
55958 var row = rows[i], lrow = lrows[i];
55959 var isAlt = ((i+1) % 2 == 0);
55960 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55961 if(isAlt == hasAlt){
55965 row.className += " x-grid-row-alt";
55967 row.className = row.className.replace("x-grid-row-alt", "");
55970 lrow.className = row.className;
55975 restoreScroll : function(state){
55976 //Roo.log('GridView.restoreScroll');
55977 var sb = this.scroller.dom;
55978 sb.scrollLeft = state.left;
55979 sb.scrollTop = state.top;
55983 syncScroll : function(){
55984 //Roo.log('GridView.syncScroll');
55985 var sb = this.scroller.dom;
55986 var sh = this.mainHd.dom;
55987 var bs = this.mainBody.dom;
55988 var lv = this.lockedBody.dom;
55989 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55990 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55993 handleScroll : function(e){
55995 var sb = this.scroller.dom;
55996 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
56000 handleWheel : function(e){
56001 var d = e.getWheelDelta();
56002 this.scroller.dom.scrollTop -= d*22;
56003 // set this here to prevent jumpy scrolling on large tables
56004 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
56008 renderRows : function(startRow, endRow){
56009 // pull in all the crap needed to render rows
56010 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
56011 var colCount = cm.getColumnCount();
56013 if(ds.getCount() < 1){
56017 // build a map for all the columns
56019 for(var i = 0; i < colCount; i++){
56020 var name = cm.getDataIndex(i);
56022 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
56023 renderer : cm.getRenderer(i),
56024 id : cm.getColumnId(i),
56025 locked : cm.isLocked(i),
56026 has_editor : cm.isCellEditable(i)
56030 startRow = startRow || 0;
56031 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
56033 // records to render
56034 var rs = ds.getRange(startRow, endRow);
56036 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
56039 // As much as I hate to duplicate code, this was branched because FireFox really hates
56040 // [].join("") on strings. The performance difference was substantial enough to
56041 // branch this function
56042 doRender : Roo.isGecko ?
56043 function(cs, rs, ds, startRow, colCount, stripe){
56044 var ts = this.templates, ct = ts.cell, rt = ts.row;
56046 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56048 var hasListener = this.grid.hasListener('rowclass');
56050 for(var j = 0, len = rs.length; j < len; j++){
56051 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
56052 for(var i = 0; i < colCount; i++){
56054 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56056 p.css = p.attr = "";
56057 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56058 if(p.value == undefined || p.value === "") {
56059 p.value = " ";
56062 p.css += ' x-grid-editable-cell';
56064 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
56065 p.css += ' x-grid-dirty-cell';
56067 var markup = ct.apply(p);
56075 if(stripe && ((rowIndex+1) % 2 == 0)){
56076 alt.push("x-grid-row-alt")
56079 alt.push( " x-grid-dirty-row");
56082 if(this.getRowClass){
56083 alt.push(this.getRowClass(r, rowIndex));
56089 rowIndex : rowIndex,
56092 this.grid.fireEvent('rowclass', this, rowcfg);
56093 alt.push(rowcfg.rowClass);
56095 rp.alt = alt.join(" ");
56096 lbuf+= rt.apply(rp);
56098 buf+= rt.apply(rp);
56100 return [lbuf, buf];
56102 function(cs, rs, ds, startRow, colCount, stripe){
56103 var ts = this.templates, ct = ts.cell, rt = ts.row;
56105 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
56106 var hasListener = this.grid.hasListener('rowclass');
56109 for(var j = 0, len = rs.length; j < len; j++){
56110 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
56111 for(var i = 0; i < colCount; i++){
56113 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
56115 p.css = p.attr = "";
56116 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
56117 if(p.value == undefined || p.value === "") {
56118 p.value = " ";
56122 p.css += ' x-grid-editable-cell';
56124 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
56125 p.css += ' x-grid-dirty-cell'
56128 var markup = ct.apply(p);
56130 cb[cb.length] = markup;
56132 lcb[lcb.length] = markup;
56136 if(stripe && ((rowIndex+1) % 2 == 0)){
56137 alt.push( "x-grid-row-alt");
56140 alt.push(" x-grid-dirty-row");
56143 if(this.getRowClass){
56144 alt.push( this.getRowClass(r, rowIndex));
56150 rowIndex : rowIndex,
56153 this.grid.fireEvent('rowclass', this, rowcfg);
56154 alt.push(rowcfg.rowClass);
56157 rp.alt = alt.join(" ");
56158 rp.cells = lcb.join("");
56159 lbuf[lbuf.length] = rt.apply(rp);
56160 rp.cells = cb.join("");
56161 buf[buf.length] = rt.apply(rp);
56163 return [lbuf.join(""), buf.join("")];
56166 renderBody : function(){
56167 var markup = this.renderRows();
56168 var bt = this.templates.body;
56169 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56173 * Refreshes the grid
56174 * @param {Boolean} headersToo
56176 refresh : function(headersToo){
56177 this.fireEvent("beforerefresh", this);
56178 this.grid.stopEditing();
56179 var result = this.renderBody();
56180 this.lockedBody.update(result[0]);
56181 this.mainBody.update(result[1]);
56182 if(headersToo === true){
56183 this.updateHeaders();
56184 this.updateColumns();
56185 this.updateSplitters();
56186 this.updateHeaderSortState();
56188 this.syncRowHeights();
56190 this.fireEvent("refresh", this);
56193 handleColumnMove : function(cm, oldIndex, newIndex){
56194 this.indexMap = null;
56195 var s = this.getScrollState();
56196 this.refresh(true);
56197 this.restoreScroll(s);
56198 this.afterMove(newIndex);
56201 afterMove : function(colIndex){
56202 if(this.enableMoveAnim && Roo.enableFx){
56203 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56205 // if multisort - fix sortOrder, and reload..
56206 if (this.grid.dataSource.multiSort) {
56207 // the we can call sort again..
56208 var dm = this.grid.dataSource;
56209 var cm = this.grid.colModel;
56211 for(var i = 0; i < cm.config.length; i++ ) {
56213 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56214 continue; // dont' bother, it's not in sort list or being set.
56217 so.push(cm.config[i].dataIndex);
56220 dm.load(dm.lastOptions);
56227 updateCell : function(dm, rowIndex, dataIndex){
56228 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56229 if(typeof colIndex == "undefined"){ // not present in grid
56232 var cm = this.grid.colModel;
56233 var cell = this.getCell(rowIndex, colIndex);
56234 var cellText = this.getCellText(rowIndex, colIndex);
56237 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56238 id : cm.getColumnId(colIndex),
56239 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56241 var renderer = cm.getRenderer(colIndex);
56242 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56243 if(typeof val == "undefined" || val === "") {
56246 cellText.innerHTML = val;
56247 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56248 this.syncRowHeights(rowIndex, rowIndex);
56251 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56253 if(this.grid.autoSizeHeaders){
56254 var h = this.getHeaderCellMeasure(colIndex);
56255 maxWidth = Math.max(maxWidth, h.scrollWidth);
56258 if(this.cm.isLocked(colIndex)){
56259 tb = this.getLockedTable();
56262 tb = this.getBodyTable();
56263 index = colIndex - this.cm.getLockedCount();
56266 var rows = tb.rows;
56267 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56268 for(var i = 0; i < stopIndex; i++){
56269 var cell = rows[i].childNodes[index].firstChild;
56270 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56273 return maxWidth + /*margin for error in IE*/ 5;
56276 * Autofit a column to its content.
56277 * @param {Number} colIndex
56278 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56280 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56281 if(this.cm.isHidden(colIndex)){
56282 return; // can't calc a hidden column
56285 var cid = this.cm.getColumnId(colIndex);
56286 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56287 if(this.grid.autoSizeHeaders){
56288 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56291 var newWidth = this.calcColumnWidth(colIndex);
56292 this.cm.setColumnWidth(colIndex,
56293 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56294 if(!suppressEvent){
56295 this.grid.fireEvent("columnresize", colIndex, newWidth);
56300 * Autofits all columns to their content and then expands to fit any extra space in the grid
56302 autoSizeColumns : function(){
56303 var cm = this.grid.colModel;
56304 var colCount = cm.getColumnCount();
56305 for(var i = 0; i < colCount; i++){
56306 this.autoSizeColumn(i, true, true);
56308 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56311 this.updateColumns();
56317 * Autofits all columns to the grid's width proportionate with their current size
56318 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56320 fitColumns : function(reserveScrollSpace){
56321 var cm = this.grid.colModel;
56322 var colCount = cm.getColumnCount();
56326 for (i = 0; i < colCount; i++){
56327 if(!cm.isHidden(i) && !cm.isFixed(i)){
56328 w = cm.getColumnWidth(i);
56334 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56335 if(reserveScrollSpace){
56338 var frac = (avail - cm.getTotalWidth())/width;
56339 while (cols.length){
56342 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56344 this.updateColumns();
56348 onRowSelect : function(rowIndex){
56349 var row = this.getRowComposite(rowIndex);
56350 row.addClass("x-grid-row-selected");
56353 onRowDeselect : function(rowIndex){
56354 var row = this.getRowComposite(rowIndex);
56355 row.removeClass("x-grid-row-selected");
56358 onCellSelect : function(row, col){
56359 var cell = this.getCell(row, col);
56361 Roo.fly(cell).addClass("x-grid-cell-selected");
56365 onCellDeselect : function(row, col){
56366 var cell = this.getCell(row, col);
56368 Roo.fly(cell).removeClass("x-grid-cell-selected");
56372 updateHeaderSortState : function(){
56374 // sort state can be single { field: xxx, direction : yyy}
56375 // or { xxx=>ASC , yyy : DESC ..... }
56378 if (!this.ds.multiSort) {
56379 var state = this.ds.getSortState();
56383 mstate[state.field] = state.direction;
56384 // FIXME... - this is not used here.. but might be elsewhere..
56385 this.sortState = state;
56388 mstate = this.ds.sortToggle;
56390 //remove existing sort classes..
56392 var sc = this.sortClasses;
56393 var hds = this.el.select(this.headerSelector).removeClass(sc);
56395 for(var f in mstate) {
56397 var sortColumn = this.cm.findColumnIndex(f);
56399 if(sortColumn != -1){
56400 var sortDir = mstate[f];
56401 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56410 handleHeaderClick : function(g, index,e){
56412 Roo.log("header click");
56415 // touch events on header are handled by context
56416 this.handleHdCtx(g,index,e);
56421 if(this.headersDisabled){
56424 var dm = g.dataSource, cm = g.colModel;
56425 if(!cm.isSortable(index)){
56430 if (dm.multiSort) {
56431 // update the sortOrder
56433 for(var i = 0; i < cm.config.length; i++ ) {
56435 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56436 continue; // dont' bother, it's not in sort list or being set.
56439 so.push(cm.config[i].dataIndex);
56445 dm.sort(cm.getDataIndex(index));
56449 destroy : function(){
56451 this.colMenu.removeAll();
56452 Roo.menu.MenuMgr.unregister(this.colMenu);
56453 this.colMenu.getEl().remove();
56454 delete this.colMenu;
56457 this.hmenu.removeAll();
56458 Roo.menu.MenuMgr.unregister(this.hmenu);
56459 this.hmenu.getEl().remove();
56462 if(this.grid.enableColumnMove){
56463 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56465 for(var dd in dds){
56466 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56467 var elid = dds[dd].dragElId;
56469 Roo.get(elid).remove();
56470 } else if(dds[dd].config.isTarget){
56471 dds[dd].proxyTop.remove();
56472 dds[dd].proxyBottom.remove();
56475 if(Roo.dd.DDM.locationCache[dd]){
56476 delete Roo.dd.DDM.locationCache[dd];
56479 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56482 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56483 this.bind(null, null);
56484 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56487 handleLockChange : function(){
56488 this.refresh(true);
56491 onDenyColumnLock : function(){
56495 onDenyColumnHide : function(){
56499 handleHdMenuClick : function(item){
56500 var index = this.hdCtxIndex;
56501 var cm = this.cm, ds = this.ds;
56504 ds.sort(cm.getDataIndex(index), "ASC");
56507 ds.sort(cm.getDataIndex(index), "DESC");
56510 var lc = cm.getLockedCount();
56511 if(cm.getColumnCount(true) <= lc+1){
56512 this.onDenyColumnLock();
56516 cm.setLocked(index, true, true);
56517 cm.moveColumn(index, lc);
56518 this.grid.fireEvent("columnmove", index, lc);
56520 cm.setLocked(index, true);
56524 var lc = cm.getLockedCount();
56525 if((lc-1) != index){
56526 cm.setLocked(index, false, true);
56527 cm.moveColumn(index, lc-1);
56528 this.grid.fireEvent("columnmove", index, lc-1);
56530 cm.setLocked(index, false);
56533 case 'wider': // used to expand cols on touch..
56535 var cw = cm.getColumnWidth(index);
56536 cw += (item.id == 'wider' ? 1 : -1) * 50;
56537 cw = Math.max(0, cw);
56538 cw = Math.min(cw,4000);
56539 cm.setColumnWidth(index, cw);
56543 index = cm.getIndexById(item.id.substr(4));
56545 if(item.checked && cm.getColumnCount(true) <= 1){
56546 this.onDenyColumnHide();
56549 cm.setHidden(index, item.checked);
56555 beforeColMenuShow : function(){
56556 var cm = this.cm, colCount = cm.getColumnCount();
56557 this.colMenu.removeAll();
56558 for(var i = 0; i < colCount; i++){
56559 this.colMenu.add(new Roo.menu.CheckItem({
56560 id: "col-"+cm.getColumnId(i),
56561 text: cm.getColumnHeader(i),
56562 checked: !cm.isHidden(i),
56568 handleHdCtx : function(g, index, e){
56570 var hd = this.getHeaderCell(index);
56571 this.hdCtxIndex = index;
56572 var ms = this.hmenu.items, cm = this.cm;
56573 ms.get("asc").setDisabled(!cm.isSortable(index));
56574 ms.get("desc").setDisabled(!cm.isSortable(index));
56575 if(this.grid.enableColLock !== false){
56576 ms.get("lock").setDisabled(cm.isLocked(index));
56577 ms.get("unlock").setDisabled(!cm.isLocked(index));
56579 this.hmenu.show(hd, "tl-bl");
56582 handleHdOver : function(e){
56583 var hd = this.findHeaderCell(e.getTarget());
56584 if(hd && !this.headersDisabled){
56585 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56586 this.fly(hd).addClass("x-grid-hd-over");
56591 handleHdOut : function(e){
56592 var hd = this.findHeaderCell(e.getTarget());
56594 this.fly(hd).removeClass("x-grid-hd-over");
56598 handleSplitDblClick : function(e, t){
56599 var i = this.getCellIndex(t);
56600 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56601 this.autoSizeColumn(i, true);
56606 render : function(){
56609 var colCount = cm.getColumnCount();
56611 if(this.grid.monitorWindowResize === true){
56612 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56614 var header = this.renderHeaders();
56615 var body = this.templates.body.apply({rows:""});
56616 var html = this.templates.master.apply({
56619 lockedHeader: header[0],
56623 //this.updateColumns();
56625 this.grid.getGridEl().dom.innerHTML = html;
56627 this.initElements();
56629 // a kludge to fix the random scolling effect in webkit
56630 this.el.on("scroll", function() {
56631 this.el.dom.scrollTop=0; // hopefully not recursive..
56634 this.scroller.on("scroll", this.handleScroll, this);
56635 this.lockedBody.on("mousewheel", this.handleWheel, this);
56636 this.mainBody.on("mousewheel", this.handleWheel, this);
56638 this.mainHd.on("mouseover", this.handleHdOver, this);
56639 this.mainHd.on("mouseout", this.handleHdOut, this);
56640 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56641 {delegate: "."+this.splitClass});
56643 this.lockedHd.on("mouseover", this.handleHdOver, this);
56644 this.lockedHd.on("mouseout", this.handleHdOut, this);
56645 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56646 {delegate: "."+this.splitClass});
56648 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56649 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56652 this.updateSplitters();
56654 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56655 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56656 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56659 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56660 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56662 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56663 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56665 if(this.grid.enableColLock !== false){
56666 this.hmenu.add('-',
56667 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56668 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56672 this.hmenu.add('-',
56673 {id:"wider", text: this.columnsWiderText},
56674 {id:"narrow", text: this.columnsNarrowText }
56680 if(this.grid.enableColumnHide !== false){
56682 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56683 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56684 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56686 this.hmenu.add('-',
56687 {id:"columns", text: this.columnsText, menu: this.colMenu}
56690 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56692 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56695 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56696 this.dd = new Roo.grid.GridDragZone(this.grid, {
56697 ddGroup : this.grid.ddGroup || 'GridDD'
56703 for(var i = 0; i < colCount; i++){
56704 if(cm.isHidden(i)){
56705 this.hideColumn(i);
56707 if(cm.config[i].align){
56708 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56709 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56713 this.updateHeaderSortState();
56715 this.beforeInitialResize();
56718 // two part rendering gives faster view to the user
56719 this.renderPhase2.defer(1, this);
56722 renderPhase2 : function(){
56723 // render the rows now
56725 if(this.grid.autoSizeColumns){
56726 this.autoSizeColumns();
56730 beforeInitialResize : function(){
56734 onColumnSplitterMoved : function(i, w){
56735 this.userResized = true;
56736 var cm = this.grid.colModel;
56737 cm.setColumnWidth(i, w, true);
56738 var cid = cm.getColumnId(i);
56739 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56740 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56741 this.updateSplitters();
56743 this.grid.fireEvent("columnresize", i, w);
56746 syncRowHeights : function(startIndex, endIndex){
56747 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56748 startIndex = startIndex || 0;
56749 var mrows = this.getBodyTable().rows;
56750 var lrows = this.getLockedTable().rows;
56751 var len = mrows.length-1;
56752 endIndex = Math.min(endIndex || len, len);
56753 for(var i = startIndex; i <= endIndex; i++){
56754 var m = mrows[i], l = lrows[i];
56755 var h = Math.max(m.offsetHeight, l.offsetHeight);
56756 m.style.height = l.style.height = h + "px";
56761 layout : function(initialRender, is2ndPass){
56763 var auto = g.autoHeight;
56764 var scrollOffset = 16;
56765 var c = g.getGridEl(), cm = this.cm,
56766 expandCol = g.autoExpandColumn,
56768 //c.beginMeasure();
56770 if(!c.dom.offsetWidth){ // display:none?
56772 this.lockedWrap.show();
56773 this.mainWrap.show();
56778 var hasLock = this.cm.isLocked(0);
56780 var tbh = this.headerPanel.getHeight();
56781 var bbh = this.footerPanel.getHeight();
56784 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56785 var newHeight = ch + c.getBorderWidth("tb");
56787 newHeight = Math.min(g.maxHeight, newHeight);
56789 c.setHeight(newHeight);
56793 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56796 var s = this.scroller;
56798 var csize = c.getSize(true);
56800 this.el.setSize(csize.width, csize.height);
56802 this.headerPanel.setWidth(csize.width);
56803 this.footerPanel.setWidth(csize.width);
56805 var hdHeight = this.mainHd.getHeight();
56806 var vw = csize.width;
56807 var vh = csize.height - (tbh + bbh);
56811 var bt = this.getBodyTable();
56813 if(cm.getLockedCount() == cm.config.length){
56814 bt = this.getLockedTable();
56817 var ltWidth = hasLock ?
56818 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56820 var scrollHeight = bt.offsetHeight;
56821 var scrollWidth = ltWidth + bt.offsetWidth;
56822 var vscroll = false, hscroll = false;
56824 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56826 var lw = this.lockedWrap, mw = this.mainWrap;
56827 var lb = this.lockedBody, mb = this.mainBody;
56829 setTimeout(function(){
56830 var t = s.dom.offsetTop;
56831 var w = s.dom.clientWidth,
56832 h = s.dom.clientHeight;
56835 lw.setSize(ltWidth, h);
56837 mw.setLeftTop(ltWidth, t);
56838 mw.setSize(w-ltWidth, h);
56840 lb.setHeight(h-hdHeight);
56841 mb.setHeight(h-hdHeight);
56843 if(is2ndPass !== true && !gv.userResized && expandCol){
56844 // high speed resize without full column calculation
56846 var ci = cm.getIndexById(expandCol);
56848 ci = cm.findColumnIndex(expandCol);
56850 ci = Math.max(0, ci); // make sure it's got at least the first col.
56851 var expandId = cm.getColumnId(ci);
56852 var tw = cm.getTotalWidth(false);
56853 var currentWidth = cm.getColumnWidth(ci);
56854 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56855 if(currentWidth != cw){
56856 cm.setColumnWidth(ci, cw, true);
56857 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56858 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56859 gv.updateSplitters();
56860 gv.layout(false, true);
56872 onWindowResize : function(){
56873 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56879 appendFooter : function(parentEl){
56883 sortAscText : "Sort Ascending",
56884 sortDescText : "Sort Descending",
56885 lockText : "Lock Column",
56886 unlockText : "Unlock Column",
56887 columnsText : "Columns",
56889 columnsWiderText : "Wider",
56890 columnsNarrowText : "Thinner"
56894 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56895 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56896 this.proxy.el.addClass('x-grid3-col-dd');
56899 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56900 handleMouseDown : function(e){
56904 callHandleMouseDown : function(e){
56905 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56910 * Ext JS Library 1.1.1
56911 * Copyright(c) 2006-2007, Ext JS, LLC.
56913 * Originally Released Under LGPL - original licence link has changed is not relivant.
56916 * <script type="text/javascript">
56920 // This is a support class used internally by the Grid components
56921 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56923 this.view = grid.getView();
56924 this.proxy = this.view.resizeProxy;
56925 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56926 "gridSplitters" + this.grid.getGridEl().id, {
56927 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56929 this.setHandleElId(Roo.id(hd));
56930 this.setOuterHandleElId(Roo.id(hd2));
56931 this.scroll = false;
56933 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56934 fly: Roo.Element.fly,
56936 b4StartDrag : function(x, y){
56937 this.view.headersDisabled = true;
56938 this.proxy.setHeight(this.view.mainWrap.getHeight());
56939 var w = this.cm.getColumnWidth(this.cellIndex);
56940 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56941 this.resetConstraints();
56942 this.setXConstraint(minw, 1000);
56943 this.setYConstraint(0, 0);
56944 this.minX = x - minw;
56945 this.maxX = x + 1000;
56947 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56951 handleMouseDown : function(e){
56952 ev = Roo.EventObject.setEvent(e);
56953 var t = this.fly(ev.getTarget());
56954 if(t.hasClass("x-grid-split")){
56955 this.cellIndex = this.view.getCellIndex(t.dom);
56956 this.split = t.dom;
56957 this.cm = this.grid.colModel;
56958 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56959 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56964 endDrag : function(e){
56965 this.view.headersDisabled = false;
56966 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56967 var diff = endX - this.startPos;
56968 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56971 autoOffset : function(){
56972 this.setDelta(0,0);
56976 * Ext JS Library 1.1.1
56977 * Copyright(c) 2006-2007, Ext JS, LLC.
56979 * Originally Released Under LGPL - original licence link has changed is not relivant.
56982 * <script type="text/javascript">
56986 // This is a support class used internally by the Grid components
56987 Roo.grid.GridDragZone = function(grid, config){
56988 this.view = grid.getView();
56989 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56990 if(this.view.lockedBody){
56991 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56992 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56994 this.scroll = false;
56996 this.ddel = document.createElement('div');
56997 this.ddel.className = 'x-grid-dd-wrap';
57000 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
57001 ddGroup : "GridDD",
57003 getDragData : function(e){
57004 var t = Roo.lib.Event.getTarget(e);
57005 var rowIndex = this.view.findRowIndex(t);
57006 var sm = this.grid.selModel;
57008 //Roo.log(rowIndex);
57010 if (sm.getSelectedCell) {
57011 // cell selection..
57012 if (!sm.getSelectedCell()) {
57015 if (rowIndex != sm.getSelectedCell()[0]) {
57021 if(rowIndex !== false){
57026 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
57028 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
57031 if (e.hasModifier()){
57032 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
57035 Roo.log("getDragData");
57040 rowIndex: rowIndex,
57041 selections:sm.getSelections ? sm.getSelections() : (
57042 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
57049 onInitDrag : function(e){
57050 var data = this.dragData;
57051 this.ddel.innerHTML = this.grid.getDragDropText();
57052 this.proxy.update(this.ddel);
57053 // fire start drag?
57056 afterRepair : function(){
57057 this.dragging = false;
57060 getRepairXY : function(e, data){
57064 onEndDrag : function(data, e){
57068 onValidDrop : function(dd, e, id){
57073 beforeInvalidDrop : function(e, id){
57078 * Ext JS Library 1.1.1
57079 * Copyright(c) 2006-2007, Ext JS, LLC.
57081 * Originally Released Under LGPL - original licence link has changed is not relivant.
57084 * <script type="text/javascript">
57089 * @class Roo.grid.ColumnModel
57090 * @extends Roo.util.Observable
57091 * This is the default implementation of a ColumnModel used by the Grid. It defines
57092 * the columns in the grid.
57095 var colModel = new Roo.grid.ColumnModel([
57096 {header: "Ticker", width: 60, sortable: true, locked: true},
57097 {header: "Company Name", width: 150, sortable: true},
57098 {header: "Market Cap.", width: 100, sortable: true},
57099 {header: "$ Sales", width: 100, sortable: true, renderer: money},
57100 {header: "Employees", width: 100, sortable: true, resizable: false}
57105 * The config options listed for this class are options which may appear in each
57106 * individual column definition.
57107 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
57109 * @param {Object} config An Array of column config objects. See this class's
57110 * config objects for details.
57112 Roo.grid.ColumnModel = function(config){
57114 * The config passed into the constructor
57116 this.config = config;
57119 // if no id, create one
57120 // if the column does not have a dataIndex mapping,
57121 // map it to the order it is in the config
57122 for(var i = 0, len = config.length; i < len; i++){
57124 if(typeof c.dataIndex == "undefined"){
57127 if(typeof c.renderer == "string"){
57128 c.renderer = Roo.util.Format[c.renderer];
57130 if(typeof c.id == "undefined"){
57133 if(c.editor && c.editor.xtype){
57134 c.editor = Roo.factory(c.editor, Roo.grid);
57136 if(c.editor && c.editor.isFormField){
57137 c.editor = new Roo.grid.GridEditor(c.editor);
57139 this.lookup[c.id] = c;
57143 * The width of columns which have no width specified (defaults to 100)
57146 this.defaultWidth = 100;
57149 * Default sortable of columns which have no sortable specified (defaults to false)
57152 this.defaultSortable = false;
57156 * @event widthchange
57157 * Fires when the width of a column changes.
57158 * @param {ColumnModel} this
57159 * @param {Number} columnIndex The column index
57160 * @param {Number} newWidth The new width
57162 "widthchange": true,
57164 * @event headerchange
57165 * Fires when the text of a header changes.
57166 * @param {ColumnModel} this
57167 * @param {Number} columnIndex The column index
57168 * @param {Number} newText The new header text
57170 "headerchange": true,
57172 * @event hiddenchange
57173 * Fires when a column is hidden or "unhidden".
57174 * @param {ColumnModel} this
57175 * @param {Number} columnIndex The column index
57176 * @param {Boolean} hidden true if hidden, false otherwise
57178 "hiddenchange": true,
57180 * @event columnmoved
57181 * Fires when a column is moved.
57182 * @param {ColumnModel} this
57183 * @param {Number} oldIndex
57184 * @param {Number} newIndex
57186 "columnmoved" : true,
57188 * @event columlockchange
57189 * Fires when a column's locked state is changed
57190 * @param {ColumnModel} this
57191 * @param {Number} colIndex
57192 * @param {Boolean} locked true if locked
57194 "columnlockchange" : true
57196 Roo.grid.ColumnModel.superclass.constructor.call(this);
57198 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57200 * @cfg {String} header The header text to display in the Grid view.
57203 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57204 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57205 * specified, the column's index is used as an index into the Record's data Array.
57208 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57209 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57212 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57213 * Defaults to the value of the {@link #defaultSortable} property.
57214 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57217 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57220 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57223 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57226 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57229 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57230 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57231 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57232 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57235 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57238 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57241 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
57244 * @cfg {String} cursor (Optional)
57247 * @cfg {String} tooltip (Optional)
57250 * @cfg {Number} xs (Optional)
57253 * @cfg {Number} sm (Optional)
57256 * @cfg {Number} md (Optional)
57259 * @cfg {Number} lg (Optional)
57262 * Returns the id of the column at the specified index.
57263 * @param {Number} index The column index
57264 * @return {String} the id
57266 getColumnId : function(index){
57267 return this.config[index].id;
57271 * Returns the column for a specified id.
57272 * @param {String} id The column id
57273 * @return {Object} the column
57275 getColumnById : function(id){
57276 return this.lookup[id];
57281 * Returns the column for a specified dataIndex.
57282 * @param {String} dataIndex The column dataIndex
57283 * @return {Object|Boolean} the column or false if not found
57285 getColumnByDataIndex: function(dataIndex){
57286 var index = this.findColumnIndex(dataIndex);
57287 return index > -1 ? this.config[index] : false;
57291 * Returns the index for a specified column id.
57292 * @param {String} id The column id
57293 * @return {Number} the index, or -1 if not found
57295 getIndexById : function(id){
57296 for(var i = 0, len = this.config.length; i < len; i++){
57297 if(this.config[i].id == id){
57305 * Returns the index for a specified column dataIndex.
57306 * @param {String} dataIndex The column dataIndex
57307 * @return {Number} the index, or -1 if not found
57310 findColumnIndex : function(dataIndex){
57311 for(var i = 0, len = this.config.length; i < len; i++){
57312 if(this.config[i].dataIndex == dataIndex){
57320 moveColumn : function(oldIndex, newIndex){
57321 var c = this.config[oldIndex];
57322 this.config.splice(oldIndex, 1);
57323 this.config.splice(newIndex, 0, c);
57324 this.dataMap = null;
57325 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57328 isLocked : function(colIndex){
57329 return this.config[colIndex].locked === true;
57332 setLocked : function(colIndex, value, suppressEvent){
57333 if(this.isLocked(colIndex) == value){
57336 this.config[colIndex].locked = value;
57337 if(!suppressEvent){
57338 this.fireEvent("columnlockchange", this, colIndex, value);
57342 getTotalLockedWidth : function(){
57343 var totalWidth = 0;
57344 for(var i = 0; i < this.config.length; i++){
57345 if(this.isLocked(i) && !this.isHidden(i)){
57346 this.totalWidth += this.getColumnWidth(i);
57352 getLockedCount : function(){
57353 for(var i = 0, len = this.config.length; i < len; i++){
57354 if(!this.isLocked(i)){
57359 return this.config.length;
57363 * Returns the number of columns.
57366 getColumnCount : function(visibleOnly){
57367 if(visibleOnly === true){
57369 for(var i = 0, len = this.config.length; i < len; i++){
57370 if(!this.isHidden(i)){
57376 return this.config.length;
57380 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57381 * @param {Function} fn
57382 * @param {Object} scope (optional)
57383 * @return {Array} result
57385 getColumnsBy : function(fn, scope){
57387 for(var i = 0, len = this.config.length; i < len; i++){
57388 var c = this.config[i];
57389 if(fn.call(scope||this, c, i) === true){
57397 * Returns true if the specified column is sortable.
57398 * @param {Number} col The column index
57399 * @return {Boolean}
57401 isSortable : function(col){
57402 if(typeof this.config[col].sortable == "undefined"){
57403 return this.defaultSortable;
57405 return this.config[col].sortable;
57409 * Returns the rendering (formatting) function defined for the column.
57410 * @param {Number} col The column index.
57411 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57413 getRenderer : function(col){
57414 if(!this.config[col].renderer){
57415 return Roo.grid.ColumnModel.defaultRenderer;
57417 return this.config[col].renderer;
57421 * Sets the rendering (formatting) function for a column.
57422 * @param {Number} col The column index
57423 * @param {Function} fn The function to use to process the cell's raw data
57424 * to return HTML markup for the grid view. The render function is called with
57425 * the following parameters:<ul>
57426 * <li>Data value.</li>
57427 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57428 * <li>css A CSS style string to apply to the table cell.</li>
57429 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57430 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57431 * <li>Row index</li>
57432 * <li>Column index</li>
57433 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57435 setRenderer : function(col, fn){
57436 this.config[col].renderer = fn;
57440 * Returns the width for the specified column.
57441 * @param {Number} col The column index
57444 getColumnWidth : function(col){
57445 return this.config[col].width * 1 || this.defaultWidth;
57449 * Sets the width for a column.
57450 * @param {Number} col The column index
57451 * @param {Number} width The new width
57453 setColumnWidth : function(col, width, suppressEvent){
57454 this.config[col].width = width;
57455 this.totalWidth = null;
57456 if(!suppressEvent){
57457 this.fireEvent("widthchange", this, col, width);
57462 * Returns the total width of all columns.
57463 * @param {Boolean} includeHidden True to include hidden column widths
57466 getTotalWidth : function(includeHidden){
57467 if(!this.totalWidth){
57468 this.totalWidth = 0;
57469 for(var i = 0, len = this.config.length; i < len; i++){
57470 if(includeHidden || !this.isHidden(i)){
57471 this.totalWidth += this.getColumnWidth(i);
57475 return this.totalWidth;
57479 * Returns the header for the specified column.
57480 * @param {Number} col The column index
57483 getColumnHeader : function(col){
57484 return this.config[col].header;
57488 * Sets the header for a column.
57489 * @param {Number} col The column index
57490 * @param {String} header The new header
57492 setColumnHeader : function(col, header){
57493 this.config[col].header = header;
57494 this.fireEvent("headerchange", this, col, header);
57498 * Returns the tooltip for the specified column.
57499 * @param {Number} col The column index
57502 getColumnTooltip : function(col){
57503 return this.config[col].tooltip;
57506 * Sets the tooltip for a column.
57507 * @param {Number} col The column index
57508 * @param {String} tooltip The new tooltip
57510 setColumnTooltip : function(col, tooltip){
57511 this.config[col].tooltip = tooltip;
57515 * Returns the dataIndex for the specified column.
57516 * @param {Number} col The column index
57519 getDataIndex : function(col){
57520 return this.config[col].dataIndex;
57524 * Sets the dataIndex for a column.
57525 * @param {Number} col The column index
57526 * @param {Number} dataIndex The new dataIndex
57528 setDataIndex : function(col, dataIndex){
57529 this.config[col].dataIndex = dataIndex;
57535 * Returns true if the cell is editable.
57536 * @param {Number} colIndex The column index
57537 * @param {Number} rowIndex The row index - this is nto actually used..?
57538 * @return {Boolean}
57540 isCellEditable : function(colIndex, rowIndex){
57541 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57545 * Returns the editor defined for the cell/column.
57546 * return false or null to disable editing.
57547 * @param {Number} colIndex The column index
57548 * @param {Number} rowIndex The row index
57551 getCellEditor : function(colIndex, rowIndex){
57552 return this.config[colIndex].editor;
57556 * Sets if a column is editable.
57557 * @param {Number} col The column index
57558 * @param {Boolean} editable True if the column is editable
57560 setEditable : function(col, editable){
57561 this.config[col].editable = editable;
57566 * Returns true if the column is hidden.
57567 * @param {Number} colIndex The column index
57568 * @return {Boolean}
57570 isHidden : function(colIndex){
57571 return this.config[colIndex].hidden;
57576 * Returns true if the column width cannot be changed
57578 isFixed : function(colIndex){
57579 return this.config[colIndex].fixed;
57583 * Returns true if the column can be resized
57584 * @return {Boolean}
57586 isResizable : function(colIndex){
57587 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57590 * Sets if a column is hidden.
57591 * @param {Number} colIndex The column index
57592 * @param {Boolean} hidden True if the column is hidden
57594 setHidden : function(colIndex, hidden){
57595 this.config[colIndex].hidden = hidden;
57596 this.totalWidth = null;
57597 this.fireEvent("hiddenchange", this, colIndex, hidden);
57601 * Sets the editor for a column.
57602 * @param {Number} col The column index
57603 * @param {Object} editor The editor object
57605 setEditor : function(col, editor){
57606 this.config[col].editor = editor;
57610 Roo.grid.ColumnModel.defaultRenderer = function(value)
57612 if(typeof value == "object") {
57615 if(typeof value == "string" && value.length < 1){
57619 return String.format("{0}", value);
57622 // Alias for backwards compatibility
57623 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57626 * Ext JS Library 1.1.1
57627 * Copyright(c) 2006-2007, Ext JS, LLC.
57629 * Originally Released Under LGPL - original licence link has changed is not relivant.
57632 * <script type="text/javascript">
57636 * @class Roo.grid.AbstractSelectionModel
57637 * @extends Roo.util.Observable
57638 * Abstract base class for grid SelectionModels. It provides the interface that should be
57639 * implemented by descendant classes. This class should not be directly instantiated.
57642 Roo.grid.AbstractSelectionModel = function(){
57643 this.locked = false;
57644 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57647 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57648 /** @ignore Called by the grid automatically. Do not call directly. */
57649 init : function(grid){
57655 * Locks the selections.
57658 this.locked = true;
57662 * Unlocks the selections.
57664 unlock : function(){
57665 this.locked = false;
57669 * Returns true if the selections are locked.
57670 * @return {Boolean}
57672 isLocked : function(){
57673 return this.locked;
57677 * Ext JS Library 1.1.1
57678 * Copyright(c) 2006-2007, Ext JS, LLC.
57680 * Originally Released Under LGPL - original licence link has changed is not relivant.
57683 * <script type="text/javascript">
57686 * @extends Roo.grid.AbstractSelectionModel
57687 * @class Roo.grid.RowSelectionModel
57688 * The default SelectionModel used by {@link Roo.grid.Grid}.
57689 * It supports multiple selections and keyboard selection/navigation.
57691 * @param {Object} config
57693 Roo.grid.RowSelectionModel = function(config){
57694 Roo.apply(this, config);
57695 this.selections = new Roo.util.MixedCollection(false, function(o){
57700 this.lastActive = false;
57704 * @event selectionchange
57705 * Fires when the selection changes
57706 * @param {SelectionModel} this
57708 "selectionchange" : true,
57710 * @event afterselectionchange
57711 * Fires after the selection changes (eg. by key press or clicking)
57712 * @param {SelectionModel} this
57714 "afterselectionchange" : true,
57716 * @event beforerowselect
57717 * Fires when a row is selected being selected, return false to cancel.
57718 * @param {SelectionModel} this
57719 * @param {Number} rowIndex The selected index
57720 * @param {Boolean} keepExisting False if other selections will be cleared
57722 "beforerowselect" : true,
57725 * Fires when a row is selected.
57726 * @param {SelectionModel} this
57727 * @param {Number} rowIndex The selected index
57728 * @param {Roo.data.Record} r The record
57730 "rowselect" : true,
57732 * @event rowdeselect
57733 * Fires when a row is deselected.
57734 * @param {SelectionModel} this
57735 * @param {Number} rowIndex The selected index
57737 "rowdeselect" : true
57739 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57740 this.locked = false;
57743 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57745 * @cfg {Boolean} singleSelect
57746 * True to allow selection of only one row at a time (defaults to false)
57748 singleSelect : false,
57751 initEvents : function(){
57753 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57754 this.grid.on("mousedown", this.handleMouseDown, this);
57755 }else{ // allow click to work like normal
57756 this.grid.on("rowclick", this.handleDragableRowClick, this);
57759 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57760 "up" : function(e){
57762 this.selectPrevious(e.shiftKey);
57763 }else if(this.last !== false && this.lastActive !== false){
57764 var last = this.last;
57765 this.selectRange(this.last, this.lastActive-1);
57766 this.grid.getView().focusRow(this.lastActive);
57767 if(last !== false){
57771 this.selectFirstRow();
57773 this.fireEvent("afterselectionchange", this);
57775 "down" : function(e){
57777 this.selectNext(e.shiftKey);
57778 }else if(this.last !== false && this.lastActive !== false){
57779 var last = this.last;
57780 this.selectRange(this.last, this.lastActive+1);
57781 this.grid.getView().focusRow(this.lastActive);
57782 if(last !== false){
57786 this.selectFirstRow();
57788 this.fireEvent("afterselectionchange", this);
57793 var view = this.grid.view;
57794 view.on("refresh", this.onRefresh, this);
57795 view.on("rowupdated", this.onRowUpdated, this);
57796 view.on("rowremoved", this.onRemove, this);
57800 onRefresh : function(){
57801 var ds = this.grid.dataSource, i, v = this.grid.view;
57802 var s = this.selections;
57803 s.each(function(r){
57804 if((i = ds.indexOfId(r.id)) != -1){
57806 s.add(ds.getAt(i)); // updating the selection relate data
57814 onRemove : function(v, index, r){
57815 this.selections.remove(r);
57819 onRowUpdated : function(v, index, r){
57820 if(this.isSelected(r)){
57821 v.onRowSelect(index);
57827 * @param {Array} records The records to select
57828 * @param {Boolean} keepExisting (optional) True to keep existing selections
57830 selectRecords : function(records, keepExisting){
57832 this.clearSelections();
57834 var ds = this.grid.dataSource;
57835 for(var i = 0, len = records.length; i < len; i++){
57836 this.selectRow(ds.indexOf(records[i]), true);
57841 * Gets the number of selected rows.
57844 getCount : function(){
57845 return this.selections.length;
57849 * Selects the first row in the grid.
57851 selectFirstRow : function(){
57856 * Select the last row.
57857 * @param {Boolean} keepExisting (optional) True to keep existing selections
57859 selectLastRow : function(keepExisting){
57860 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57864 * Selects the row immediately following the last selected row.
57865 * @param {Boolean} keepExisting (optional) True to keep existing selections
57867 selectNext : function(keepExisting){
57868 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57869 this.selectRow(this.last+1, keepExisting);
57870 this.grid.getView().focusRow(this.last);
57875 * Selects the row that precedes the last selected row.
57876 * @param {Boolean} keepExisting (optional) True to keep existing selections
57878 selectPrevious : function(keepExisting){
57880 this.selectRow(this.last-1, keepExisting);
57881 this.grid.getView().focusRow(this.last);
57886 * Returns the selected records
57887 * @return {Array} Array of selected records
57889 getSelections : function(){
57890 return [].concat(this.selections.items);
57894 * Returns the first selected record.
57897 getSelected : function(){
57898 return this.selections.itemAt(0);
57903 * Clears all selections.
57905 clearSelections : function(fast){
57910 var ds = this.grid.dataSource;
57911 var s = this.selections;
57912 s.each(function(r){
57913 this.deselectRow(ds.indexOfId(r.id));
57917 this.selections.clear();
57924 * Selects all rows.
57926 selectAll : function(){
57930 this.selections.clear();
57931 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57932 this.selectRow(i, true);
57937 * Returns True if there is a selection.
57938 * @return {Boolean}
57940 hasSelection : function(){
57941 return this.selections.length > 0;
57945 * Returns True if the specified row is selected.
57946 * @param {Number/Record} record The record or index of the record to check
57947 * @return {Boolean}
57949 isSelected : function(index){
57950 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57951 return (r && this.selections.key(r.id) ? true : false);
57955 * Returns True if the specified record id is selected.
57956 * @param {String} id The id of record to check
57957 * @return {Boolean}
57959 isIdSelected : function(id){
57960 return (this.selections.key(id) ? true : false);
57964 handleMouseDown : function(e, t){
57965 var view = this.grid.getView(), rowIndex;
57966 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57969 if(e.shiftKey && this.last !== false){
57970 var last = this.last;
57971 this.selectRange(last, rowIndex, e.ctrlKey);
57972 this.last = last; // reset the last
57973 view.focusRow(rowIndex);
57975 var isSelected = this.isSelected(rowIndex);
57976 if(e.button !== 0 && isSelected){
57977 view.focusRow(rowIndex);
57978 }else if(e.ctrlKey && isSelected){
57979 this.deselectRow(rowIndex);
57980 }else if(!isSelected){
57981 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57982 view.focusRow(rowIndex);
57985 this.fireEvent("afterselectionchange", this);
57988 handleDragableRowClick : function(grid, rowIndex, e)
57990 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57991 this.selectRow(rowIndex, false);
57992 grid.view.focusRow(rowIndex);
57993 this.fireEvent("afterselectionchange", this);
57998 * Selects multiple rows.
57999 * @param {Array} rows Array of the indexes of the row to select
58000 * @param {Boolean} keepExisting (optional) True to keep existing selections
58002 selectRows : function(rows, keepExisting){
58004 this.clearSelections();
58006 for(var i = 0, len = rows.length; i < len; i++){
58007 this.selectRow(rows[i], true);
58012 * Selects a range of rows. All rows in between startRow and endRow are also selected.
58013 * @param {Number} startRow The index of the first row in the range
58014 * @param {Number} endRow The index of the last row in the range
58015 * @param {Boolean} keepExisting (optional) True to retain existing selections
58017 selectRange : function(startRow, endRow, keepExisting){
58022 this.clearSelections();
58024 if(startRow <= endRow){
58025 for(var i = startRow; i <= endRow; i++){
58026 this.selectRow(i, true);
58029 for(var i = startRow; i >= endRow; i--){
58030 this.selectRow(i, true);
58036 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
58037 * @param {Number} startRow The index of the first row in the range
58038 * @param {Number} endRow The index of the last row in the range
58040 deselectRange : function(startRow, endRow, preventViewNotify){
58044 for(var i = startRow; i <= endRow; i++){
58045 this.deselectRow(i, preventViewNotify);
58051 * @param {Number} row The index of the row to select
58052 * @param {Boolean} keepExisting (optional) True to keep existing selections
58054 selectRow : function(index, keepExisting, preventViewNotify){
58055 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
58058 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
58059 if(!keepExisting || this.singleSelect){
58060 this.clearSelections();
58062 var r = this.grid.dataSource.getAt(index);
58063 this.selections.add(r);
58064 this.last = this.lastActive = index;
58065 if(!preventViewNotify){
58066 this.grid.getView().onRowSelect(index);
58068 this.fireEvent("rowselect", this, index, r);
58069 this.fireEvent("selectionchange", this);
58075 * @param {Number} row The index of the row to deselect
58077 deselectRow : function(index, preventViewNotify){
58081 if(this.last == index){
58084 if(this.lastActive == index){
58085 this.lastActive = false;
58087 var r = this.grid.dataSource.getAt(index);
58088 this.selections.remove(r);
58089 if(!preventViewNotify){
58090 this.grid.getView().onRowDeselect(index);
58092 this.fireEvent("rowdeselect", this, index);
58093 this.fireEvent("selectionchange", this);
58097 restoreLast : function(){
58099 this.last = this._last;
58104 acceptsNav : function(row, col, cm){
58105 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58109 onEditorKey : function(field, e){
58110 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
58115 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58117 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58119 }else if(k == e.ENTER && !e.ctrlKey){
58123 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
58125 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
58127 }else if(k == e.ESC){
58131 g.startEditing(newCell[0], newCell[1]);
58136 * Ext JS Library 1.1.1
58137 * Copyright(c) 2006-2007, Ext JS, LLC.
58139 * Originally Released Under LGPL - original licence link has changed is not relivant.
58142 * <script type="text/javascript">
58145 * @class Roo.grid.CellSelectionModel
58146 * @extends Roo.grid.AbstractSelectionModel
58147 * This class provides the basic implementation for cell selection in a grid.
58149 * @param {Object} config The object containing the configuration of this model.
58150 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58152 Roo.grid.CellSelectionModel = function(config){
58153 Roo.apply(this, config);
58155 this.selection = null;
58159 * @event beforerowselect
58160 * Fires before a cell is selected.
58161 * @param {SelectionModel} this
58162 * @param {Number} rowIndex The selected row index
58163 * @param {Number} colIndex The selected cell index
58165 "beforecellselect" : true,
58167 * @event cellselect
58168 * Fires when a cell is selected.
58169 * @param {SelectionModel} this
58170 * @param {Number} rowIndex The selected row index
58171 * @param {Number} colIndex The selected cell index
58173 "cellselect" : true,
58175 * @event selectionchange
58176 * Fires when the active selection changes.
58177 * @param {SelectionModel} this
58178 * @param {Object} selection null for no selection or an object (o) with two properties
58180 <li>o.record: the record object for the row the selection is in</li>
58181 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58184 "selectionchange" : true,
58187 * Fires when the tab (or enter) was pressed on the last editable cell
58188 * You can use this to trigger add new row.
58189 * @param {SelectionModel} this
58193 * @event beforeeditnext
58194 * Fires before the next editable sell is made active
58195 * You can use this to skip to another cell or fire the tabend
58196 * if you set cell to false
58197 * @param {Object} eventdata object : { cell : [ row, col ] }
58199 "beforeeditnext" : true
58201 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58204 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58206 enter_is_tab: false,
58209 initEvents : function(){
58210 this.grid.on("mousedown", this.handleMouseDown, this);
58211 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58212 var view = this.grid.view;
58213 view.on("refresh", this.onViewChange, this);
58214 view.on("rowupdated", this.onRowUpdated, this);
58215 view.on("beforerowremoved", this.clearSelections, this);
58216 view.on("beforerowsinserted", this.clearSelections, this);
58217 if(this.grid.isEditor){
58218 this.grid.on("beforeedit", this.beforeEdit, this);
58223 beforeEdit : function(e){
58224 this.select(e.row, e.column, false, true, e.record);
58228 onRowUpdated : function(v, index, r){
58229 if(this.selection && this.selection.record == r){
58230 v.onCellSelect(index, this.selection.cell[1]);
58235 onViewChange : function(){
58236 this.clearSelections(true);
58240 * Returns the currently selected cell,.
58241 * @return {Array} The selected cell (row, column) or null if none selected.
58243 getSelectedCell : function(){
58244 return this.selection ? this.selection.cell : null;
58248 * Clears all selections.
58249 * @param {Boolean} true to prevent the gridview from being notified about the change.
58251 clearSelections : function(preventNotify){
58252 var s = this.selection;
58254 if(preventNotify !== true){
58255 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58257 this.selection = null;
58258 this.fireEvent("selectionchange", this, null);
58263 * Returns true if there is a selection.
58264 * @return {Boolean}
58266 hasSelection : function(){
58267 return this.selection ? true : false;
58271 handleMouseDown : function(e, t){
58272 var v = this.grid.getView();
58273 if(this.isLocked()){
58276 var row = v.findRowIndex(t);
58277 var cell = v.findCellIndex(t);
58278 if(row !== false && cell !== false){
58279 this.select(row, cell);
58285 * @param {Number} rowIndex
58286 * @param {Number} collIndex
58288 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58289 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58290 this.clearSelections();
58291 r = r || this.grid.dataSource.getAt(rowIndex);
58294 cell : [rowIndex, colIndex]
58296 if(!preventViewNotify){
58297 var v = this.grid.getView();
58298 v.onCellSelect(rowIndex, colIndex);
58299 if(preventFocus !== true){
58300 v.focusCell(rowIndex, colIndex);
58303 this.fireEvent("cellselect", this, rowIndex, colIndex);
58304 this.fireEvent("selectionchange", this, this.selection);
58309 isSelectable : function(rowIndex, colIndex, cm){
58310 return !cm.isHidden(colIndex);
58314 handleKeyDown : function(e){
58315 //Roo.log('Cell Sel Model handleKeyDown');
58316 if(!e.isNavKeyPress()){
58319 var g = this.grid, s = this.selection;
58322 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58324 this.select(cell[0], cell[1]);
58329 var walk = function(row, col, step){
58330 return g.walkCells(row, col, step, sm.isSelectable, sm);
58332 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58339 // handled by onEditorKey
58340 if (g.isEditor && g.editing) {
58344 newCell = walk(r, c-1, -1);
58346 newCell = walk(r, c+1, 1);
58351 newCell = walk(r+1, c, 1);
58355 newCell = walk(r-1, c, -1);
58359 newCell = walk(r, c+1, 1);
58363 newCell = walk(r, c-1, -1);
58368 if(g.isEditor && !g.editing){
58369 g.startEditing(r, c);
58378 this.select(newCell[0], newCell[1]);
58384 acceptsNav : function(row, col, cm){
58385 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58389 * @param {Number} field (not used) - as it's normally used as a listener
58390 * @param {Number} e - event - fake it by using
58392 * var e = Roo.EventObjectImpl.prototype;
58393 * e.keyCode = e.TAB
58397 onEditorKey : function(field, e){
58399 var k = e.getKey(),
58402 ed = g.activeEditor,
58404 ///Roo.log('onEditorKey' + k);
58407 if (this.enter_is_tab && k == e.ENTER) {
58413 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58415 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58421 } else if(k == e.ENTER && !e.ctrlKey){
58424 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58426 } else if(k == e.ESC){
58431 var ecall = { cell : newCell, forward : forward };
58432 this.fireEvent('beforeeditnext', ecall );
58433 newCell = ecall.cell;
58434 forward = ecall.forward;
58438 //Roo.log('next cell after edit');
58439 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58440 } else if (forward) {
58441 // tabbed past last
58442 this.fireEvent.defer(100, this, ['tabend',this]);
58447 * Ext JS Library 1.1.1
58448 * Copyright(c) 2006-2007, Ext JS, LLC.
58450 * Originally Released Under LGPL - original licence link has changed is not relivant.
58453 * <script type="text/javascript">
58457 * @class Roo.grid.EditorGrid
58458 * @extends Roo.grid.Grid
58459 * Class for creating and editable grid.
58460 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58461 * The container MUST have some type of size defined for the grid to fill. The container will be
58462 * automatically set to position relative if it isn't already.
58463 * @param {Object} dataSource The data model to bind to
58464 * @param {Object} colModel The column model with info about this grid's columns
58466 Roo.grid.EditorGrid = function(container, config){
58467 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58468 this.getGridEl().addClass("xedit-grid");
58470 if(!this.selModel){
58471 this.selModel = new Roo.grid.CellSelectionModel();
58474 this.activeEditor = null;
58478 * @event beforeedit
58479 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58480 * <ul style="padding:5px;padding-left:16px;">
58481 * <li>grid - This grid</li>
58482 * <li>record - The record being edited</li>
58483 * <li>field - The field name being edited</li>
58484 * <li>value - The value for the field being edited.</li>
58485 * <li>row - The grid row index</li>
58486 * <li>column - The grid column index</li>
58487 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58489 * @param {Object} e An edit event (see above for description)
58491 "beforeedit" : true,
58494 * Fires after a cell is edited. <br />
58495 * <ul style="padding:5px;padding-left:16px;">
58496 * <li>grid - This grid</li>
58497 * <li>record - The record being edited</li>
58498 * <li>field - The field name being edited</li>
58499 * <li>value - The value being set</li>
58500 * <li>originalValue - The original value for the field, before the edit.</li>
58501 * <li>row - The grid row index</li>
58502 * <li>column - The grid column index</li>
58504 * @param {Object} e An edit event (see above for description)
58506 "afteredit" : true,
58508 * @event validateedit
58509 * Fires after a cell is edited, but before the value is set in the record.
58510 * You can use this to modify the value being set in the field, Return false
58511 * to cancel the change. The edit event object has the following properties <br />
58512 * <ul style="padding:5px;padding-left:16px;">
58513 * <li>editor - This editor</li>
58514 * <li>grid - This grid</li>
58515 * <li>record - The record being edited</li>
58516 * <li>field - The field name being edited</li>
58517 * <li>value - The value being set</li>
58518 * <li>originalValue - The original value for the field, before the edit.</li>
58519 * <li>row - The grid row index</li>
58520 * <li>column - The grid column index</li>
58521 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58523 * @param {Object} e An edit event (see above for description)
58525 "validateedit" : true
58527 this.on("bodyscroll", this.stopEditing, this);
58528 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58531 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58533 * @cfg {Number} clicksToEdit
58534 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58541 trackMouseOver: false, // causes very odd FF errors
58543 onCellDblClick : function(g, row, col){
58544 this.startEditing(row, col);
58547 onEditComplete : function(ed, value, startValue){
58548 this.editing = false;
58549 this.activeEditor = null;
58550 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58552 var field = this.colModel.getDataIndex(ed.col);
58557 originalValue: startValue,
58564 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58567 if(String(value) !== String(startValue)){
58569 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58570 r.set(field, e.value);
58571 // if we are dealing with a combo box..
58572 // then we also set the 'name' colum to be the displayField
58573 if (ed.field.displayField && ed.field.name) {
58574 r.set(ed.field.name, ed.field.el.dom.value);
58577 delete e.cancel; //?? why!!!
58578 this.fireEvent("afteredit", e);
58581 this.fireEvent("afteredit", e); // always fire it!
58583 this.view.focusCell(ed.row, ed.col);
58587 * Starts editing the specified for the specified row/column
58588 * @param {Number} rowIndex
58589 * @param {Number} colIndex
58591 startEditing : function(row, col){
58592 this.stopEditing();
58593 if(this.colModel.isCellEditable(col, row)){
58594 this.view.ensureVisible(row, col, true);
58596 var r = this.dataSource.getAt(row);
58597 var field = this.colModel.getDataIndex(col);
58598 var cell = Roo.get(this.view.getCell(row,col));
58603 value: r.data[field],
58608 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58609 this.editing = true;
58610 var ed = this.colModel.getCellEditor(col, row);
58616 ed.render(ed.parentEl || document.body);
58622 (function(){ // complex but required for focus issues in safari, ie and opera
58626 ed.on("complete", this.onEditComplete, this, {single: true});
58627 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58628 this.activeEditor = ed;
58629 var v = r.data[field];
58630 ed.startEdit(this.view.getCell(row, col), v);
58631 // combo's with 'displayField and name set
58632 if (ed.field.displayField && ed.field.name) {
58633 ed.field.el.dom.value = r.data[ed.field.name];
58637 }).defer(50, this);
58643 * Stops any active editing
58645 stopEditing : function(){
58646 if(this.activeEditor){
58647 this.activeEditor.completeEdit();
58649 this.activeEditor = null;
58653 * Called to get grid's drag proxy text, by default returns this.ddText.
58656 getDragDropText : function(){
58657 var count = this.selModel.getSelectedCell() ? 1 : 0;
58658 return String.format(this.ddText, count, count == 1 ? '' : 's');
58663 * Ext JS Library 1.1.1
58664 * Copyright(c) 2006-2007, Ext JS, LLC.
58666 * Originally Released Under LGPL - original licence link has changed is not relivant.
58669 * <script type="text/javascript">
58672 // private - not really -- you end up using it !
58673 // This is a support class used internally by the Grid components
58676 * @class Roo.grid.GridEditor
58677 * @extends Roo.Editor
58678 * Class for creating and editable grid elements.
58679 * @param {Object} config any settings (must include field)
58681 Roo.grid.GridEditor = function(field, config){
58682 if (!config && field.field) {
58684 field = Roo.factory(config.field, Roo.form);
58686 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58687 field.monitorTab = false;
58690 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58693 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58696 alignment: "tl-tl",
58699 cls: "x-small-editor x-grid-editor",
58704 * Ext JS Library 1.1.1
58705 * Copyright(c) 2006-2007, Ext JS, LLC.
58707 * Originally Released Under LGPL - original licence link has changed is not relivant.
58710 * <script type="text/javascript">
58715 Roo.grid.PropertyRecord = Roo.data.Record.create([
58716 {name:'name',type:'string'}, 'value'
58720 Roo.grid.PropertyStore = function(grid, source){
58722 this.store = new Roo.data.Store({
58723 recordType : Roo.grid.PropertyRecord
58725 this.store.on('update', this.onUpdate, this);
58727 this.setSource(source);
58729 Roo.grid.PropertyStore.superclass.constructor.call(this);
58734 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58735 setSource : function(o){
58737 this.store.removeAll();
58740 if(this.isEditableValue(o[k])){
58741 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58744 this.store.loadRecords({records: data}, {}, true);
58747 onUpdate : function(ds, record, type){
58748 if(type == Roo.data.Record.EDIT){
58749 var v = record.data['value'];
58750 var oldValue = record.modified['value'];
58751 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58752 this.source[record.id] = v;
58754 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58761 getProperty : function(row){
58762 return this.store.getAt(row);
58765 isEditableValue: function(val){
58766 if(val && val instanceof Date){
58768 }else if(typeof val == 'object' || typeof val == 'function'){
58774 setValue : function(prop, value){
58775 this.source[prop] = value;
58776 this.store.getById(prop).set('value', value);
58779 getSource : function(){
58780 return this.source;
58784 Roo.grid.PropertyColumnModel = function(grid, store){
58787 g.PropertyColumnModel.superclass.constructor.call(this, [
58788 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58789 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58791 this.store = store;
58792 this.bselect = Roo.DomHelper.append(document.body, {
58793 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58794 {tag: 'option', value: 'true', html: 'true'},
58795 {tag: 'option', value: 'false', html: 'false'}
58798 Roo.id(this.bselect);
58801 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58802 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58803 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58804 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58805 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58807 this.renderCellDelegate = this.renderCell.createDelegate(this);
58808 this.renderPropDelegate = this.renderProp.createDelegate(this);
58811 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58815 valueText : 'Value',
58817 dateFormat : 'm/j/Y',
58820 renderDate : function(dateVal){
58821 return dateVal.dateFormat(this.dateFormat);
58824 renderBool : function(bVal){
58825 return bVal ? 'true' : 'false';
58828 isCellEditable : function(colIndex, rowIndex){
58829 return colIndex == 1;
58832 getRenderer : function(col){
58834 this.renderCellDelegate : this.renderPropDelegate;
58837 renderProp : function(v){
58838 return this.getPropertyName(v);
58841 renderCell : function(val){
58843 if(val instanceof Date){
58844 rv = this.renderDate(val);
58845 }else if(typeof val == 'boolean'){
58846 rv = this.renderBool(val);
58848 return Roo.util.Format.htmlEncode(rv);
58851 getPropertyName : function(name){
58852 var pn = this.grid.propertyNames;
58853 return pn && pn[name] ? pn[name] : name;
58856 getCellEditor : function(colIndex, rowIndex){
58857 var p = this.store.getProperty(rowIndex);
58858 var n = p.data['name'], val = p.data['value'];
58860 if(typeof(this.grid.customEditors[n]) == 'string'){
58861 return this.editors[this.grid.customEditors[n]];
58863 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58864 return this.grid.customEditors[n];
58866 if(val instanceof Date){
58867 return this.editors['date'];
58868 }else if(typeof val == 'number'){
58869 return this.editors['number'];
58870 }else if(typeof val == 'boolean'){
58871 return this.editors['boolean'];
58873 return this.editors['string'];
58879 * @class Roo.grid.PropertyGrid
58880 * @extends Roo.grid.EditorGrid
58881 * This class represents the interface of a component based property grid control.
58882 * <br><br>Usage:<pre><code>
58883 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58891 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58892 * The container MUST have some type of size defined for the grid to fill. The container will be
58893 * automatically set to position relative if it isn't already.
58894 * @param {Object} config A config object that sets properties on this grid.
58896 Roo.grid.PropertyGrid = function(container, config){
58897 config = config || {};
58898 var store = new Roo.grid.PropertyStore(this);
58899 this.store = store;
58900 var cm = new Roo.grid.PropertyColumnModel(this, store);
58901 store.store.sort('name', 'ASC');
58902 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58905 enableColLock:false,
58906 enableColumnMove:false,
58908 trackMouseOver: false,
58911 this.getGridEl().addClass('x-props-grid');
58912 this.lastEditRow = null;
58913 this.on('columnresize', this.onColumnResize, this);
58916 * @event beforepropertychange
58917 * Fires before a property changes (return false to stop?)
58918 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58919 * @param {String} id Record Id
58920 * @param {String} newval New Value
58921 * @param {String} oldval Old Value
58923 "beforepropertychange": true,
58925 * @event propertychange
58926 * Fires after a property changes
58927 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58928 * @param {String} id Record Id
58929 * @param {String} newval New Value
58930 * @param {String} oldval Old Value
58932 "propertychange": true
58934 this.customEditors = this.customEditors || {};
58936 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58939 * @cfg {Object} customEditors map of colnames=> custom editors.
58940 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58941 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58942 * false disables editing of the field.
58946 * @cfg {Object} propertyNames map of property Names to their displayed value
58949 render : function(){
58950 Roo.grid.PropertyGrid.superclass.render.call(this);
58951 this.autoSize.defer(100, this);
58954 autoSize : function(){
58955 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58957 this.view.fitColumns();
58961 onColumnResize : function(){
58962 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58966 * Sets the data for the Grid
58967 * accepts a Key => Value object of all the elements avaiable.
58968 * @param {Object} data to appear in grid.
58970 setSource : function(source){
58971 this.store.setSource(source);
58975 * Gets all the data from the grid.
58976 * @return {Object} data data stored in grid
58978 getSource : function(){
58979 return this.store.getSource();
58988 * @class Roo.grid.Calendar
58989 * @extends Roo.util.Grid
58990 * This class extends the Grid to provide a calendar widget
58991 * <br><br>Usage:<pre><code>
58992 var grid = new Roo.grid.Calendar("my-container-id", {
58995 selModel: mySelectionModel,
58996 autoSizeColumns: true,
58997 monitorWindowResize: false,
58998 trackMouseOver: true
58999 eventstore : real data store..
59005 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59006 * The container MUST have some type of size defined for the grid to fill. The container will be
59007 * automatically set to position relative if it isn't already.
59008 * @param {Object} config A config object that sets properties on this grid.
59010 Roo.grid.Calendar = function(container, config){
59011 // initialize the container
59012 this.container = Roo.get(container);
59013 this.container.update("");
59014 this.container.setStyle("overflow", "hidden");
59015 this.container.addClass('x-grid-container');
59017 this.id = this.container.id;
59019 Roo.apply(this, config);
59020 // check and correct shorthanded configs
59024 for (var r = 0;r < 6;r++) {
59027 for (var c =0;c < 7;c++) {
59031 if (this.eventStore) {
59032 this.eventStore= Roo.factory(this.eventStore, Roo.data);
59033 this.eventStore.on('load',this.onLoad, this);
59034 this.eventStore.on('beforeload',this.clearEvents, this);
59038 this.dataSource = new Roo.data.Store({
59039 proxy: new Roo.data.MemoryProxy(rows),
59040 reader: new Roo.data.ArrayReader({}, [
59041 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
59044 this.dataSource.load();
59045 this.ds = this.dataSource;
59046 this.ds.xmodule = this.xmodule || false;
59049 var cellRender = function(v,x,r)
59051 return String.format(
59052 '<div class="fc-day fc-widget-content"><div>' +
59053 '<div class="fc-event-container"></div>' +
59054 '<div class="fc-day-number">{0}</div>'+
59056 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
59057 '</div></div>', v);
59062 this.colModel = new Roo.grid.ColumnModel( [
59064 xtype: 'ColumnModel',
59066 dataIndex : 'weekday0',
59068 renderer : cellRender
59071 xtype: 'ColumnModel',
59073 dataIndex : 'weekday1',
59075 renderer : cellRender
59078 xtype: 'ColumnModel',
59080 dataIndex : 'weekday2',
59081 header : 'Tuesday',
59082 renderer : cellRender
59085 xtype: 'ColumnModel',
59087 dataIndex : 'weekday3',
59088 header : 'Wednesday',
59089 renderer : cellRender
59092 xtype: 'ColumnModel',
59094 dataIndex : 'weekday4',
59095 header : 'Thursday',
59096 renderer : cellRender
59099 xtype: 'ColumnModel',
59101 dataIndex : 'weekday5',
59103 renderer : cellRender
59106 xtype: 'ColumnModel',
59108 dataIndex : 'weekday6',
59109 header : 'Saturday',
59110 renderer : cellRender
59113 this.cm = this.colModel;
59114 this.cm.xmodule = this.xmodule || false;
59118 //this.selModel = new Roo.grid.CellSelectionModel();
59119 //this.sm = this.selModel;
59120 //this.selModel.init(this);
59124 this.container.setWidth(this.width);
59128 this.container.setHeight(this.height);
59135 * The raw click event for the entire grid.
59136 * @param {Roo.EventObject} e
59141 * The raw dblclick event for the entire grid.
59142 * @param {Roo.EventObject} e
59146 * @event contextmenu
59147 * The raw contextmenu event for the entire grid.
59148 * @param {Roo.EventObject} e
59150 "contextmenu" : true,
59153 * The raw mousedown event for the entire grid.
59154 * @param {Roo.EventObject} e
59156 "mousedown" : true,
59159 * The raw mouseup event for the entire grid.
59160 * @param {Roo.EventObject} e
59165 * The raw mouseover event for the entire grid.
59166 * @param {Roo.EventObject} e
59168 "mouseover" : true,
59171 * The raw mouseout event for the entire grid.
59172 * @param {Roo.EventObject} e
59177 * The raw keypress event for the entire grid.
59178 * @param {Roo.EventObject} e
59183 * The raw keydown event for the entire grid.
59184 * @param {Roo.EventObject} e
59192 * Fires when a cell is clicked
59193 * @param {Grid} this
59194 * @param {Number} rowIndex
59195 * @param {Number} columnIndex
59196 * @param {Roo.EventObject} e
59198 "cellclick" : true,
59200 * @event celldblclick
59201 * Fires when a cell is double clicked
59202 * @param {Grid} this
59203 * @param {Number} rowIndex
59204 * @param {Number} columnIndex
59205 * @param {Roo.EventObject} e
59207 "celldblclick" : true,
59210 * Fires when a row is clicked
59211 * @param {Grid} this
59212 * @param {Number} rowIndex
59213 * @param {Roo.EventObject} e
59217 * @event rowdblclick
59218 * Fires when a row is double clicked
59219 * @param {Grid} this
59220 * @param {Number} rowIndex
59221 * @param {Roo.EventObject} e
59223 "rowdblclick" : true,
59225 * @event headerclick
59226 * Fires when a header is clicked
59227 * @param {Grid} this
59228 * @param {Number} columnIndex
59229 * @param {Roo.EventObject} e
59231 "headerclick" : true,
59233 * @event headerdblclick
59234 * Fires when a header cell is double clicked
59235 * @param {Grid} this
59236 * @param {Number} columnIndex
59237 * @param {Roo.EventObject} e
59239 "headerdblclick" : true,
59241 * @event rowcontextmenu
59242 * Fires when a row is right clicked
59243 * @param {Grid} this
59244 * @param {Number} rowIndex
59245 * @param {Roo.EventObject} e
59247 "rowcontextmenu" : true,
59249 * @event cellcontextmenu
59250 * Fires when a cell is right clicked
59251 * @param {Grid} this
59252 * @param {Number} rowIndex
59253 * @param {Number} cellIndex
59254 * @param {Roo.EventObject} e
59256 "cellcontextmenu" : true,
59258 * @event headercontextmenu
59259 * Fires when a header is right clicked
59260 * @param {Grid} this
59261 * @param {Number} columnIndex
59262 * @param {Roo.EventObject} e
59264 "headercontextmenu" : true,
59266 * @event bodyscroll
59267 * Fires when the body element is scrolled
59268 * @param {Number} scrollLeft
59269 * @param {Number} scrollTop
59271 "bodyscroll" : true,
59273 * @event columnresize
59274 * Fires when the user resizes a column
59275 * @param {Number} columnIndex
59276 * @param {Number} newSize
59278 "columnresize" : true,
59280 * @event columnmove
59281 * Fires when the user moves a column
59282 * @param {Number} oldIndex
59283 * @param {Number} newIndex
59285 "columnmove" : true,
59288 * Fires when row(s) start being dragged
59289 * @param {Grid} this
59290 * @param {Roo.GridDD} dd The drag drop object
59291 * @param {event} e The raw browser event
59293 "startdrag" : true,
59296 * Fires when a drag operation is complete
59297 * @param {Grid} this
59298 * @param {Roo.GridDD} dd The drag drop object
59299 * @param {event} e The raw browser event
59304 * Fires when dragged row(s) are dropped on a valid DD target
59305 * @param {Grid} this
59306 * @param {Roo.GridDD} dd The drag drop object
59307 * @param {String} targetId The target drag drop object
59308 * @param {event} e The raw browser event
59313 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59314 * @param {Grid} this
59315 * @param {Roo.GridDD} dd The drag drop object
59316 * @param {String} targetId The target drag drop object
59317 * @param {event} e The raw browser event
59322 * Fires when the dragged row(s) first cross another DD target while being dragged
59323 * @param {Grid} this
59324 * @param {Roo.GridDD} dd The drag drop object
59325 * @param {String} targetId The target drag drop object
59326 * @param {event} e The raw browser event
59328 "dragenter" : true,
59331 * Fires when the dragged row(s) leave another DD target while being dragged
59332 * @param {Grid} this
59333 * @param {Roo.GridDD} dd The drag drop object
59334 * @param {String} targetId The target drag drop object
59335 * @param {event} e The raw browser event
59340 * Fires when a row is rendered, so you can change add a style to it.
59341 * @param {GridView} gridview The grid view
59342 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59348 * Fires when the grid is rendered
59349 * @param {Grid} grid
59354 * Fires when a date is selected
59355 * @param {DatePicker} this
59356 * @param {Date} date The selected date
59360 * @event monthchange
59361 * Fires when the displayed month changes
59362 * @param {DatePicker} this
59363 * @param {Date} date The selected month
59365 'monthchange': true,
59367 * @event evententer
59368 * Fires when mouse over an event
59369 * @param {Calendar} this
59370 * @param {event} Event
59372 'evententer': true,
59374 * @event eventleave
59375 * Fires when the mouse leaves an
59376 * @param {Calendar} this
59379 'eventleave': true,
59381 * @event eventclick
59382 * Fires when the mouse click an
59383 * @param {Calendar} this
59386 'eventclick': true,
59388 * @event eventrender
59389 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59390 * @param {Calendar} this
59391 * @param {data} data to be modified
59393 'eventrender': true
59397 Roo.grid.Grid.superclass.constructor.call(this);
59398 this.on('render', function() {
59399 this.view.el.addClass('x-grid-cal');
59401 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59405 if (!Roo.grid.Calendar.style) {
59406 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59409 '.x-grid-cal .x-grid-col' : {
59410 height: 'auto !important',
59411 'vertical-align': 'top'
59413 '.x-grid-cal .fc-event-hori' : {
59424 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59426 * @cfg {Store} eventStore The store that loads events.
59431 activeDate : false,
59434 monitorWindowResize : false,
59437 resizeColumns : function() {
59438 var col = (this.view.el.getWidth() / 7) - 3;
59439 // loop through cols, and setWidth
59440 for(var i =0 ; i < 7 ; i++){
59441 this.cm.setColumnWidth(i, col);
59444 setDate :function(date) {
59446 Roo.log('setDate?');
59448 this.resizeColumns();
59449 var vd = this.activeDate;
59450 this.activeDate = date;
59451 // if(vd && this.el){
59452 // var t = date.getTime();
59453 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59454 // Roo.log('using add remove');
59456 // this.fireEvent('monthchange', this, date);
59458 // this.cells.removeClass("fc-state-highlight");
59459 // this.cells.each(function(c){
59460 // if(c.dateValue == t){
59461 // c.addClass("fc-state-highlight");
59462 // setTimeout(function(){
59463 // try{c.dom.firstChild.focus();}catch(e){}
59473 var days = date.getDaysInMonth();
59475 var firstOfMonth = date.getFirstDateOfMonth();
59476 var startingPos = firstOfMonth.getDay()-this.startDay;
59478 if(startingPos < this.startDay){
59482 var pm = date.add(Date.MONTH, -1);
59483 var prevStart = pm.getDaysInMonth()-startingPos;
59487 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59489 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59490 //this.cells.addClassOnOver('fc-state-hover');
59492 var cells = this.cells.elements;
59493 var textEls = this.textNodes;
59495 //Roo.each(cells, function(cell){
59496 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59499 days += startingPos;
59501 // convert everything to numbers so it's fast
59502 var day = 86400000;
59503 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59506 //Roo.log(prevStart);
59508 var today = new Date().clearTime().getTime();
59509 var sel = date.clearTime().getTime();
59510 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59511 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59512 var ddMatch = this.disabledDatesRE;
59513 var ddText = this.disabledDatesText;
59514 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59515 var ddaysText = this.disabledDaysText;
59516 var format = this.format;
59518 var setCellClass = function(cal, cell){
59520 //Roo.log('set Cell Class');
59522 var t = d.getTime();
59527 cell.dateValue = t;
59529 cell.className += " fc-today";
59530 cell.className += " fc-state-highlight";
59531 cell.title = cal.todayText;
59534 // disable highlight in other month..
59535 cell.className += " fc-state-highlight";
59540 //cell.className = " fc-state-disabled";
59541 cell.title = cal.minText;
59545 //cell.className = " fc-state-disabled";
59546 cell.title = cal.maxText;
59550 if(ddays.indexOf(d.getDay()) != -1){
59551 // cell.title = ddaysText;
59552 // cell.className = " fc-state-disabled";
59555 if(ddMatch && format){
59556 var fvalue = d.dateFormat(format);
59557 if(ddMatch.test(fvalue)){
59558 cell.title = ddText.replace("%0", fvalue);
59559 cell.className = " fc-state-disabled";
59563 if (!cell.initialClassName) {
59564 cell.initialClassName = cell.dom.className;
59567 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59572 for(; i < startingPos; i++) {
59573 cells[i].dayName = (++prevStart);
59574 Roo.log(textEls[i]);
59575 d.setDate(d.getDate()+1);
59577 //cells[i].className = "fc-past fc-other-month";
59578 setCellClass(this, cells[i]);
59583 for(; i < days; i++){
59584 intDay = i - startingPos + 1;
59585 cells[i].dayName = (intDay);
59586 d.setDate(d.getDate()+1);
59588 cells[i].className = ''; // "x-date-active";
59589 setCellClass(this, cells[i]);
59593 for(; i < 42; i++) {
59594 //textEls[i].innerHTML = (++extraDays);
59596 d.setDate(d.getDate()+1);
59597 cells[i].dayName = (++extraDays);
59598 cells[i].className = "fc-future fc-other-month";
59599 setCellClass(this, cells[i]);
59602 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59604 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59606 // this will cause all the cells to mis
59609 for (var r = 0;r < 6;r++) {
59610 for (var c =0;c < 7;c++) {
59611 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59615 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59616 for(i=0;i<cells.length;i++) {
59618 this.cells.elements[i].dayName = cells[i].dayName ;
59619 this.cells.elements[i].className = cells[i].className;
59620 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59621 this.cells.elements[i].title = cells[i].title ;
59622 this.cells.elements[i].dateValue = cells[i].dateValue ;
59628 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59629 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59631 ////if(totalRows != 6){
59632 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59633 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59636 this.fireEvent('monthchange', this, date);
59641 * Returns the grid's SelectionModel.
59642 * @return {SelectionModel}
59644 getSelectionModel : function(){
59645 if(!this.selModel){
59646 this.selModel = new Roo.grid.CellSelectionModel();
59648 return this.selModel;
59652 this.eventStore.load()
59658 findCell : function(dt) {
59659 dt = dt.clearTime().getTime();
59661 this.cells.each(function(c){
59662 //Roo.log("check " +c.dateValue + '?=' + dt);
59663 if(c.dateValue == dt){
59673 findCells : function(rec) {
59674 var s = rec.data.start_dt.clone().clearTime().getTime();
59676 var e= rec.data.end_dt.clone().clearTime().getTime();
59679 this.cells.each(function(c){
59680 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59682 if(c.dateValue > e){
59685 if(c.dateValue < s){
59694 findBestRow: function(cells)
59698 for (var i =0 ; i < cells.length;i++) {
59699 ret = Math.max(cells[i].rows || 0,ret);
59706 addItem : function(rec)
59708 // look for vertical location slot in
59709 var cells = this.findCells(rec);
59711 rec.row = this.findBestRow(cells);
59713 // work out the location.
59717 for(var i =0; i < cells.length; i++) {
59725 if (crow.start.getY() == cells[i].getY()) {
59727 crow.end = cells[i];
59743 for (var i = 0; i < cells.length;i++) {
59744 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59751 clearEvents: function() {
59753 if (!this.eventStore.getCount()) {
59756 // reset number of rows in cells.
59757 Roo.each(this.cells.elements, function(c){
59761 this.eventStore.each(function(e) {
59762 this.clearEvent(e);
59767 clearEvent : function(ev)
59770 Roo.each(ev.els, function(el) {
59771 el.un('mouseenter' ,this.onEventEnter, this);
59772 el.un('mouseleave' ,this.onEventLeave, this);
59780 renderEvent : function(ev,ctr) {
59782 ctr = this.view.el.select('.fc-event-container',true).first();
59786 this.clearEvent(ev);
59792 var cells = ev.cells;
59793 var rows = ev.rows;
59794 this.fireEvent('eventrender', this, ev);
59796 for(var i =0; i < rows.length; i++) {
59800 cls += ' fc-event-start';
59802 if ((i+1) == rows.length) {
59803 cls += ' fc-event-end';
59806 //Roo.log(ev.data);
59807 // how many rows should it span..
59808 var cg = this.eventTmpl.append(ctr,Roo.apply({
59811 }, ev.data) , true);
59814 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59815 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59816 cg.on('click', this.onEventClick, this, ev);
59820 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59821 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59824 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59825 cg.setWidth(ebox.right - sbox.x -2);
59829 renderEvents: function()
59831 // first make sure there is enough space..
59833 if (!this.eventTmpl) {
59834 this.eventTmpl = new Roo.Template(
59835 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59836 '<div class="fc-event-inner">' +
59837 '<span class="fc-event-time">{time}</span>' +
59838 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59840 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59848 this.cells.each(function(c) {
59849 //Roo.log(c.select('.fc-day-content div',true).first());
59850 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59853 var ctr = this.view.el.select('.fc-event-container',true).first();
59856 this.eventStore.each(function(ev){
59858 this.renderEvent(ev);
59862 this.view.layout();
59866 onEventEnter: function (e, el,event,d) {
59867 this.fireEvent('evententer', this, el, event);
59870 onEventLeave: function (e, el,event,d) {
59871 this.fireEvent('eventleave', this, el, event);
59874 onEventClick: function (e, el,event,d) {
59875 this.fireEvent('eventclick', this, el, event);
59878 onMonthChange: function () {
59882 onLoad: function () {
59884 //Roo.log('calendar onload');
59886 if(this.eventStore.getCount() > 0){
59890 this.eventStore.each(function(d){
59895 if (typeof(add.end_dt) == 'undefined') {
59896 Roo.log("Missing End time in calendar data: ");
59900 if (typeof(add.start_dt) == 'undefined') {
59901 Roo.log("Missing Start time in calendar data: ");
59905 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59906 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59907 add.id = add.id || d.id;
59908 add.title = add.title || '??';
59916 this.renderEvents();
59926 render : function ()
59930 if (!this.view.el.hasClass('course-timesheet')) {
59931 this.view.el.addClass('course-timesheet');
59933 if (this.tsStyle) {
59938 Roo.log(_this.grid.view.el.getWidth());
59941 this.tsStyle = Roo.util.CSS.createStyleSheet({
59942 '.course-timesheet .x-grid-row' : {
59945 '.x-grid-row td' : {
59946 'vertical-align' : 0
59948 '.course-edit-link' : {
59950 'text-overflow' : 'ellipsis',
59951 'overflow' : 'hidden',
59952 'white-space' : 'nowrap',
59953 'cursor' : 'pointer'
59958 '.de-act-sup-link' : {
59959 'color' : 'purple',
59960 'text-decoration' : 'line-through'
59964 'text-decoration' : 'line-through'
59966 '.course-timesheet .course-highlight' : {
59967 'border-top-style': 'dashed !important',
59968 'border-bottom-bottom': 'dashed !important'
59970 '.course-timesheet .course-item' : {
59971 'font-family' : 'tahoma, arial, helvetica',
59972 'font-size' : '11px',
59973 'overflow' : 'hidden',
59974 'padding-left' : '10px',
59975 'padding-right' : '10px',
59976 'padding-top' : '10px'
59984 monitorWindowResize : false,
59985 cellrenderer : function(v,x,r)
59990 xtype: 'CellSelectionModel',
59997 beforeload : function (_self, options)
59999 options.params = options.params || {};
60000 options.params._month = _this.monthField.getValue();
60001 options.params.limit = 9999;
60002 options.params['sort'] = 'when_dt';
60003 options.params['dir'] = 'ASC';
60004 this.proxy.loadResponse = this.loadResponse;
60006 //this.addColumns();
60008 load : function (_self, records, options)
60010 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
60011 // if you click on the translation.. you can edit it...
60012 var el = Roo.get(this);
60013 var id = el.dom.getAttribute('data-id');
60014 var d = el.dom.getAttribute('data-date');
60015 var t = el.dom.getAttribute('data-time');
60016 //var id = this.child('span').dom.textContent;
60019 Pman.Dialog.CourseCalendar.show({
60023 productitem_active : id ? 1 : 0
60025 _this.grid.ds.load({});
60030 _this.panel.fireEvent('resize', [ '', '' ]);
60033 loadResponse : function(o, success, response){
60034 // this is overridden on before load..
60036 Roo.log("our code?");
60037 //Roo.log(success);
60038 //Roo.log(response)
60039 delete this.activeRequest;
60041 this.fireEvent("loadexception", this, o, response);
60042 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60047 result = o.reader.read(response);
60049 Roo.log("load exception?");
60050 this.fireEvent("loadexception", this, o, response, e);
60051 o.request.callback.call(o.request.scope, null, o.request.arg, false);
60054 Roo.log("ready...");
60055 // loop through result.records;
60056 // and set this.tdate[date] = [] << array of records..
60058 Roo.each(result.records, function(r){
60060 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
60061 _this.tdata[r.data.when_dt.format('j')] = [];
60063 _this.tdata[r.data.when_dt.format('j')].push(r.data);
60066 //Roo.log(_this.tdata);
60068 result.records = [];
60069 result.totalRecords = 6;
60071 // let's generate some duumy records for the rows.
60072 //var st = _this.dateField.getValue();
60074 // work out monday..
60075 //st = st.add(Date.DAY, -1 * st.format('w'));
60077 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60079 var firstOfMonth = date.getFirstDayOfMonth();
60080 var days = date.getDaysInMonth();
60082 var firstAdded = false;
60083 for (var i = 0; i < result.totalRecords ; i++) {
60084 //var d= st.add(Date.DAY, i);
60087 for(var w = 0 ; w < 7 ; w++){
60088 if(!firstAdded && firstOfMonth != w){
60095 var dd = (d > 0 && d < 10) ? "0"+d : d;
60096 row['weekday'+w] = String.format(
60097 '<span style="font-size: 16px;"><b>{0}</b></span>'+
60098 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
60100 date.format('Y-m-')+dd
60103 if(typeof(_this.tdata[d]) != 'undefined'){
60104 Roo.each(_this.tdata[d], function(r){
60108 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
60109 if(r.parent_id*1>0){
60110 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
60113 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
60114 deactive = 'de-act-link';
60117 row['weekday'+w] += String.format(
60118 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
60120 r.product_id_name, //1
60121 r.when_dt.format('h:ia'), //2
60131 // only do this if something added..
60133 result.records.push(_this.grid.dataSource.reader.newRow(row));
60137 // push it twice. (second one with an hour..
60141 this.fireEvent("load", this, o, o.request.arg);
60142 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60144 sortInfo : {field: 'when_dt', direction : 'ASC' },
60146 xtype: 'HttpProxy',
60149 url : baseURL + '/Roo/Shop_course.php'
60152 xtype: 'JsonReader',
60169 'name': 'parent_id',
60173 'name': 'product_id',
60177 'name': 'productitem_id',
60195 click : function (_self, e)
60197 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60198 sd.setMonth(sd.getMonth()-1);
60199 _this.monthField.setValue(sd.format('Y-m-d'));
60200 _this.grid.ds.load({});
60206 xtype: 'Separator',
60210 xtype: 'MonthField',
60213 render : function (_self)
60215 _this.monthField = _self;
60216 // _this.monthField.set today
60218 select : function (combo, date)
60220 _this.grid.ds.load({});
60223 value : (function() { return new Date(); })()
60226 xtype: 'Separator',
60232 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60242 click : function (_self, e)
60244 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60245 sd.setMonth(sd.getMonth()+1);
60246 _this.monthField.setValue(sd.format('Y-m-d'));
60247 _this.grid.ds.load({});
60260 * Ext JS Library 1.1.1
60261 * Copyright(c) 2006-2007, Ext JS, LLC.
60263 * Originally Released Under LGPL - original licence link has changed is not relivant.
60266 * <script type="text/javascript">
60270 * @class Roo.LoadMask
60271 * A simple utility class for generically masking elements while loading data. If the element being masked has
60272 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60273 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60274 * element's UpdateManager load indicator and will be destroyed after the initial load.
60276 * Create a new LoadMask
60277 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60278 * @param {Object} config The config object
60280 Roo.LoadMask = function(el, config){
60281 this.el = Roo.get(el);
60282 Roo.apply(this, config);
60284 this.store.on('beforeload', this.onBeforeLoad, this);
60285 this.store.on('load', this.onLoad, this);
60286 this.store.on('loadexception', this.onLoadException, this);
60287 this.removeMask = false;
60289 var um = this.el.getUpdateManager();
60290 um.showLoadIndicator = false; // disable the default indicator
60291 um.on('beforeupdate', this.onBeforeLoad, this);
60292 um.on('update', this.onLoad, this);
60293 um.on('failure', this.onLoad, this);
60294 this.removeMask = true;
60298 Roo.LoadMask.prototype = {
60300 * @cfg {Boolean} removeMask
60301 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60302 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60305 * @cfg {String} msg
60306 * The text to display in a centered loading message box (defaults to 'Loading...')
60308 msg : 'Loading...',
60310 * @cfg {String} msgCls
60311 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60313 msgCls : 'x-mask-loading',
60316 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60322 * Disables the mask to prevent it from being displayed
60324 disable : function(){
60325 this.disabled = true;
60329 * Enables the mask so that it can be displayed
60331 enable : function(){
60332 this.disabled = false;
60335 onLoadException : function()
60337 Roo.log(arguments);
60339 if (typeof(arguments[3]) != 'undefined') {
60340 Roo.MessageBox.alert("Error loading",arguments[3]);
60344 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60345 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60352 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60355 onLoad : function()
60357 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60361 onBeforeLoad : function(){
60362 if(!this.disabled){
60363 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60368 destroy : function(){
60370 this.store.un('beforeload', this.onBeforeLoad, this);
60371 this.store.un('load', this.onLoad, this);
60372 this.store.un('loadexception', this.onLoadException, this);
60374 var um = this.el.getUpdateManager();
60375 um.un('beforeupdate', this.onBeforeLoad, this);
60376 um.un('update', this.onLoad, this);
60377 um.un('failure', this.onLoad, this);
60382 * Ext JS Library 1.1.1
60383 * Copyright(c) 2006-2007, Ext JS, LLC.
60385 * Originally Released Under LGPL - original licence link has changed is not relivant.
60388 * <script type="text/javascript">
60393 * @class Roo.XTemplate
60394 * @extends Roo.Template
60395 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60397 var t = new Roo.XTemplate(
60398 '<select name="{name}">',
60399 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60403 // then append, applying the master template values
60406 * Supported features:
60411 {a_variable} - output encoded.
60412 {a_variable.format:("Y-m-d")} - call a method on the variable
60413 {a_variable:raw} - unencoded output
60414 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60415 {a_variable:this.method_on_template(...)} - call a method on the template object.
60420 <tpl for="a_variable or condition.."></tpl>
60421 <tpl if="a_variable or condition"></tpl>
60422 <tpl exec="some javascript"></tpl>
60423 <tpl name="named_template"></tpl> (experimental)
60425 <tpl for="."></tpl> - just iterate the property..
60426 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60430 Roo.XTemplate = function()
60432 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60439 Roo.extend(Roo.XTemplate, Roo.Template, {
60442 * The various sub templates
60447 * basic tag replacing syntax
60450 * // you can fake an object call by doing this
60454 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60457 * compile the template
60459 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60462 compile: function()
60466 s = ['<tpl>', s, '</tpl>'].join('');
60468 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60469 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60470 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60471 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60472 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60477 while(true == !!(m = s.match(re))){
60478 var forMatch = m[0].match(nameRe),
60479 ifMatch = m[0].match(ifRe),
60480 execMatch = m[0].match(execRe),
60481 namedMatch = m[0].match(namedRe),
60486 name = forMatch && forMatch[1] ? forMatch[1] : '';
60489 // if - puts fn into test..
60490 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60492 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60497 // exec - calls a function... returns empty if true is returned.
60498 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60500 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60508 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60509 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60510 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60513 var uid = namedMatch ? namedMatch[1] : id;
60517 id: namedMatch ? namedMatch[1] : id,
60524 s = s.replace(m[0], '');
60526 s = s.replace(m[0], '{xtpl'+ id + '}');
60531 for(var i = tpls.length-1; i >= 0; --i){
60532 this.compileTpl(tpls[i]);
60533 this.tpls[tpls[i].id] = tpls[i];
60535 this.master = tpls[tpls.length-1];
60539 * same as applyTemplate, except it's done to one of the subTemplates
60540 * when using named templates, you can do:
60542 * var str = pl.applySubTemplate('your-name', values);
60545 * @param {Number} id of the template
60546 * @param {Object} values to apply to template
60547 * @param {Object} parent (normaly the instance of this object)
60549 applySubTemplate : function(id, values, parent)
60553 var t = this.tpls[id];
60557 if(t.test && !t.test.call(this, values, parent)){
60561 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60562 Roo.log(e.toString());
60568 if(t.exec && t.exec.call(this, values, parent)){
60572 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60573 Roo.log(e.toString());
60578 var vs = t.target ? t.target.call(this, values, parent) : values;
60579 parent = t.target ? values : parent;
60580 if(t.target && vs instanceof Array){
60582 for(var i = 0, len = vs.length; i < len; i++){
60583 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60585 return buf.join('');
60587 return t.compiled.call(this, vs, parent);
60589 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60590 Roo.log(e.toString());
60591 Roo.log(t.compiled);
60596 compileTpl : function(tpl)
60598 var fm = Roo.util.Format;
60599 var useF = this.disableFormats !== true;
60600 var sep = Roo.isGecko ? "+" : ",";
60601 var undef = function(str) {
60602 Roo.log("Property not found :" + str);
60606 var fn = function(m, name, format, args)
60608 //Roo.log(arguments);
60609 args = args ? args.replace(/\\'/g,"'") : args;
60610 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60611 if (typeof(format) == 'undefined') {
60612 format= 'htmlEncode';
60614 if (format == 'raw' ) {
60618 if(name.substr(0, 4) == 'xtpl'){
60619 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60622 // build an array of options to determine if value is undefined..
60624 // basically get 'xxxx.yyyy' then do
60625 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60626 // (function () { Roo.log("Property not found"); return ''; })() :
60631 Roo.each(name.split('.'), function(st) {
60632 lookfor += (lookfor.length ? '.': '') + st;
60633 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60636 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60639 if(format && useF){
60641 args = args ? ',' + args : "";
60643 if(format.substr(0, 5) != "this."){
60644 format = "fm." + format + '(';
60646 format = 'this.call("'+ format.substr(5) + '", ';
60650 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60654 // called with xxyx.yuu:(test,test)
60656 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60658 // raw.. - :raw modifier..
60659 return "'"+ sep + udef_st + name + ")"+sep+"'";
60663 // branched to use + in gecko and [].join() in others
60665 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60666 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60669 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60670 body.push(tpl.body.replace(/(\r\n|\n)/g,
60671 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60672 body.push("'].join('');};};");
60673 body = body.join('');
60676 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60678 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60684 applyTemplate : function(values){
60685 return this.master.compiled.call(this, values, {});
60686 //var s = this.subs;
60689 apply : function(){
60690 return this.applyTemplate.apply(this, arguments);
60695 Roo.XTemplate.from = function(el){
60696 el = Roo.getDom(el);
60697 return new Roo.XTemplate(el.value || el.innerHTML);